local player = require'cplayer' local clipper = require'clipper' local ffi = require'ffi' local cairo = require'cairo' local point_count = 20 local first_poly = true local second_poly = true local result_poly = true local even_odd = true local seed = 0 local offset = 5 local command = 'intersection' local join_type = 'round' local miter_limit = 5 function player:on_render(cr) if self:button{ id = 'generate', x = 10, y = 10, w = 160, h = 24, text = 'generate', theme = self.themes.red, } then seed = seed + 1 end command = self:mbutton{ id = 'command', x = 200, y = 10, w = 300, h = 24, values = {'intersection', 'union', 'difference', 'xor'}, selected = command, } even_odd = self:mbutton{ id = 'even_odd', x = 520, y = 10, w = 160, h = 24, values = {true, false}, texts = {[true] = 'even odd', [false] = 'winding'}, selected = even_odd, } first_poly = self:togglebutton{id = 'first_poly', x = 700, y = 10, w = 60, h = 24, text = 'first', selected = first_poly, cut = 'right'} second_poly = self:togglebutton{id = 'second_poly', x = 760, y = 10, w = 60, h = 24, text = 'second', selected = second_poly, cut = 'both'} result_poly = self:togglebutton{id = 'result_poly', x = 820, y = 10, w = 60, h = 24, text = 'result', selected = result_poly, cut = 'left'} point_count = self:slider{ id = 'point_count', x = 10, y = 40, w = 160, h = 24, i0 = 3, i1 = 20, i = point_count, text = 'points', } offset = self:slider{ id = 'offset', x = 10, y = 100, w = 160, h = 24, i0 = 0, i1 = 20, i = offset, text = 'offset', } join_type = self:mbutton{ id = 'join_type', x = 10, y = 130, w = 160, h = 24, values = {'round', 'square', 'miter'}, selected = join_type, } miter_limit = self:slider{ id = 'miter_limit', x = 10, y = 160, w = 160, h = 24, i0 = 0, i1 = 100, i = miter_limit, text = 'miter limit', } math.randomseed(seed) cr:fill_rule(even_odd and 'even_odd' or 'winding') cr:line_width(1) local scale = 1000000 local function draw_poly(i, p, fr,fg,fb,fa, sr,sg,sb,sa) if p:size() == 0 then return end cr:new_path() cr:move_to(p:get(1).x / scale, p:get(1).y / scale) for i=2,p:size() do cr:line_to(p:get(i).x / scale, p:get(i).y / scale) end cr:close_path() if fr then fr, fg, fb, fa = fr or 1, fg or 1, fb or 1, fa or 1 cr:rgba(fr, fg, fb, fa) cr:fill_preserve() end if sr then sr, sg, sb, sa = sr or 1, sg or 1, sb or 1, sa or 1 cr:rgba(sr, sg, sb, sa) cr:stroke() end end local function draw_polys(p, ...) for i=1,p:size() do draw_poly(i, p:get(i), ...) end end local function random_polys(n) local n1 = math.floor(n / 2) local n2 = math.ceil(n / 2) --you can preallocate elements... local p = clipper.polygon(n1) for i=1,n1 do p:get(i).x = math.random(100, 1000) * scale p:get(i).y = math.random(100, 600) * scale end --or you can add elements one by one... for i=1,n2 do p:add(math.random(100, 1000) * scale, math.random(100, 600) * scale) end p = p:clean() --test CleanPolygon() p = clipper.polygons(p) --test polygons constructor p = p:clean() --test CleanPolygons() p = p:simplify(even_odd and 'even_odd' or 'non_zero') return p end local p1 = random_polys(point_count) local p2 = random_polys(point_count) if first_poly then draw_polys(p1, 0.7, 0.7, 1, 0.2, 0.7, 0.7, 1, 0.5) end if second_poly then draw_polys(p2, 0.7, 1, 0.7, 0.2, 0.7, 1, 0.7, 0.5) end local cl = clipper.new() cl:add_subject(p1) cl:add_clip(p2) local p3 = cl:execute(command) if result_poly then draw_polys(p3, 0, 1, 0, 0.5, 0, 1, 0, 1) end if offset > 0 then draw_polys(p3:offset(offset * scale, join_type, miter_limit), 0, 1, 0, 0, 0, 1, 0, 1) draw_polys(p3:offset(-offset * scale, join_type, miter_limit), 0, 1, 0, 0, 0, 1, 0, 1) end end player:play()