Skip to content

Commit 48d314c

Browse files
committed
Improved Path.simplify
1 parent 64da0ef commit 48d314c

File tree

3 files changed

+45
-56
lines changed

3 files changed

+45
-56
lines changed

macros/ILL.Shapery.moon

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export script_name = "Shapery"
22
export script_description = "Does several types of shape manipulations from the simplest to the most complex"
3-
export script_version = "2.5.7"
3+
export script_version = "2.5.8"
44
export script_author = "ILLTeam"
55
export script_namespace = "ILL.Shapery"
66

@@ -223,15 +223,18 @@ ManipulateDialog = (sub, sel, activeLine) ->
223223
if button != "Cancel"
224224
cfg = getConfigElements!
225225
ass = Ass sub, sel, activeLine, not cfg.saveLines
226-
{:enableClip, :recreateBezier, :distance, :angleThreshold} = elements
226+
{:enableClip, :recreateBezier, :distance, :angleThreshold, :tolerance} = elements
227227
for l, s, i, n in ass\iterSel!
228228
ass\progressLine s, i, n
229229
Line.extend ass, l
230230
if enableClip
231231
{:clip, :isIclip} = l.data
232232
if clip
233233
if type(clip) != "table"
234-
clip = Path(clip)\flatten(distance)\simplify(tolerance, false, recreateBezier, angleThreshold)\export!
234+
if button == "Flatten"
235+
clip = Path(clip)\flatten(distance)\export!
236+
elseif button == "Simplify"
237+
clip = Path(clip)\simplify(tolerance, false, recreateBezier, angleThreshold)\export!
235238
if isIclip
236239
l.tags\insert {{"iclip", clip}}
237240
else
@@ -248,7 +251,7 @@ ManipulateDialog = (sub, sel, activeLine) ->
248251
if button == "Flatten"
249252
path\flatten distance
250253
elseif button == "Simplify"
251-
path\flatten(distance)\simplify tolerance, false, recreateBezier, angleThreshold
254+
path\simplify tolerance, false, recreateBezier, angleThreshold
252255
l.shape = path\export!
253256
ass\insertLine l, s
254257
else

modules/ILL/ILL.moon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module_version = "1.6.1"
1+
module_version = "1.6.2"
22

33
haveDepCtrl, DependencyControl = pcall require, "l0.DependencyControl"
44

modules/ILL/ILL/Ass/Shape/Path.moon

Lines changed: 37 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,12 @@ class Path
123123
return @
124124

125125
-- Simplifies the number of path points
126-
simplify: (tolerance = 0.5, highestQuality = true, recreateBezier = true, angleThreshold = 170) =>
127-
@cleanContours!
126+
simplify: (tolerance = 0.5, filterNoise = true, recreateBezier = true, angleThreshold = 170) =>
128127
if @hasCurve
129128
@flatten!
130129
if recreateBezier
131130
@hasCurve = true
132-
@path = Path.Simplifier @path, tolerance, highestQuality, recreateBezier, angleThreshold
131+
@path = Path.Simplifier @path, tolerance, filterNoise, recreateBezier, angleThreshold
133132
return @
134133

135134
-- Move the @path by specified distance
@@ -580,7 +579,8 @@ class Path
580579
offset: (delta, join_type, end_type, miter_limit, arc_tolerance, preserve_collinear, reverse_solution) =>
581580
subj = @convertToClipper!
582581
subj = subj\inflate delta, join_type, end_type, miter_limit, arc_tolerance, preserve_collinear, reverse_solution
583-
@path = Path.convertFromClipper(subj).path
582+
result = Path.convertFromClipper(subj).path
583+
@path = Path.Simplifier result, 0.1, true, false
584584
return @
585585

