feat: Добавил толщину линий, унифицировал геометрию
Переименовал основные геометрические модели (Point, Size, Rect, Scale, Radii), явно разделив их на типы с плавающей точкой (_f) и целочисленные (_i). Обновил использование этих типов во всем проекте для улучшения типобезопасности и ясности. Ввел новое свойство thickness для объектов и реализовал его применение при отрисовке линий и ломаных. Добавил Point2_i для целочисленных координат буфера в конвейере отрисовки.
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
const std = @import("std");
|
||||
const basic_models = @import("basic_models.zig");
|
||||
const Size = basic_models.Size;
|
||||
const Size_f = basic_models.Size_f;
|
||||
const Document = @This();
|
||||
|
||||
pub const Object = @import("Object.zig");
|
||||
const shape = @import("shape/shape.zig");
|
||||
|
||||
size: Size,
|
||||
size: Size_f,
|
||||
allocator: std.mem.Allocator,
|
||||
objects: std.ArrayList(Object),
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, size: Size) Document {
|
||||
pub fn init(allocator: std.mem.Allocator, size: Size_f) Document {
|
||||
return .{
|
||||
.size = size,
|
||||
.allocator = allocator,
|
||||
|
||||
@@ -18,6 +18,7 @@ const default_common_data = [_]PropertyData{
|
||||
.{ .opacity = 1.0 },
|
||||
.{ .locked = false },
|
||||
.{ .stroke_rgba = 0x000000FF },
|
||||
.{ .thickness = 2.0 },
|
||||
};
|
||||
|
||||
pub const defaultCommonProperties: [default_common_data.len]Property = blk: {
|
||||
@@ -47,7 +48,6 @@ pub fn setProperty(self: *Object, allocator: std.mem.Allocator, prop: Property)
|
||||
return;
|
||||
}
|
||||
}
|
||||
std.debug.print("Property not found: {s}\n", .{@tagName(prop.data)});
|
||||
return error.PropertyNotFound;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
const std = @import("std");
|
||||
const basic_models = @import("basic_models.zig");
|
||||
const Point2 = basic_models.Point2;
|
||||
const Scale2 = basic_models.Scale2;
|
||||
const Size = basic_models.Size;
|
||||
const Radii = basic_models.Radii;
|
||||
const Point2_f = basic_models.Point2_f;
|
||||
const Scale2_f = basic_models.Scale2_f;
|
||||
const Size_f = basic_models.Size_f;
|
||||
const Radii_f = basic_models.Radii_f;
|
||||
|
||||
pub const Data = union(enum) {
|
||||
position: Point2,
|
||||
position: Point2_f,
|
||||
angle: f32,
|
||||
scale: Scale2,
|
||||
scale: Scale2_f,
|
||||
visible: bool,
|
||||
opacity: f32,
|
||||
locked: bool,
|
||||
|
||||
size: Size,
|
||||
radii: Radii,
|
||||
end_point: Point2,
|
||||
size: Size_f,
|
||||
radii: Radii_f,
|
||||
end_point: Point2_f,
|
||||
|
||||
points: std.ArrayList(Point2),
|
||||
points: std.ArrayList(Point2_f),
|
||||
|
||||
fill_rgba: u32,
|
||||
stroke_rgba: u32,
|
||||
|
||||
@@ -1,37 +1,43 @@
|
||||
pub const ImageRect = struct {
|
||||
pub const Rect_i = struct {
|
||||
x: u32,
|
||||
y: u32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
};
|
||||
|
||||
pub const ImageSize = struct {
|
||||
pub const Size_i = struct {
|
||||
w: u32,
|
||||
h: u32,
|
||||
};
|
||||
|
||||
pub const Size = struct {
|
||||
width: f32,
|
||||
height: f32,
|
||||
pub const Size_f = struct {
|
||||
w: f32,
|
||||
h: f32,
|
||||
};
|
||||
|
||||
pub const Point2 = struct {
|
||||
pub const Point2_f = struct {
|
||||
x: f32 = 0,
|
||||
y: f32 = 0,
|
||||
};
|
||||
|
||||
pub const Radii = struct {
|
||||
/// Целочисленная точка (например, координаты в буфере пикселей).
|
||||
pub const Point2_i = struct {
|
||||
x: i32 = 0,
|
||||
y: i32 = 0,
|
||||
};
|
||||
|
||||
pub const Radii_f = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
};
|
||||
|
||||
pub const Scale2 = struct {
|
||||
pub const Scale2_f = struct {
|
||||
scale_x: f32 = 1,
|
||||
scale_y: f32 = 1,
|
||||
};
|
||||
|
||||
/// Прямоугольник в координатах документа (f32), например локальные границы объекта.
|
||||
pub const Rect = struct {
|
||||
pub const Rect_f = struct {
|
||||
x: f32 = 0,
|
||||
y: f32 = 0,
|
||||
w: f32 = 0,
|
||||
|
||||
@@ -3,10 +3,10 @@ const Document = @import("Document.zig");
|
||||
const Object = Document.Object;
|
||||
const shape = @import("shape/shape.zig");
|
||||
const basic_models = @import("basic_models.zig");
|
||||
const Size = basic_models.Size;
|
||||
const Point2 = basic_models.Point2;
|
||||
const Scale2 = basic_models.Scale2;
|
||||
const Radii = basic_models.Radii;
|
||||
const Size_f = basic_models.Size_f;
|
||||
const Point2_f = basic_models.Point2_f;
|
||||
const Scale2_f = basic_models.Scale2_f;
|
||||
const Radii_f = basic_models.Radii_f;
|
||||
|
||||
fn randFloat(rng: std.Random, min: f32, max: f32) f32 {
|
||||
return min + (max - min) * rng.float(f32);
|
||||
@@ -26,10 +26,10 @@ fn randomShapeKind(rng: std.Random) Object.ShapeKind {
|
||||
}
|
||||
|
||||
/// Случайно заполняет все доступные свойства объекта; позиция — в пределах документа.
|
||||
fn randomizeObjectProperties(allocator: std.mem.Allocator, doc_size: *const Size, obj: *Object, rng: std.Random) !void {
|
||||
fn randomizeObjectProperties(allocator: std.mem.Allocator, doc_size: *const Size_f, obj: *Object, rng: std.Random) !void {
|
||||
const margin: f32 = 8;
|
||||
const max_x = @max(0, doc_size.width - margin);
|
||||
const max_y = @max(0, doc_size.height - margin);
|
||||
const max_x = @max(0, doc_size.w - margin);
|
||||
const max_y = @max(0, doc_size.h - margin);
|
||||
|
||||
try obj.setProperty(allocator, .{ .data = .{
|
||||
.position = .{
|
||||
@@ -44,17 +44,19 @@ fn randomizeObjectProperties(allocator: std.mem.Allocator, doc_size: *const Size
|
||||
.scale_y = randFloat(rng, 0.25, 2.0),
|
||||
},
|
||||
} });
|
||||
try obj.setProperty(allocator, .{ .data = .{ .visible = rng.boolean() } });
|
||||
try obj.setProperty(allocator, .{ .data = .{ .visible = true } });
|
||||
try obj.setProperty(allocator, .{ .data = .{ .opacity = randFloat(rng, 0.3, 1.0) } });
|
||||
try obj.setProperty(allocator, .{ .data = .{ .locked = rng.boolean() } });
|
||||
|
||||
const stroke = randRgba(rng);
|
||||
try obj.setProperty(allocator, .{ .data = .{ .stroke_rgba = stroke } });
|
||||
obj.setProperty(allocator, .{ .data = .{ .fill_rgba = randRgba(rng) } }) catch {};
|
||||
const thickness = randFloat(rng, max_x * 0.01, max_x * 0.1);
|
||||
try obj.setProperty(allocator, .{ .data = .{ .thickness = thickness } });
|
||||
|
||||
switch (obj.shape) {
|
||||
.line => {
|
||||
const len = randFloat(rng, 20, @min(doc_size.width, doc_size.height) * 0.5);
|
||||
const len = randFloat(rng, 20, @min(doc_size.w, doc_size.h) * 0.5);
|
||||
const angle = randFloat(rng, 0, 2 * std.math.pi);
|
||||
try obj.setProperty(allocator, .{ .data = .{
|
||||
.end_point = .{
|
||||
@@ -64,7 +66,7 @@ fn randomizeObjectProperties(allocator: std.mem.Allocator, doc_size: *const Size
|
||||
} });
|
||||
},
|
||||
.ellipse => {
|
||||
const max_r = @min(120, @min(doc_size.width / 4, doc_size.height / 4));
|
||||
const max_r = @min(120, @min(doc_size.w / 4, doc_size.h / 4));
|
||||
try obj.setProperty(allocator, .{ .data = .{
|
||||
.radii = .{
|
||||
.x = randFloat(rng, 8, @max(8, max_r)),
|
||||
@@ -73,7 +75,7 @@ fn randomizeObjectProperties(allocator: std.mem.Allocator, doc_size: *const Size
|
||||
} });
|
||||
},
|
||||
.broken => {
|
||||
var points = std.ArrayList(Point2).empty;
|
||||
var points = std.ArrayList(Point2_f).empty;
|
||||
const n = rng.intRangeLessThan(usize, 2, 9);
|
||||
var x: f32 = 0;
|
||||
var y: f32 = 0;
|
||||
@@ -96,7 +98,7 @@ pub fn addRandomShapes(doc: *Document, rng: std.Random) !void {
|
||||
var total_count: usize = 0;
|
||||
const allocator = doc.allocator;
|
||||
|
||||
const n_root = rng.intRangeLessThan(usize, 1, 5);
|
||||
const n_root = rng.intRangeLessThan(usize, 6, 15);
|
||||
for (0..n_root) |_| {
|
||||
if (total_count >= max_total) break;
|
||||
var obj = try shape.createObject(allocator, randomShapeKind(rng));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Object = @import("../Object.zig");
|
||||
const PropertyData = @import("../Property.zig").Data;
|
||||
const Rect = @import("../basic_models.zig").Rect;
|
||||
const Rect_f = @import("../basic_models.zig").Rect_f;
|
||||
const shape_mod = @import("shape.zig");
|
||||
|
||||
/// Теги обязательных свойств (заглушка: arc пока не реализован).
|
||||
@@ -17,7 +17,7 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object)
|
||||
}
|
||||
|
||||
/// Локальные границы дуги (заглушка: пока не реализовано).
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect {
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect_f {
|
||||
try shape_mod.ensure(obj, .arc);
|
||||
return error.ArcNotImplemented;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ const std = @import("std");
|
||||
const Object = @import("../Object.zig");
|
||||
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 Point2_f = @import("../basic_models.zig").Point2_f;
|
||||
const Rect_f = @import("../basic_models.zig").Rect_f;
|
||||
const shape_mod = @import("shape.zig");
|
||||
|
||||
/// Точки ломаной по умолчанию (для создания).
|
||||
pub const default_points = [_]Point2{
|
||||
pub const default_points = [_]Point2_f{
|
||||
.{ .x = 0, .y = 0 },
|
||||
.{ .x = 80, .y = 0 },
|
||||
.{ .x = 80, .y = 60 },
|
||||
@@ -22,13 +22,13 @@ pub fn getRequiredTags() []const std.meta.Tag(PropertyData) {
|
||||
|
||||
/// Добавляет к объекту свойства по умолчанию для ломаной (points из default_points).
|
||||
pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object) !void {
|
||||
var points = std.ArrayList(Point2).empty;
|
||||
var points = std.ArrayList(Point2_f).empty;
|
||||
try points.appendSlice(allocator, &default_points);
|
||||
try obj.properties.append(allocator, .{ .data = .{ .points = points } });
|
||||
}
|
||||
|
||||
/// Локальные границы ломаной: AABB по всем точкам.
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect {
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect_f {
|
||||
try shape_mod.ensure(obj, .broken);
|
||||
const p = obj.getProperty(.points).?;
|
||||
if (p.points.items.len == 0) return error.EmptyPoints;
|
||||
|
||||
@@ -2,7 +2,7 @@ const std = @import("std");
|
||||
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 Rect_f = @import("../basic_models.zig").Rect_f;
|
||||
const shape_mod = @import("shape.zig");
|
||||
|
||||
/// Свойства фигуры по умолчанию (для создания и проверки типа). Теги для ensure выводятся отсюда.
|
||||
@@ -21,7 +21,7 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object)
|
||||
}
|
||||
|
||||
/// Локальные границы эллипса: [-radii.x, -radii.y] .. [radii.x, radii.y].
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect {
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect_f {
|
||||
try shape_mod.ensure(obj, .ellipse);
|
||||
const r = obj.getProperty(.radii).?;
|
||||
return .{
|
||||
|
||||
@@ -2,7 +2,7 @@ const std = @import("std");
|
||||
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 Rect_f = @import("../basic_models.zig").Rect_f;
|
||||
const shape_mod = @import("shape.zig");
|
||||
|
||||
/// Свойства фигуры по умолчанию (для создания и проверки типа). Теги для ensure выводятся отсюда.
|
||||
@@ -21,7 +21,7 @@ pub fn appendDefaultShapeProperties(allocator: std.mem.Allocator, obj: *Object)
|
||||
}
|
||||
|
||||
/// Локальные границы линии: от (0,0) до end_point.
|
||||
pub fn getLocalBounds(obj: *const Object) !Rect {
|
||||
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);
|
||||
|
||||
@@ -9,7 +9,7 @@ const ellipse = @import("ellipse.zig");
|
||||
const broken = @import("broken.zig");
|
||||
const arc = @import("arc.zig");
|
||||
|
||||
pub const Rect = basic_models.Rect;
|
||||
pub const Rect = basic_models.Rectf;
|
||||
|
||||
/// Создаёт объект с общими свойствами по умолчанию и специфичными для типа фигуры.
|
||||
pub fn createObject(allocator: std.mem.Allocator, shape_kind: Object.ShapeKind) !Object {
|
||||
|
||||
Reference in New Issue
Block a user