From d6d41388b30db13bbf8cb107501a231be8bb5205 Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Tue, 3 Mar 2026 19:46:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B5=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=BE=D0=B5=20=D1=83=D0=BF=D1=80=D0=BE=D1=89=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/render/cpu/ellipse.zig | 42 +++++++++++--------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/src/render/cpu/ellipse.zig b/src/render/cpu/ellipse.zig index b2bd0c5..bfdd7c1 100644 --- a/src/render/cpu/ellipse.zig +++ b/src/render/cpu/ellipse.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const std_math = std.math; const Document = @import("../../models/Document.zig"); const pipeline = @import("pipeline.zig"); const DrawContext = pipeline.DrawContext; @@ -10,8 +11,6 @@ const Object = Document.Object; const default_stroke: Color.PMA = .{ .r = 0, .g = 0, .b = 0, .a = 255 }; const default_thickness: f32 = 2.0; -const std_math = std.math; - /// Эллипс с центром (0,0) и полуосями radii. Обводка — полоса расстояния до контура (чёткая линия, не круги). /// arc_percent: 100 — полный эллипс, иначе одна дуга; обход в коде от (0,ry) по квадрантам (визуально может казаться от низа против часовой из‑за экранной Y). /// Отрисовка в отдельный буфер и один composite, чтобы при alpha<255 пиксели не накладывались несколько раз. @@ -23,10 +22,7 @@ pub fn draw(ctx: *DrawContext, obj: *const Object, allocator: std.mem.Allocator) const stroke = if (obj.getProperty(.stroke_rgba)) |s| pipeline.rgbaToPma(s.stroke_rgba) else default_stroke; const thickness = if (obj.getProperty(.thickness)) |t| t.thickness else default_thickness; - const arc_percent = blk: { - const p = obj.getProperty(.arc_percent); - break :blk std.math.clamp(if (p) |v| v.arc_percent else 100.0, 0.0, 100.0); - }; + const arc_percent = std_math.clamp(if (obj.getProperty(.arc_percent)) |p| p.arc_percent else 100.0, 0.0, 100.0); const t = &ctx.transform; const min_r = @min(rx, ry); @@ -43,19 +39,11 @@ pub fn draw(ctx: *DrawContext, obj: *const Object, allocator: std.mem.Allocator) .{ .x = rx * margin, .y = ry * margin }, .{ .x = -rx * margin, .y = ry * margin }, }; - var min_bx: f32 = undefined; - var min_by: f32 = undefined; - var max_bx: f32 = undefined; - var max_by: f32 = undefined; - { - const w0 = ctx.localToWorld(corners[0].x, corners[0].y); - const b0 = ctx.worldToBufferF(w0.x, w0.y); - min_bx = b0.x; - min_by = b0.y; - max_bx = b0.x; - max_by = b0.y; - } - for (corners[1..]) |c| { + var min_bx: f32 = std_math.inf(f32); + var min_by: f32 = std_math.inf(f32); + var max_bx: f32 = -std_math.inf(f32); + var max_by: f32 = -std_math.inf(f32); + for (corners) |c| { const w = ctx.localToWorld(c.x, c.y); const b = ctx.worldToBufferF(w.x, w.y); min_bx = @min(min_bx, b.x); @@ -80,10 +68,7 @@ pub fn draw(ctx: *DrawContext, obj: *const Object, allocator: std.mem.Allocator) const inv_rx = 1.0 / rx; const inv_ry = 1.0 / ry; - const arc_full = arc_percent >= 100.0; - const t_start = std_math.pi / 2.0; - const t_end_raw = t_start - 2.0 * std_math.pi * arc_percent / 100.0; - const t_end = if (t_end_raw <= -std_math.pi) t_end_raw + 2.0 * std_math.pi else t_end_raw; + const arc_len = 2.0 * std_math.pi * arc_percent / 100.0; var by: i32 = y0; while (by < y1) : (by += 1) { @@ -97,13 +82,10 @@ pub fn draw(ctx: *DrawContext, obj: *const Object, allocator: std.mem.Allocator) const ny = loc.y * inv_ry; const d = nx * nx + ny * ny; if (d < d_inner_sq or d > d_outer_sq) continue; - if (!arc_full) { - const t_pt = std_math.atan2(ny, nx); - const in_arc = if (t_end <= t_start) - (t_pt >= t_end and t_pt <= t_start) - else - (t_pt >= t_end or t_pt <= t_start); - if (!in_arc) continue; + if (arc_percent < 100.0) { + var diff = std_math.pi / 2.0 - std_math.atan2(ny, nx); + if (diff < 0) diff += 2.0 * std_math.pi; + if (diff > arc_len) continue; } stroke_ctx.blendPixelAtBuffer(bx, by, stroke); }