Files
Zivro/src/models/shape/shape.zig

96 lines
3.8 KiB
Zig
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const std = @import("std");
const Object = @import("../Object.zig");
const Property = @import("../Property.zig").Property;
const PropertyData = @import("../Property.zig").Data;
const defaultCommonProperties = Object.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.Rectf;
/// Создаёт объект с дефолтными общими и фигурными свойствами.
pub fn createObject(allocator: std.mem.Allocator, shape_kind: Object.ShapeKind) !Object {
var obj = try createWithCommonProperties(allocator, shape_kind);
errdefer obj.deinit(allocator);
switch (shape_kind) {
.line => try line.appendDefaultShapeProperties(allocator, &obj),
.ellipse => try ellipse.appendDefaultShapeProperties(allocator, &obj),
.broken => try broken.appendDefaultShapeProperties(allocator, &obj),
.arc => try arc.appendDefaultShapeProperties(allocator, &obj),
}
return obj;
}
fn createWithCommonProperties(allocator: std.mem.Allocator, shape_kind: Object.ShapeKind) !Object {
var properties_list = std.ArrayList(Property).empty;
errdefer properties_list.deinit(allocator);
for (defaultCommonProperties) |prop| try properties_list.append(allocator, prop);
return .{
.shape = shape_kind,
.properties = properties_list,
.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;
}
}
fn requiredTagsFor(kind: Object.ShapeKind) []const std.meta.Tag(PropertyData) {
return switch (kind) {
.line => line.getRequiredTags(),
.ellipse => ellipse.getRequiredTags(),
.broken => broken.getRequiredTags(),
.arc => arc.getRequiredTags(),
};
}
/// Локальные границы (AABB).
pub fn getLocalBounds(obj: *const Object) !Rect {
return switch (obj.shape) {
.line => line.getLocalBounds(obj),
.ellipse => ellipse.getLocalBounds(obj),
.broken => broken.getLocalBounds(obj),
.arc => arc.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 == 0);
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);
}