586586
Path.RoundingPath = (path, radius, inverted = false, cornerStyle = "Rounded", rounding = "Absolute") ->
@@ -888,7 +888,7 @@ Path.RoundingPath = (path, radius, inverted = false, cornerStyle = "Rounded", ro
888888

889889
return newPath
890890

891-
Path.Simplifier = (points, tolerance = 0.1, highestQuality, recreateBezier, angleThreshold) ->
891+
Path.Simplifier = (paths, tolerance, filterNoise, recreateBezier, angleThreshold) ->
892892
simplifyRadialDist = (points, sqTolerance) ->
893893
prevPoint = points[1]
894894
newPoints = {prevPoint}
@@ -1151,87 +1151,73 @@ Path.Simplifier = (points, tolerance = 0.1, highestQuality, recreateBezier, angl
11511151
tHat1 = computeLeftTangent(d, 1)
11521152
tHat2 = computeRightTangent(d, nPts)
11531153
fitCubic(b, d, 1, nPts, tHat1, tHat2, _error)
1154-
1155-
getAngle = (p1, p2, p3) ->
1156-
x1, y1 = p1.x, p1.y
1157-
x2, y2 = p2.x, p2.y
1158-
x3, y3 = p3.x, p3.y
1159-
angle = math.atan2(y3 - y2, x3 - x2) - math.atan2(y1 - y2, x1 - x2)
1160-
return math.deg(angle)
1161-
1162-
elaborateSelected = (selected, final, tolerance) ->
11631154

1164-
if #selected <= 4
1165-
for i = 1, #selected
1166-
insert final, selected[i]
1167-
return
1155+
elaborateSection = (section, final, tolerance) ->
1156+
if #section <= 4
1157+
for i = 2, #section
1158+
insert final, section[i]
1159+
return {section[#section]}
11681160

1169-
b = {selected[1]}
1161+
b = {section[1]}
11701162

1171-
fitCurve(b, selected, #selected, tolerance)
1163+
fitCurve(b, section, #section, tolerance)
11721164

1173-
for i = 1, #b
1165+
for i = 2, #b
11741166
insert final, b[i]
1167+
1168+
return {b[#b]}
11751169

11761170
isInRange = (cs, ls) ->
11771171
if not (cs > ls * 2) and not (cs < ls / 2)
11781172
return true
11791173
return false
11801174

1181-
simplify = (points, tolerance, angleThreshold) ->
1175+
getAngle = (p1, p2, p3) ->
1176+
x1, y1 = p1.x, p1.y
1177+
x2, y2 = p2.x, p2.y
1178+
x3, y3 = p3.x, p3.y
1179+
angle = math.atan2(y3 - y2, x3 - x2) - math.atan2(y1 - y2, x1 - x2)
1180+
return math.deg(angle)
1181+
1182+
simplifyBezier = (points, tolerance, angleThreshold) ->
11821183
at1, at2 = angleThreshold, 360 - angleThreshold
11831184
final = {}
11841185

1185-
-- first and last points are duplicated for checks but ignored
11861186
insert points, 1, points[#points]
11871187
insert points, points[2]
11881188

1189-
lastSegmentLength = 0
1190-
selected = {points[1]}
1191-
-- the current work around to remove duplicated points
1192-
-- close the contour by duplicating the first point
1193-
-- in this foor loop is possible to change to #points - 2
1194-
-- if you want to have an open contour
1189+
lastSegmentLength = points[1]\distance(points[2])
1190+
section = {points[1]}
1191+
11951192
for i = 2, #points - 1
1196-
1197-
-- first point must not be a control point
1198-
if i == 2
1199-
lastSegmentLength = points[2]\distance(points[3])
1200-
points[i].id = "l"
1201-
selected = {points[i]}
1202-
continue
1203-
insert selected, points[i]
1193+
insert section, points[i]
12041194

12051195
currSegmentLength = points[i]\distance(points[i + 1])
12061196
if not isInRange(currSegmentLength, lastSegmentLength)
1207-
elaborateSelected(selected, final, tolerance)
1208-
selected = {}
1197+
section = elaborateSection(section, final, tolerance)
12091198
lastSegmentLength = currSegmentLength
12101199
continue
12111200

12121201
ang = math.abs getAngle(points[i-1], points[i], points[i+1])
12131202
if ang < at1 or ang > at2
1214-
elaborateSelected(selected, final, tolerance)
1215-
selected = {}
1203+
section = elaborateSection(section, final, tolerance)
12161204
lastSegmentLength = currSegmentLength
12171205
continue
12181206

12191207
lastSegmentLength = currSegmentLength
12201208

1221-
elaborateSelected(selected, final, tolerance)
12221209
return final
12231210

1224-
for i = 1, #points
1211+
for i = 1, #paths
1212+
if filterNoise
1213+
paths[i] = simplifyRadialDist(paths[i], tolerance)
1214+
12251215
if recreateBezier
1226-
points[i] = simplifyRadialDist(points[i], 0.5) -- from 0.5 to 1
1227-
points[i] = simplify(points[i], tolerance, angleThreshold)
1216+
paths[i] = simplifyBezier(paths[i], tolerance, angleThreshold)
12281217
else
12291218
sqTolerance = tolerance * tolerance
1230-
if not highestQuality
1231-
points[i] = simplifyRadialDist(points[i], sqTolerance)
1232-
1233-
points[i] = simplifyDouglasPeucker(points[i], sqTolerance)
1234-
1235-
return points
1219+
paths[i] = simplifyDouglasPeucker(paths[i], sqTolerance)
1220+
1221+
return paths
12361222

12371223
{:Path}

0 commit comments

Comments
 (0)