Я переместил модуль shape в подкаталог shape/ для лучшей организации кода. Изменил пути импорта в связанных файлах, чтобы соответствовать новому местоположению модуля. Удалил возвраты null из `getLocalBounds` и заменил их на обработку ошибок для улучшения надежности.
79 lines
2.8 KiB
Zig
79 lines
2.8 KiB
Zig
const std = @import("std");
|
|
const basic_models = @import("basic_models.zig");
|
|
const Size = basic_models.Size;
|
|
const Document = @This();
|
|
|
|
pub const Object = @import("Object.zig");
|
|
const shape = @import("shape/shape.zig");
|
|
|
|
size: Size,
|
|
allocator: std.mem.Allocator,
|
|
objects: std.ArrayList(Object),
|
|
|
|
pub fn init(allocator: std.mem.Allocator, size: Size) Document {
|
|
return .{
|
|
.size = size,
|
|
.allocator = allocator,
|
|
.objects = std.ArrayList(Object).empty,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Document) void {
|
|
for (self.objects.items) |*obj| obj.deinit(self.allocator);
|
|
self.objects.deinit(self.allocator);
|
|
}
|
|
|
|
pub fn addObject(self: *Document, template: Object) !void {
|
|
const obj = try template.clone(self.allocator);
|
|
try self.objects.append(self.allocator, obj);
|
|
}
|
|
|
|
pub fn addShape(self: *Document, parent: ?*Object, shape_kind: Object.ShapeKind) !void {
|
|
const obj = try shape.createObject(self.allocator, shape_kind);
|
|
if (parent) |p| {
|
|
try p.addChild(self.allocator, obj);
|
|
} else {
|
|
try self.addObject(obj);
|
|
}
|
|
}
|
|
|
|
fn randomShapeKind(rng: std.Random) Object.ShapeKind {
|
|
const shapes_implemented = [_]Object.ShapeKind{ .line, .ellipse, .broken };
|
|
return shapes_implemented[rng.intRangeLessThan(usize, 0, shapes_implemented.len)];
|
|
}
|
|
|
|
/// Создаёт случайное количество фигур в документе (в т.ч. вложенных).
|
|
/// Используются только реализованные типы: line, ellipse, broken.
|
|
/// Ограничение max_total предотвращает экспоненциальный рост и переполнение.
|
|
pub fn addRandomShapes(self: *Document, rng: std.Random) !void {
|
|
const max_total: usize = 80;
|
|
var total_count: usize = 0;
|
|
|
|
const n_root = rng.intRangeLessThan(usize, 1, 5);
|
|
for (0..n_root) |_| {
|
|
if (total_count >= max_total) break;
|
|
try self.addShape(null, randomShapeKind(rng));
|
|
total_count += 1;
|
|
}
|
|
|
|
var stack = std.ArrayList(*Object).empty;
|
|
defer stack.deinit(self.allocator);
|
|
for (self.objects.items) |*obj| {
|
|
try stack.append(self.allocator, obj);
|
|
}
|
|
while (stack.pop()) |obj| {
|
|
if (total_count >= max_total) continue;
|
|
const n_children = rng.intRangeLessThan(usize, 0, 2);
|
|
const base_len = obj.children.items.len;
|
|
for (0..n_children) |_| {
|
|
if (total_count >= max_total) break;
|
|
try self.addShape(obj, randomShapeKind(rng));
|
|
total_count += 1;
|
|
}
|
|
// Пушим в стек только после всех append, чтобы не держать указатели при реаллокации obj.children
|
|
for (obj.children.items[base_len..]) |*child| {
|
|
try stack.append(self.allocator, child);
|
|
}
|
|
}
|
|
}
|