local player = require'cplayer' local arc = require'path2d_arc' local svgarc = require'path2d_svgarc' local matrix = require'affine2d' local world_rotation = 0 local rotation = 0 local scale = 1 function player:on_render(cr) world_rotation = self:slider{id = 'world_rotation', x = 10, y = 10, w = 300, h = 24, text = 'world rotation', i0 = 0, i1 = 360, step = 1, i = world_rotation, } rotation = self:slider{id = 'rotation', x = 10, y = 40, w = 300, h = 24, text = 'arc rotation', i0 = 0, i1 = 360, step = 1, i = rotation, } scale = self:slider{id = 'scale', x = 10, y = 70, w = 300, h = 24, text = 'scale', i0 = 0.1, i1 = 5, step = 0.01, i = scale, } cr:identity_matrix() cr:translate(400, 500) cr:scale(scale, scale) cr:translate(-400, -500) local cpx, cpy local function write(_, x2, y2, x3, y3, x4, y4) cpx, cpy = cr:current_point() cr:circle(cpx, cpy, 2) cr:circle(x4, y4, 2) cr:move_to(cpx, cpy) cr:curve_to(x2, y2, x3, y3, x4, y4) end local world_center_x, world_center_y = 600, 300 local mt = matrix():rotate_around(world_center_x, world_center_y, math.rad(world_rotation)) local function draw(x1, y1, rx, ry, rotation, large, sweep, x2, y2, r, g, b, a) if not svgarc.valid(x1, y1, x2, y2, rx, ry) then return end cr:move_to(mt(x1, y1)) arc.to_bezier3(write, svgarc.to_arc(x1, y1, rx, ry, rotation, large, sweep, x2, y2, mt)) cr:rgba(r, g, b, a) cr:stroke() end cr:line_width(2) local mind, minx, miny, mint local function hit(x1, y1, rx, ry, rotation, large, sweep, x2, y2) if not svgarc.valid(x1, y1, x2, y2, rx, ry) then return end local x, y = cr:device_to_user(self.mousex, self.mousey) local d, x, y, t = arc.hit(x, y, svgarc.to_arc(x1, y1, rx, ry, rotation, large, sweep, x2, y2, mt)) if not mind or d < mind then mind, minx, miny, mint = d, x, y, t end local x11, y11, rx1, ry1, rotation1, large1, sweep1, x12, y12, x21, y21, rx2, ry2, rotation2, large2, sweep2, x22, y22 = svgarc.split(t, x1, y1, rx, ry, rotation, large, sweep, x2, y2) draw(x11, y11, rx1, ry1, rotation1, large1, sweep1, x12, y12, 1, 0, 0, 1) draw(x21, y21, rx2, ry2, rotation2, large2, sweep2, x22, y22, 0.3, 0.3, 1, 1) end --the four svg elliptic arcs from http://www.w3.org/TR/SVG/images/paths/arcs02.svg local function ellipses(tx, ty, large, sweep) local x1, y1, rx, ry, x2, y2 = tx+125, ty+75, 100, 50, tx+125+100, ty+75+50 local cx, cy, crx, cry = svgarc.to_arc(x1, y1, rx, ry, rotation, large, sweep, x2, y2, mt) local cmt = cr:matrix() cr:rotate_around(world_center_x, world_center_y, math.rad(world_rotation)) cr:translate(cx, cy) cr:rotate(math.rad(rotation)) cr:translate(-125, -125) cr:ellipse(125, 125, crx, cry) cr:matrix(cmt) cr:rgba(0,1,0,0.3) cr:stroke() hit(x1, y1, rx, ry, rotation, large, sweep, x2, y2) end ellipses(200, 100, 0, 0) ellipses(600, 100, 0, 1) ellipses(600, 400, 1, 0) ellipses(200, 400, 1, 1) --degenerate arcs hit(700, 100, 100, 0, 0, 0, 0, 800, 200) --zero radius hit(800, 100, 100, 100, 0, 0, 0, 800, 100) --conincident endpoints --closest hit point cr:line_width(1) cr:rgb(1,1,1) cr:circle(minx, miny, 5) cr:stroke() end player:play()