[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