Specify direction of an arc in a curve containing many segments

Andrew Martchenko <[email protected]> Thu, 24 Nov 2016 16:54:58 +1100
Newsgroups gmane.comp.graphics.ipe.general
Message-ID <[email protected]>
Hi all,

I have written an ipelet (attached) called "fillet", which will create 
circular fillets on a polyline or polygon. The problem I am having is 
that I am unable to specify which side of an arc to draw when 
constructing the filleted curve. On line 108, swapping x1 and x2 around 
in the function
     ipe.Arc(ipe.Matrix(r, 0, 0, r, c.x, c.y), x1, x2)
does not make a difference to the arc that gets drawn.

I have attached a test.ipe file to illustrate the problem. Here's how to 
run the ipelet
1) select the shape
2) type Ctrl-F
3) enter 12 for the radius of the fillet and select OK

Notice that the inner fillets are correctly applied while the outer 
fillets are incorrect. So how can I specify the direction in which the 
arc is drawn.

Also, how would I go about deleting the old polygon/polyline?

Cheers,
Andrew M.

_______________________________________________
Ipe-discuss mailing list
Ipe-discuss-rGrgPyRx506NN8uzcEdRPYRWq/[email protected]
http://lists.science.uu.nl/mailman/listinfo/ipe-discuss
fillet.lua (text/x-lua, 2.9 KB)

label = "Fillet"

about = [[
Create fillets in a polyline or polygon
]]




