diff --git a/src/models/shape/broken.zig b/src/models/shape/broken.zig index 70d88ea..056013a 100644 --- a/src/models/shape/broken.zig +++ b/src/models/shape/broken.zig @@ -4,7 +4,6 @@ const Property = @import("../Property.zig").Property; const PropertyData = @import("../Property.zig").Data; const Point2_f = @import("../basic_models.zig").Point2_f; const Rect_f = @import("../basic_models.zig").Rect_f; -const common = @import("common.zig"); const shape_mod = @import("shape.zig"); /// Свойства фигуры по умолчанию (добавляются к общим). points — слайс на статический массив. @@ -19,29 +18,3 @@ pub const default_shape_properties = [_]Property{ .{ .data = .{ .filled = true } }, .{ .data = .{ .fill_rgba = 0x000000FF } }, }; - -/// Теги обязательных свойств = теги из default_shape_properties. -pub const required_tags = common.tagsFromProperties(&default_shape_properties); - -/// Локальные границы: AABB по точкам. -pub fn getLocalBounds(obj: *const Object) !Rect_f { - try shape_mod.ensure(obj, .broken); - const p = obj.getProperty(.points).?; - if (p.points.len == 0) return error.EmptyPoints; - var min_x: f32 = p.points[0].x; - var max_x: f32 = min_x; - var min_y: f32 = p.points[0].y; - var max_y: f32 = min_y; - for (p.points[1..]) |pt| { - min_x = @min(min_x, pt.x); - max_x = @max(max_x, pt.x); - min_y = @min(min_y, pt.y); - max_y = @max(max_y, pt.y); - } - return .{ - .x = min_x, - .y = min_y, - .w = max_x - min_x, - .h = max_y - min_y, - }; -} diff --git a/src/models/shape/common.zig b/src/models/shape/common.zig deleted file mode 100644 index 32b9181..0000000 --- a/src/models/shape/common.zig +++ /dev/null @@ -1,10 +0,0 @@ -const std = @import("std"); -const Property = @import("../Property.zig").Property; -const PropertyData = @import("../Property.zig").Data; - -/// Теги свойств — те же, что фигура добавляет к стандартным (из default_shape_properties). -pub fn tagsFromProperties(comptime props: []const Property) [props.len]std.meta.Tag(PropertyData) { - var result: [props.len]std.meta.Tag(PropertyData) = undefined; - for (props, &result) |p, *r| r.* = std.meta.activeTag(p.data); - return result; -} diff --git a/src/models/shape/ellipse.zig b/src/models/shape/ellipse.zig index 92e5479..a3806f7 100644 --- a/src/models/shape/ellipse.zig +++ b/src/models/shape/ellipse.zig @@ -2,7 +2,6 @@ const std = @import("std"); const Object = @import("../Object.zig"); const Property = @import("../Property.zig").Property; const Rect_f = @import("../basic_models.zig").Rect_f; -const common = @import("common.zig"); const shape_mod = @import("shape.zig"); /// Свойства фигуры по умолчанию (добавляются к общим). @@ -13,18 +12,3 @@ pub const default_shape_properties = [_]Property{ .{ .data = .{ .filled = false } }, .{ .data = .{ .fill_rgba = 0x000000FF } }, }; - -/// Теги обязательных свойств = теги из default_shape_properties. -pub const required_tags = common.tagsFromProperties(&default_shape_properties); - -/// Локальные границы эллипса: [-radii.x, -radii.y] .. [radii.x, radii.y]. -pub fn getLocalBounds(obj: *const Object) !Rect_f { - try shape_mod.ensure(obj, .ellipse); - const r = obj.getProperty(.radii).?; - return .{ - .x = -r.radii.x, - .y = -r.radii.y, - .w = 2 * r.radii.x, - .h = 2 * r.radii.y, - }; -} diff --git a/src/models/shape/line.zig b/src/models/shape/line.zig index fe9a289..b205a16 100644 --- a/src/models/shape/line.zig +++ b/src/models/shape/line.zig @@ -2,29 +2,9 @@ const std = @import("std"); const Object = @import("../Object.zig"); const Property = @import("../Property.zig").Property; const Rect_f = @import("../basic_models.zig").Rect_f; -const common = @import("common.zig"); const shape_mod = @import("shape.zig"); /// Свойства фигуры по умолчанию (добавляются к общим). pub const default_shape_properties = [_]Property{ .{ .data = .{ .end_point = .{ .x = 100, .y = 200 } } }, }; - -/// Теги обязательных свойств = теги из default_shape_properties. -pub const required_tags = common.tagsFromProperties(&default_shape_properties); - -/// Локальные границы: от (0,0) до end_point. -pub fn getLocalBounds(obj: *const Object) !Rect_f { - try shape_mod.ensure(obj, .line); - const ep = obj.getProperty(.end_point).?; - const min_x = @min(0, ep.end_point.x); - const max_x = @max(0, ep.end_point.x); - const min_y = @min(0, ep.end_point.y); - const max_y = @max(0, ep.end_point.y); - return .{ - .x = min_x, - .y = min_y, - .w = max_x - min_x, - .h = max_y - min_y, - }; -} diff --git a/src/models/shape/shape.zig b/src/models/shape/shape.zig index aff5905..9b5ae27 100644 --- a/src/models/shape/shape.zig +++ b/src/models/shape/shape.zig @@ -50,61 +50,3 @@ fn createWithCommonProperties(allocator: std.mem.Allocator, shape_kind: Object.S .children = std.ArrayList(Object).empty, }; } - -/// Проверяет тип объекта и наличие обязательных свойств. -pub fn ensure(obj: *const Object, expected_kind: Object.ShapeKind) !void { - if (obj.shape != expected_kind) return error.WrongShapeKind; - const tags = requiredTagsFor(expected_kind); - for (tags) |tag| { - if (obj.getProperty(tag) == null) return error.MissingRequiredProperty; - } -} - -/// Обязательные теги = те свойства, которые фигура добавляет к общим (из default_shape_properties). -fn requiredTagsFor(kind: Object.ShapeKind) []const std.meta.Tag(PropertyData) { - return switch (kind) { - .line => &line.required_tags, - .ellipse => &ellipse.required_tags, - .broken => &broken.required_tags, - }; -} - -/// Локальные границы (AABB). -pub fn getLocalBounds(obj: *const Object) !Rect { - return switch (obj.shape) { - .line => line.getLocalBounds(obj), - .ellipse => ellipse.getLocalBounds(obj), - .broken => broken.getLocalBounds(obj), - }; -} - -test "getLocalBounds" { - const shape = @This(); - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var line_obj = try shape.createObject(allocator, .line); - defer line_obj.deinit(allocator); - const line_bounds = try getLocalBounds(&line_obj); - try std.testing.expect(line_bounds.x == 0); - try std.testing.expect(line_bounds.y == 0); - try std.testing.expect(line_bounds.w == 100); - try std.testing.expect(line_bounds.h == 200); - - var ellipse_obj = try shape.createObject(allocator, .ellipse); - defer ellipse_obj.deinit(allocator); - const ellipse_bounds = try getLocalBounds(&ellipse_obj); - try std.testing.expect(ellipse_bounds.x == -50); - try std.testing.expect(ellipse_bounds.y == -50); - try std.testing.expect(ellipse_bounds.w == 100); - try std.testing.expect(ellipse_bounds.h == 100); - - var broken_obj = try shape.createObject(allocator, .broken); - defer broken_obj.deinit(allocator); - const broken_bounds = try getLocalBounds(&broken_obj); - try std.testing.expect(broken_bounds.x == 0); - try std.testing.expect(broken_bounds.y == 0); - try std.testing.expect(broken_bounds.w == 80); - try std.testing.expect(broken_bounds.h == 60); -}