Skip to content

Commit 8e3f613

Browse files
authored
Merge pull request #3838 from Zinoex/fm/minkowski_2d_polygonal_chain
Fix `_minkowski_sum_vrep_2d`
2 parents 1cdaf6e + 3492cf6 commit 8e3f613

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

src/ConcreteOperations/minkowski_sum.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,28 +222,41 @@ function _minkowski_sum_vrep_2d(vlistP::AbstractVector{<:AbstractVector{N}},
222222
return _minkowski_sum_vrep_2d_singleton(vlistP, vlistQ)
223223
end
224224

225-
EAST = N[1, 0]
226-
ORIGIN = N[0, 0]
227-
R = fill(ORIGIN, mP + mQ)
228-
k = _σ_helper(EAST, vlistP)
229-
j = _σ_helper(EAST, vlistQ)
225+
R = fill(N[0, 0], mP + mQ)
226+
P₁P₂ = N[0, 0]
227+
Q₁Q₂ = N[0, 0]
228+
229+
# `_σ_helper(WEST, vlistP)` would be faster but if the direction is
230+
# orthogonal to a facet, it may return a pair of vertices (k, j) that
231+
# added together is not a vertex of the Minkowski sum.
232+
233+
# Instead, argmin searches WEST and if two such vertices exist, it
234+
# arbitrates between them by picking the one with the smallest x[2].
235+
# This is guaranteed to be a vertex of the Minkowski sum.
236+
k = argmin(vlistP)
237+
j = argmin(vlistQ)
230238

231239
i = 1
232240
while i <= size(R, 1)
233-
P₁, P₂ = vlistP[(k - 1) % mP + 1], vlistP[(k % mP + 1)]
234-
P₁P₂ = P₂ - P₁
235-
Q₁, Q₂ = vlistQ[(j - 1) % mQ + 1], vlistQ[(j % mQ + 1)]
236-
Q₁Q₂ = Q₂ - Q₁
241+
P₁, P₂ = vlistP[mod1(k, mP)], vlistP[mod1(k + 1, mP)]
242+
@. P₁P₂ = P₂ - P₁
243+
Q₁, Q₂ = vlistQ[mod1(j, mQ)], vlistQ[mod1(j + 1, mQ)]
244+
@. Q₁Q₂ = Q₂ - Q₁
237245
R[i] = P₁ + Q₁
238-
turn = right_turn(P₁P₂, Q₁Q₂, ORIGIN)
246+
turn = right_turn(P₁P₂, Q₁Q₂)
239247
if turn > 0
240248
k += 1
241249
elseif turn < 0
242250
j += 1
243-
else
251+
else # collinear and same direction
252+
# Increment both k and j, and Minkowski sum will have one less vertex.
244253
pop!(R)
245254
k += 1
246255
j += 1
256+
257+
# Note: collinear and opposite direction is not possible, as the
258+
# the one of the two vertices would lie outside the respective polygons.
259+
# This only holds for proper initialization and sorted vertices.
247260
end
248261
i += 1
249262
end

src/Sets/VPolygon/minkowski_sum.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ sorted in counter-clockwise fashion and has linear complexity ``O(m+n)``, where
1414
"""
1515
function minkowski_sum(P::VPolygon, Q::VPolygon)
1616
R = _minkowski_sum_vrep_2d(P.vertices, Q.vertices)
17-
return VPolygon(R)
17+
return VPolygon(R, apply_convex_hull=false)
1818
end

test/Sets/Polygon.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,34 @@ for N in [Float64, Float32, Rational{Int}]
190190
[N[2, -2], N[6, 0], N[8, 2],
191191
N[8, 4], N[6, 6], N[2, 8]])
192192

193+
P = VPolygon([N[0, -1], N[2, 0], N[1, 1], N[0, 1]], apply_convex_hull=false)
194+
Q1 = VPolygon([N[0, 1], N[0, -1]], apply_convex_hull=false)
195+
Q2 = VPolygon([N[0, 1], N[0, -1]], apply_convex_hull=false)
196+
PQ1 = minkowski_sum(P, Q1)
197+
PQ2 = minkowski_sum(P, Q2)
198+
@test length(PQ1.vertices) == 5
199+
@test is_cyclic_permutation(PQ1.vertices,
200+
[N[0, -2], N[2, -1], N[2, 1],
201+
N[1, 2], N[0, 2]])
202+
@test length(PQ2.vertices) == 5
203+
@test is_cyclic_permutation(PQ2.vertices,
204+
[N[0, -2], N[2, -1], N[2, 1],
205+
N[1, 2], N[0, 2]])
206+
207+
P = VPolygon([N[-1, -1], N[2, 0], N[2, 1], N[0, 1]], apply_convex_hull=false)
208+
Q1 = VPolygon([N[0, 1], N[0, -1]], apply_convex_hull=false)
209+
Q2 = VPolygon([N[0, -1], N[0, 1]], apply_convex_hull=false)
210+
PQ1 = minkowski_sum(P, Q1)
211+
PQ2 = minkowski_sum(P, Q2)
212+
@test length(PQ1.vertices) == 5
213+
@test is_cyclic_permutation(PQ1.vertices,
214+
[N[-1, -2], N[2, -1], N[2, 2],
215+
N[0, 2], N[-1, 0]])
216+
@test length(PQ2.vertices) == 5
217+
@test is_cyclic_permutation(PQ2.vertices,
218+
[N[-1, -2], N[2, -1], N[2, 2],
219+
N[0, 2], N[-1, 0]])
220+
193221
# test for different starting points in vertices_list of minkowski sum
194222
P = VPolygon([N[4, 0], N[6, 2], N[4, 4]])
195223
P2 = VPolygon([N[4, 4], N[4, 0], N[6, 2]])

0 commit comments

Comments
 (0)