function get_polysegments(obj)

   if obj:type() ~= "path" then return end

   local shape = obj:shape()
   if (#shape ~= 1 or shape[1].type ~= "curve" or #shape[1] < 2) then return end
   local m = obj:matrix()
   local v
   local seg = {}

   
   -- get all the line segments
   for i=1,#shape[1] do
      v = shape[1][i]
      if v.type ~= "segment" then return end
      seg[#seg+1] = ipe.Segment(m*v[1],m*v[2])
   end

   local closed = shape[1].closed

   if closed then
      local a,b = seg[#seg]:endpoints()
      local c,d = seg[1]:endpoints()
      seg[#seg+1] = ipe.Segment(b,c)
      seg[#seg+1] = seg[1]
   end
   
   return seg, closed
end



function run(model)

   local p = model:page()
   local prim = p:primarySelection()
   if not prim then model.ui:explain("no selection") return end
   local obj = p[prim]


   local seg, closed = get_polysegments(obj)

   if seg==nil then
      model:warning("Primary selection is not a polyline or polygon")
   end


   local str = model:getString("Enter fillet radius in pts")
   if not str or str:match("^%s*$") then return end
   local r = tonumber(str)

   local s11,s12,s21,s22
   local n1,n2,p11,p12,p21,p22
   local c
   local x1, x2
   local shape={type="curve", closed=closed}

   for i=1,#seg-1 do
      -- normals of line segments with length equal to r
      n1 = r*seg[i]:line():normal()
      n2 = r*seg[i+1]:line():normal()

      -- endpoints of line segments
      p11,p12 = seg[i]:endpoints()
      p21,p22 = seg[i+1]:endpoints()

      -- line segments translated by +/- the respective normals
      s11 = ipe.Segment(p11+n1,p12+n1)
      s12 = ipe.Segment(p11-n1,p12-n1)
      s21 = ipe.Segment(p21+n2,p22+n2)
      s22 = ipe.Segment(p21-n2,p22-n2)


      -- find center of the joing arc which is equal to the intersection
      -- of two of the translated line segments
      if s11:intersects(s21) then
	 c = s11:intersects(s21)
      elseif s11:intersects(s22) then
	 c = s11:intersects(s22)
      elseif s12:intersects(s21) then
	 c = s12:intersects(s21)
      elseif s12:intersects(s22) then
	 c = s12:intersects(s22)
      end

      -- start and end point of the arc
      x1 = seg[i]:project(c)
      x2 = seg[i+1]:project(c)


      -- append segments and arcs to form filleted shape
      if i>1 then
	 shape[#shape+1] = {type="segment", shape[#shape][2],x1}       
      elseif i==1 and closed==false then
	 shape[#shape+1] = {type="segment", p11,x1}
      end
      shape[#shape+1] = {type="arc", x1,x2,arc=ipe.Arc(ipe.Matrix(r, 0, 0, r, c.x, c.y),x1,x2)}
      if i==#seg-1 and closed==false then
	 shape[#shape+1] = {type="segment", x2,p22}
      end

   end

   
   local path = ipe.Path(model.attributes, { shape } )
   model:creation("create excircles of triangles", path)



end


----------------------------------------------------------------------
shortcuts.ipelet_1_fillet = "Shift+f"
test.ipe (text/xml, 6.3 KB)
<?xml version="1.0"?>
<!DOCTYPE ipe SYSTEM "ipe.dtd">
<ipe version="70107" creator="Ipe 7.2.5">
<info created="D:20160627205049" modified="D:20161124162812"/>
<ipestyle name="basic">
<symbol name="arrow/arc(spx)">
<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
0 0 m
-1 0.333 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/farc(spx)">
<path stroke="sym-stroke" fill="white" pen="sym-pen">
0 0 m
-1 0.333 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/ptarc(spx)">
<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
0 0 m
-1 0.333 l
-0.8 0 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/fptarc(spx)">
<path stroke="sym-stroke" fill="white" pen="sym-pen">
0 0 m
-1 0.333 l
-0.8 0 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="mark/circle(sx)" transformations="translations">
<path fill="sym-stroke">
0.6 0 0 0.6 0 0 e
0.4 0 0 0.4 0 0 e
</path>
</symbol>
<symbol name="mark/disk(sx)" transformations="translations">
<path fill="sym-stroke">
0.6 0 0 0.6 0 0 e
</path>
</symbol>
<symbol name="mark/fdisk(sfx)" transformations="translations">
<group>
<path fill="sym-fill">
0.5 0 0 0.5 0 0 e
</path>
<path fill="sym-stroke" fillrule="eofill">
0.6 0 0 0.6 0 0 e
0.4 0 0 0.4 0 0 e
</path>
</group>
</symbol>
<symbol name="mark/box(sx)" transformations="translations">
<path fill="sym-stroke" fillrule="eofill">
-0.6 -0.6 m
0.6 -0.6 l
0.6 0.6 l
-0.6 0.6 l
h
-0.4 -0.4 m
0.4 -0.4 l
0.4 0.4 l
-0.4 0.4 l
h
</path>
</symbol>
<symbol name="mark/square(sx)" transformations="translations">
<path fill="sym-stroke">
-0.6 -0.6 m
0.6 -0.6 l
0.6 0.6 l
-0.6 0.6 l
h
</path>
</symbol>
<symbol name="mark/fsquare(sfx)" transformations="translations">
<group>
<path fill="sym-fill">
-0.5 -0.5 m
0.5 -0.5 l
0.5 0.5 l
-0.5 0.5 l
h
</path>
<path fill="sym-stroke" fillrule="eofill">
-0.6 -0.6 m
0.6 -0.6 l
0.6 0.6 l
-0.6 0.6 l
h
-0.4 -0.4 m
0.4 -0.4 l
0.4 0.4 l
-0.4 0.4 l
h
</path>
</group>
</symbol>
<symbol name="mark/cross(sx)" transformations="translations">
<group>
<path fill="sym-stroke">
-0.43 -0.57 m
0.57 0.43 l
0.43 0.57 l
-0.57 -0.43 l
h
</path>
<path fill="sym-stroke">
-0.43 0.57 m
0.57 -0.43 l
0.43 -0.57 l
-0.57 0.43 l
h
</path>
</group>
</symbol>
<symbol name="arrow/fnormal(spx)">
<path stroke="sym-stroke" fill="white" pen="sym-pen">
0 0 m
-1 0.333 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/pointed(spx)">
<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
0 0 m
-1 0.333 l
-0.8 0 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/fpointed(spx)">
<path stroke="sym-stroke" fill="white" pen="sym-pen">
0 0 m
-1 0.333 l
-0.8 0 l
-1 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/linear(spx)">
<path stroke="sym-stroke" pen="sym-pen">
-1 0.333 m
0 0 l
-1 -0.333 l
</path>
</symbol>
<symbol name="arrow/fdouble(spx)">
<path stroke="sym-stroke" fill="white" pen="sym-pen">
0 0 m
-1 0.333 l
-1 -0.333 l
h
-1 0 m
-2 0.333 l
-2 -0.333 l
h
</path>
</symbol>
<symbol name="arrow/double(spx)">
<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
0 0 m
-1 0.333 l
-1 -0.333 l
h
-1 0 m
-2 0.333 l
-2 -0.333 l
h
</path>
</symbol>
<pen name="heavier" value="0.8"/>
<pen name="fat" value="1.2"/>
<pen name="ultrafat" value="2"/>
<symbolsize name="large" value="5"/>
<symbolsize name="small" value="2"/>
<symbolsize name="tiny" value="1.1"/>
<arrowsize name="large" value="10"/>
<arrowsize name="small" value="5"/>
<arrowsize name="tiny" value="3"/>
<color name="red" value="1 0 0"/>
<color name="green" value="0 1 0"/>
<color name="blue" value="0 0 1"/>
<color name="yellow" value="1 1 0"/>
<color name="orange" value="1 0.647 0"/>
<color name="gold" value="1 0.843 0"/>
<color name="purple" value="0.627 0.125 0.941"/>
<color name="gray" value="0.745"/>
<color name="brown" value="0.647 0.165 0.165"/>
<color name="navy" value="0 0 0.502"/>
<color name="pink" value="1 0.753 0.796"/>
<color name="seagreen" value="0.18 0.545 0.341"/>
<color name="turquoise" value="0.251 0.878 0.816"/>
<color name="violet" value="0.933 0.51 0.933"/>
<color name="darkblue" value="0 0 0.545"/>
<color name="darkcyan" value="0 0.545 0.545"/>
<color name="darkgray" value="0.663"/>
<color name="darkgreen" value="0 0.392 0"/>
<color name="darkmagenta" value="0.545 0 0.545"/>
<color name="darkorange" value="1 0.549 0"/>
<color name="darkred" value="0.545 0 0"/>
<color name="lightblue" value="0.678 0.847 0.902"/>
<color name="lightcyan" value="0.878 1 1"/>
<color name="lightgray" value="0.827"/>
<color name="lightgreen" value="0.565 0.933 0.565"/>
<color name="lightyellow" value="1 1 0.878"/>
<dashstyle name="dashed" value="[4] 0"/>
<dashstyle name="dotted" value="[1 3] 0"/>
<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>
<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>
<textsize name="large" value="\large"/>
<textsize name="small" value="\small"/>
<textsize name="tiny" value="\tiny"/>
<textsize name="Large" value="\Large"/>
<textsize name="LARGE" value="\LARGE"/>
<textsize name="huge" value="\huge"/>
<textsize name="Huge" value="\Huge"/>
<textsize name="footnote" value="\footnotesize"/>
<textstyle name="center" begin="\begin{center}" end="\end{center}"/>
<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>
<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>
<gridsize name="4 pts" value="4"/>
<gridsize name="8 pts (~3 mm)" value="8"/>
<gridsize name="16 pts (~6 mm)" value="16"/>
<gridsize name="32 pts (~12 mm)" value="32"/>
<gridsize name="10 pts (~3.5 mm)" value="10"/>
<gridsize name="20 pts (~7 mm)" value="20"/>
<gridsize name="14 pts (~5 mm)" value="14"/>
<gridsize name="28 pts (~10 mm)" value="28"/>
<gridsize name="56 pts (~20 mm)" value="56"/>
<anglesize name="90 deg" value="90"/>
<anglesize name="60 deg" value="60"/>
<anglesize name="45 deg" value="45"/>
<anglesize name="30 deg" value="30"/>
<anglesize name="22.5 deg" value="22.5"/>
<opacity name="10%" value="0.1"/>
<opacity name="30%" value="0.3"/>
<opacity name="50%" value="0.5"/>
<opacity name="75%" value="0.75"/>
<tiling name="falling" angle="-60" step="4" width="1"/>
<tiling name="rising" angle="30" step="4" width="1"/>
</ipestyle>
<page>
<layer name="alpha"/>
<view layers="alpha" active="alpha"/>
<path layer="alpha" stroke="black">
258.945 794.847 m
295.908 741.175 l
397.176 749.783 l
301.478 695.098 l
359.707 624.21 l
273.629 662.186 l
186.032 617.122 l
226.033 706.744 l
137.93 749.276 l
241.73 743.2 l
h
</path>
</page>
</ipe>