feat: Добавил толщину линий, унифицировал геометрию

Переименовал основные геометрические модели (Point, Size, Rect, Scale, Radii), явно разделив их на типы с плавающей точкой (_f) и целочисленные (_i). Обновил использование этих типов во всем проекте для улучшения типобезопасности и ясности.

Ввел новое свойство thickness для объектов и реализовал его применение при отрисовке линий и ломаных. Добавил Point2_i для целочисленных координат буфера в конвейере отрисовки.
This commit is contained in:
2026-02-25 00:57:55 +03:00
parent 1d995995e7
commit 0114db1f48
19 changed files with 124 additions and 106 deletions

View File

@@ -1,4 +1,3 @@
const std = @import("std");
const Document = @import("../../models/Document.zig");
const pipeline = @import("pipeline.zig");
const DrawContext = pipeline.DrawContext;
@@ -6,6 +5,7 @@ const Color = @import("dvui").Color;
const Object = Document.Object;
const default_stroke: Color.PMA = .{ .r = 0, .g = 0, .b = 0, .a = 255 };
const default_thickness: f32 = 2.0;
/// Рисует линию в локальных координатах: от (0,0) до end_point. Растеризация в координатах буфера (без пробелов при зуме).
pub fn draw(ctx: *DrawContext, obj: *const Object) void {
@@ -13,25 +13,21 @@ pub fn draw(ctx: *DrawContext, obj: *const Object) void {
const end_x = ep_prop.end_point.x;
const end_y = ep_prop.end_point.y;
const stroke = if (obj.getProperty(.stroke_rgba)) |s| pipeline.rgbaToPma(s.stroke_rgba) else default_stroke;
drawLine(ctx, 0, 0, end_x, end_y, stroke);
const thickness = if (obj.getProperty(.thickness)) |t| t.thickness else default_thickness;
drawLine(ctx, 0, 0, end_x, end_y, stroke, thickness);
}
/// Линия по локальным координатам фигуры: переводит концы в буфер и рисует в пикселях буфера.
pub fn drawLine(ctx: *DrawContext, x0: f32, y0: f32, x1: f32, y1: f32, color: Color.PMA) void {
pub fn drawLine(ctx: *DrawContext, x0: f32, y0: f32, x1: f32, y1: f32, color: Color.PMA, thickness: f32) void {
const w0 = ctx.localToWorld(x0, y0);
const w1 = ctx.localToWorld(x1, y1);
const b0 = ctx.worldToBufferF(w0.x, w0.y);
const b1 = ctx.worldToBufferF(w1.x, w1.y);
const bx0: i32 = @intFromFloat(std.math.round(b0.x));
const by0: i32 = @intFromFloat(std.math.round(b0.y));
const bx1: i32 = @intFromFloat(std.math.round(b1.x));
const by1: i32 = @intFromFloat(std.math.round(b1.y));
drawLineInBuffer(ctx, bx0, by0, bx1, by1, color);
const b0 = ctx.worldToBuffer(w0.x, w0.y);
const b1 = ctx.worldToBuffer(w1.x, w1.y);
drawLineInBuffer(ctx, b0.x, b0.y, b1.x, b1.y, color, thickness);
}
/// Брезенхем в координатах буфера; пиксели вне [0, buf_width) x [0, buf_height) пропускаются.
pub fn drawLineInBuffer(ctx: *DrawContext, bx0: i32, by0: i32, bx1: i32, by1: i32, color: Color.PMA) void {
fn drawLineInBuffer(ctx: *DrawContext, bx0: i32, by0: i32, bx1: i32, by1: i32, color: Color.PMA, thickness: f32) void {
const bw: i32 = @intCast(ctx.buf_width);
const bh: i32 = @intCast(ctx.buf_height);
const dx: i32 = @intCast(@abs(bx1 - bx0));
@@ -42,6 +38,8 @@ pub fn drawLineInBuffer(ctx: *DrawContext, bx0: i32, by0: i32, bx1: i32, by1: i3
var x = bx0;
var y = by0;
_ = thickness;
while (true) {
if (x >= 0 and x < bw and y >= 0 and y < bh) {
ctx.blendPixelAtBuffer(@intCast(x), @intCast(y), color);