diff --git a/src/models/Document.zig b/src/models/Document.zig index 4deb110..c3a8157 100644 --- a/src/models/Document.zig +++ b/src/models/Document.zig @@ -4,7 +4,7 @@ const Size = basic_models.Size; const Document = @This(); pub const Object = @import("Object.zig"); -const shape = @import("shape.zig"); +const shape = @import("shape/shape.zig"); size: Size, allocator: std.mem.Allocator, diff --git a/src/models/shape/arc.zig b/src/models/shape/arc.zig index f9fe54f..ef5a793 100644 --- a/src/models/shape/arc.zig +++ b/src/models/shape/arc.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Object = @import("../Object.zig"); const PropertyData = @import("../Property.zig").Data; const Rect = @import("../basic_models.zig").Rect; +const shape_mod = @import("shape.zig"); /// Теги обязательных свойств (заглушка: arc пока не реализован). pub fn getRequiredTags() []const std.meta.Tag(PropertyData) { @@ -15,7 +16,8 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object) return error.ArcNotImplemented; } -/// Локальные границы дуги (заглушка: возвращает null). -pub fn getLocalBounds(_: *const Object) ?Rect { - return null; +/// Локальные границы дуги (заглушка: пока не реализовано). +pub fn getLocalBounds(obj: *const Object) !Rect { + try shape_mod.ensure(obj, .arc); + return error.ArcNotImplemented; } diff --git a/src/models/shape/broken.zig b/src/models/shape/broken.zig index 80ad026..7fce53d 100644 --- a/src/models/shape/broken.zig +++ b/src/models/shape/broken.zig @@ -4,6 +4,7 @@ const Property = @import("../Property.zig").Property; const PropertyData = @import("../Property.zig").Data; const Point2 = @import("../basic_models.zig").Point2; const Rect = @import("../basic_models.zig").Rect; +const shape_mod = @import("shape.zig"); /// Точки ломаной по умолчанию (для создания). pub const default_points = [_]Point2{ @@ -24,10 +25,11 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object) try obj.properties.append(allocator, .{ .data = .{ .points = points } }); } -/// Локальные границы ломаной: AABB по всем точкам. Возвращает null, если точек нет. -pub fn getLocalBounds(obj: *const Object) ?Rect { - const p = obj.getProperty(.points) orelse return null; - if (p.points.items.len == 0) return null; +/// Локальные границы ломаной: AABB по всем точкам. +pub fn getLocalBounds(obj: *const Object) !Rect { + try shape_mod.ensure(obj, .broken); + const p = obj.getProperty(.points).?; + if (p.points.items.len == 0) return error.EmptyPoints; var min_x: f32 = p.points.items[0].x; var max_x: f32 = min_x; var min_y: f32 = p.points.items[0].y; diff --git a/src/models/shape/ellipse.zig b/src/models/shape/ellipse.zig index b3da3ce..23293df 100644 --- a/src/models/shape/ellipse.zig +++ b/src/models/shape/ellipse.zig @@ -3,6 +3,7 @@ const Object = @import("../Object.zig"); const Property = @import("../Property.zig").Property; const PropertyData = @import("../Property.zig").Data; const Rect = @import("../basic_models.zig").Rect; +const shape_mod = @import("shape.zig"); /// Свойства фигуры по умолчанию (для создания и проверки типа). Теги для ensure выводятся отсюда. pub const default_shape_properties = [_]Property{ @@ -20,8 +21,9 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object) } /// Локальные границы эллипса: [-radii.x, -radii.y] .. [radii.x, radii.y]. -pub fn getLocalBounds(obj: *const Object) ?Rect { - const r = obj.getProperty(.radii) orelse return null; +pub fn getLocalBounds(obj: *const Object) !Rect { + try shape_mod.ensure(obj, .ellipse); + const r = obj.getProperty(.radii).?; return .{ .x = -r.radii.x, .y = -r.radii.y, diff --git a/src/models/shape/line.zig b/src/models/shape/line.zig index a01fe33..649aa4d 100644 --- a/src/models/shape/line.zig +++ b/src/models/shape/line.zig @@ -3,6 +3,7 @@ const Object = @import("../Object.zig"); const Property = @import("../Property.zig").Property; const PropertyData = @import("../Property.zig").Data; const Rect = @import("../basic_models.zig").Rect; +const shape_mod = @import("shape.zig"); /// Свойства фигуры по умолчанию (для создания и проверки типа). Теги для ensure выводятся отсюда. pub const default_shape_properties = [_]Property{ @@ -20,8 +21,9 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object) } /// Локальные границы линии: от (0,0) до end_point. -pub fn getLocalBounds(obj: *const Object) ?Rect { - const ep = obj.getProperty(.end_point) orelse return null; +pub fn getLocalBounds(obj: *const Object) !Rect { + 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); diff --git a/src/models/shape.zig b/src/models/shape/shape.zig similarity index 64% rename from src/models/shape.zig rename to src/models/shape/shape.zig index 2a14894..8762102 100644 --- a/src/models/shape.zig +++ b/src/models/shape/shape.zig @@ -1,13 +1,13 @@ const std = @import("std"); -const Object = @import("Object.zig"); -const Property = @import("Property.zig").Property; -const PropertyData = @import("Property.zig").Data; -const defaultCommonProperties = @import("Property.zig").defaultCommonProperties; -const basic_models = @import("basic_models.zig"); -const line = @import("shape/line.zig"); -const ellipse = @import("shape/ellipse.zig"); -const broken = @import("shape/broken.zig"); -const arc = @import("shape/arc.zig"); +const Object = @import("../Object.zig"); +const Property = @import("../Property.zig").Property; +const PropertyData = @import("../Property.zig").Data; +const defaultCommonProperties = @import("../Property.zig").defaultCommonProperties; +const basic_models = @import("../basic_models.zig"); +const line = @import("line.zig"); +const ellipse = @import("ellipse.zig"); +const broken = @import("broken.zig"); +const arc = @import("arc.zig"); pub const Rect = basic_models.Rect; @@ -54,8 +54,7 @@ fn requiredTagsFor(kind: Object.ShapeKind) []const std.meta.Tag(PropertyData) { } /// Локальные границы объекта (AABB в своих координатах). -pub fn getLocalBounds(obj: *const Object) ?Rect { - ensure(obj, obj.shape) catch return null; +pub fn getLocalBounds(obj: *const Object) !Rect { return switch (obj.shape) { .line => line.getLocalBounds(obj), .ellipse => ellipse.getLocalBounds(obj), @@ -72,28 +71,25 @@ test "getLocalBounds" { var line_obj = try shape.createObject(allocator, .line); defer line_obj.deinit(allocator); - const line_bounds = getLocalBounds(&line_obj); - try std.testing.expect(line_bounds != null); - 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 == 0); + 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 == 0); var ellipse_obj = try shape.createObject(allocator, .ellipse); defer ellipse_obj.deinit(allocator); - const ellipse_bounds = getLocalBounds(&ellipse_obj); - try std.testing.expect(ellipse_bounds != null); - 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); + 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 = getLocalBounds(&broken_obj); - try std.testing.expect(broken_bounds != null); - 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); + 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); } diff --git a/src/tests.zig b/src/tests.zig index 65a82bd..99ceb59 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -4,7 +4,7 @@ test "discover tests" { _ = @import("main.zig"); _ = @import("models/Property.zig"); - _ = @import("models/shape.zig"); + _ = @import("models/shape/shape.zig"); } // Убедиться, что выполнились все ожидаемые тесты: этот тест пройдёт только если до него дошли (т.е. все предыдущие прошли).