[Ipe-discuss] ipelet: smooth

Zhengdao Wang zhengdao at iastate.edu
Sun Aug 2 17:42:14 CEST 2015


Attached please find an ipelet that performs smoothing
operation on selected curves. It can be useful for
smoothing a path that has many small line segments. For
example, when using the "Ink" tool, the drawn curves
are usually not smooth. After applying the smoothing
operation the appearance is more pleasing.

I also attached an example document to show the effects.

To use it, simply select the curves that need to be
smoothed, and then apply the operation.

If this can be incorporated to Ipe itself, applied
automatically after each Ink tool invocation, it would
be more convenient.

Another improvement that is possible would be to
approximate a curve with splines, and reduce the number
of control points, for making the resulting file
smaller and rendering faster.

Feedback and comments are welcomed.

Zhengdao
-------------- next part --------------
-- smooth.lua : smooth a curve that has just line segments

-- GPL license

label = "Smooth"

about = [[
  Smooth Curves
]]

--  Given a path object, run moving average smoothing and return the
--  smoothed object

function smooth(obj)
  local M=5 -- single sided moving average length
  local OFFSET=0
  local newobj=obj:clone()
  local shape=obj:shape()
  if #shape > 1 then -- if more than one path
    return newobj
  end
  path=shape[1]
  if path.type~="curve" or path.closed==true then
    return newobj
  end

  -- collect the coordinates
  local X,Y={},{}
  for i=1,#path do
    X[i]=path[i][1].x
    Y[i]=path[i][1].y
  end
  X[#path+1]=path[#path][2].x
  Y[#path+1]=path[#path][2].y

  -- smoothing
  local X2={X[1]}
  local Y2={Y[1]}
  for i=2,#path do
    local x,y=0,0
    for j=-M,M do
      k=math.max(i+j, 1)
      k=math.min(k, #path+1)
      x=x+X[k]
      y=y+Y[k]
    end
    X2[i]=x/(2*M+1)
    Y2[i]=y/(2*M+1)+OFFSET
  end
  X2[#path+1]=X[#path+1]
  Y2[#path+1]=Y[#path+1]

  -- down sampling by a factor of N
  local N=2
  local X3,Y3={X2[1]},{Y2[1]}
  for i=1,math.floor((#path+1)/N) do
    X3[i+1],Y3[i+1]=X2[i*N],Y2[i*N]
  end
  if math.floor((#path+1)/N)*N~=#path+1 then
    X3[#X3+1],Y3[#Y3+1]=X2[#X2],Y2[#Y2]
  end

  -- assemble the segments
  local newpath={type="curve", closed=false}
  for i=1,#X3-1 do
    newpath[i]={type="segment", ipe.Vector(X3[i], Y3[i]), ipe.Vector(X3[i+1], Y3[i+1])}
  end

  local shape={newpath}
  newobj:setShape(shape)
  return newobj
end

function runsmooth(model)
  gmodel=model
  p=model:page()
  replace={}
  for i, obj, sel, layer in p:objects() do
    if sel then
      replace[#replace+1]={i, p[i]:clone(), smooth(p[i])}
    end
  end

  local t = { label="smoothing", pno=model.pno, vno=model.vno,
          layer=p:active(model.vno),
          original=p:clone(),
          replace=replace}
  t.undo = function (t, doc)
       for i=1,#t.replace do
         doc[t.pno]:replace(t.replace[i][1], t.replace[i][2])
       end
       end
  t.redo = function (t, doc)
       for i=1,#t.replace do
         doc[t.pno]:replace(t.replace[i][1], t.replace[i][3])
       end
       end
  model:register(t)
end

methods = {
  { label = "Smooth", run=runsmooth }
}

-- shortcuts.automatic_snap=nil
-- shortcuts.ipelet_1_smooth="F9"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smooth-test.pdf
Type: application/pdf
Size: 39235 bytes
Desc: not available
Url : http://lists.science.uu.nl/pipermail/ipe-discuss/attachments/20150802/a74199e9/attachment-0001.pdf 


More information about the Ipe-discuss mailing list