ipelet: smooth
Zhengdao Wang <zhengdao-KgB/[email protected]>
| Newsgroups | gmane.comp.graphics.ipe.general |
|---|---|
| Message-ID | <[email protected]> |
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 _______________________________________________ Ipe-discuss mailing list Ipe-discuss-rGrgPyRx506NN8uzcEdRPYRWq/[email protected] http://lists.science.uu.nl/mailman/listinfo/ipe-discuss
smooth.lua
(text/plain, 2.2 KB)
-- 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"
smooth-test.pdf
(application/pdf, 38.3 KB) - not displayed