Skip to content

Commit 0e361fc

Browse files
Merge pull request #42 from ModiaSim/an_avoidCollisionErrors
An avoid collision errors
2 parents 7114e47 + 39c020b commit 0e361fc

File tree

1 file changed

+136
-82
lines changed
  • src/contactDetection/ContactDetectionMPR

1 file changed

+136
-82
lines changed

src/contactDetection/ContactDetectionMPR/mpr.jl

Lines changed: 136 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ function getSupportPoint(shapeA::Modia3D.Composition.Object3D, shapeB::Compositi
2121
return SupportPoint((a-b).*scale,n,a,b)
2222
end
2323

24-
#=
25-
function getSupportPoint(shapeA::Modia3D.Composition.Object3D, shapeB::Composition.Object3D, n::Nothing; scale::Float64=1.0)
26-
println(Modia3D.fullName(shapeA), " r_abs ", shapeA.r_abs, " R_abs ", shapeA.R_abs)
27-
println(Modia3D.fullName(shapeB), " r_abs ", shapeB.r_abs, " R_abs ", shapeB.R_abs)
28-
error("numerical issues computing normalized vector")
29-
return nothing
30-
end
31-
=#
3224

3325
function barycentric(r1::SupportPoint,r2::SupportPoint,r3::SupportPoint,r4::SupportPoint)
3426
r21 = r2.p - r1.p
@@ -75,7 +67,7 @@ end
7567
# belongs to construction of r0
7668
function checkCentersOfShapesOverlapp(r0::SupportPoint, neps::Float64, shapeA::Composition.Object3D, shapeB::Composition.Object3D)
7769
if norm(r0.p) <= neps
78-
error("MPR: Too large penetration (prerequisite of MPR violated). Centers are overlapping. Look at shapeA = ", shapeA, " shapeB = ", shapeB)
70+
error("MPR: Too large penetration (prerequisite of MPR violated). Centers are overlapping. Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
7971
end
8072
end
8173

@@ -94,7 +86,7 @@ function checkIfShapesArePlanar(r0::SupportPoint,r1::SupportPoint,r2::SupportPoi
9486
# Shape is purely planar. Computing the shortest distance for a planar shape
9587
# requires an MPR 2D algorithm (using lines instead of triangles as portals).
9688
# However, this is not implemented and therefore the shortest distance cannot be computed
97-
error("MPR: Shapes are planar and MPR2D is not supported. abs(dot((r2.p-r1.p),n2)). Look at shapeA = ", shapeA, " shapeB = ", shapeB)
89+
error("MPR: Shapes are planar and MPR2D is not supported. abs(dot((r2.p-r1.p),n2)). Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
9890
end
9991
# new normal to the triangle plane (r0-r1-r2_new)
10092
n3 = cross(r1.p-r0.p, r2.p-r0.p) # |n3| > 0 guaranteed, due to construction
@@ -114,7 +106,7 @@ function checkIfShapesArePlanar(r0::SupportPoint,r1::SupportPoint,r2::SupportPoi
114106
# Shape is purely planar. Computing the shortest distance for a planar shape
115107
# requires an MPR 2D algorithm (using lines instead of triangles as portals).
116108
# However, this is not implemented and therefore the shortest distance cannot be computed
117-
error("MPR: Shapes are planar and MPR2D is not supported. r1, r2, r3 are on the same ray. abs(dot((r3.p-r1.p),r3.n)) <= neps. Look at shapeA = ", shapeA, " shapeB = ", shapeB)
109+
error("MPR: Shapes are planar and MPR2D is not supported. r1, r2, r3 are on the same ray. abs(dot((r3.p-r1.p),r3.n)) <= neps. Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
118110
end
119111
end
120112

@@ -126,9 +118,13 @@ end
126118
# loop around to "ensure" the tetrahedron r0,r1,r2 and r3 encloses the origin
127119
# stimmt so nicht wirklich, muss ich nochmal nachlesen!!!
128120
# Der Ursprung muss nicht enthalten sein!!!
129-
function tetrahedronEncloseOrigin(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,r3::SupportPoint,
130-
neps::Float64, niter_max::Int64,
131-
shapeA::Composition.Object3D,shapeB::Composition.Object3D, scale::Float64)
121+
function tetrahedronEncloseOrigin(r0::SupportPoint, r1::SupportPoint,
122+
r2::SupportPoint, r3::SupportPoint,
123+
neps::Float64, niter_max::Int64,
124+
shapeA::Composition.Object3D, shapeB::Composition.Object3D, scale::Float64)
125+
r1org = r1
126+
r2org = r2
127+
r3org = r3
132128
aux = Modia3D.ZeroVector3D
133129
success = false
134130
for i in 1:niter_max
@@ -148,9 +144,13 @@ function tetrahedronEncloseOrigin(r0::SupportPoint,r1::SupportPoint,r2::SupportP
148144
break
149145
end
150146
if success != true
151-
error("MPR: Max. number of iterations is reached in phase2. Look at shapeA = ", shapeA, " shapeB = ", shapeB)
147+
if niter_max <= 100
148+
@warn("MPR (phase 2): Max. number of iterations (= $niter_max) is reached. niter_max increased locally by 10 and phase 2 is rerun. Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
149+
tetrahedronEncloseOrigin(r0, r1org, r2org, r3org, neps, niter_max + 10, shapeA, shapeB, scale)
150+
else
151+
error("MPR (phase 2): Max. number of iterations (= $niter_max) is reached and $niter_max > 100, look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
152+
end
152153
end
153-
# pointInTetrahedron(r0.p,r1.p,r2.p,r3.p,SVector(0.0, 0.0, 0.0))
154154
return (r1, r2, r3)
155155
end
156156

@@ -166,7 +166,7 @@ function constructR4(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,r3::Supp
166166
# Shape is purely planar. Computing the shortest distance for a planar shape
167167
# requires an MPR 2D algorithm (using lines instead of triangles as portals).
168168
# However, this is not implemented and therefore the shortest distance cannot be computed
169-
error("MPR: Shapes are planar and MPR2D is not supported. abs(dot((r3.p-r1.p),r3.n)). Look at shapeA = ", shapeA, " shapeB = ", shapeB)
169+
error("MPR: Shapes are planar and MPR2D is not supported. abs(dot((r3.p-r1.p),r3.n)). Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
170170
end
171171
n4 = cross(r2.p-r1.p, r3.p-r1.p) # |n4| > 0 guaranteed, due to construction
172172
end
@@ -178,8 +178,8 @@ function constructR4(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,r3::Supp
178178
return (r3, r4, n4)
179179
end
180180

181-
182-
isNextPortal(r0,r1,r2,r4) = dot( cross( (r2.p-r0.p), (r4.p-r0.p) ), r0.n ) <= 0.0 &&
181+
# computes twice a parallelepipedial product (Spatprodukt)
182+
isNextPortal(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r4::SupportPoint) = dot( cross( (r2.p-r0.p), (r4.p-r0.p) ), r0.n ) <= 0.0 &&
183183
dot( cross( (r4.p-r0.p), (r1.p-r0.p) ), r0.n ) <= 0.0
184184

185185

@@ -189,29 +189,25 @@ isNextPortal(r0,r1,r2,r4) = dot( cross( (r2.p-r0.p), (r4.p-r0.p) ), r0.n ) <= 0.
189189
# r1r2r4
190190
# r2r3r4
191191
# r3r1r4
192-
function createBabyTetrahedrons(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,r3::SupportPoint,r4::SupportPoint,
193-
shapeA::Composition.Object3D,shapeB::Composition.Object3D)
192+
function createBabyTetrahedrons(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, r4::SupportPoint)
193+
nextPortal = true
194194
if isNextPortal(r0,r1,r2,r4)
195195
r3 = r4
196196
elseif isNextPortal(r0,r2,r3,r4)
197197
r1 = r4
198198
elseif isNextPortal(r0,r3,r1,r4)
199199
r2 = r4
200200
else
201-
# Compute the closest distance to the portal and return it:
202-
(r4.p, distance) = signedDistanceToPortal(r0.p,r1.p,r2.p,r3.p)
203-
barycentric(r1,r2,r3,r4)
204-
error("MPR: Numerical issues with distance computation between shapeA = ", shapeA, " and shapeB = ", shapeB,". Used distance = ",distance)
205-
return (r1, r2, r3)
201+
nextPortal = false # the signs of all tried combinations of parallelepipedial products are not negative
206202
end
207-
return (r1, r2, r3)
203+
return (nextPortal, r1, r2, r3)
208204
end
209205

210206

211207
scaleVector(scale, ri) = ri.*scale
212208

213209

214-
function skalarization(r0,r1,r2,r3)
210+
function skalarization(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint)
215211
x = maximum([abs.(r0.p) abs.(r1.p) abs.(r2.p) abs.(r3.p)])
216212
scale = 1/x
217213
r0.p = scaleVector(scale, r0.p)
@@ -221,6 +217,116 @@ function skalarization(r0,r1,r2,r3)
221217
return (r0, r1, r2, r3, scale)
222218
end
223219

220+
function finalTC2(r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, r4::SupportPoint)
221+
#println("TC 2")
222+
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
223+
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
224+
#end
225+
distance = -dot(r4.n, r4.p)
226+
barycentric(r1,r2,r3,r4)
227+
return distance, r1, r2, r3, r4
228+
end
229+
230+
231+
function finalTC3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, r4::SupportPoint)
232+
#println("TC 3")
233+
234+
#doesRayIntersectPortal(r1.p,r2.p,r3.p, r4.p,neps)
235+
#println("r1.p = ", r1.p , " r2.p = ", r2.p ," r3.p = ", r3.p)
236+
#println("r4.p = ", r4.p)
237+
#println(" ")
238+
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
239+
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
240+
#end
241+
(r4.p, distance) = signedDistanceToPortal(r0.p,r1.p,r2.p,r3.p)
242+
barycentric(r1,r2,r3,r4)
243+
return distance, r1, r2, r3, r4
244+
end
245+
246+
247+
function phase3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, neps::Float64, niter_max::Int64,tol_rel::Float64, shapeA::Composition.Object3D,shapeB::Composition.Object3D, scale::Float64)
248+
r1org = r1
249+
r2org = r2
250+
r3org = r3
251+
new_tol = 42.0
252+
isTC2 = false
253+
isTC3 = false
254+
r1_new::SupportPoint = r0
255+
r2_new::SupportPoint = r0
256+
r3_new::SupportPoint = r0
257+
r4_new::SupportPoint = r0
258+
for i in 1:niter_max
259+
### Phase 3.1: construct r4 ###
260+
# Find support point using the tetrahedron face
261+
(r3,r4,n4) = constructR4(r0,r1,r2,r3,neps,shapeA,shapeB, scale)
262+
263+
264+
### Phase 3.2: check if r4 is close to the origin ###
265+
# check if the new point r4 is already on the plane of the triangle r1,r2,r3,
266+
# we're already as close as we can get to the origin
267+
TC2 = norm(cross(r4.p,r4.n)) # TC2
268+
TC3 = abs(dot(r4.p-r1.p, r4.n)) # TC3
269+
## TERMINATION CONDITION 2 ##
270+
if TC2 < tol_rel
271+
(distance,r1,r2,r3,r4) = finalTC2(r1,r2,r3,r4)
272+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
273+
274+
## TERMINATION CONDITION 3 ##
275+
elseif TC3 < tol_rel
276+
(distance,r1,r2,r3,r4) = finalTC3(r0, r1, r2, r3, r4)
277+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
278+
else
279+
if TC2 < new_tol
280+
new_tol = TC2
281+
isTC2 = true
282+
isTC3 = false
283+
r1_new = r1
284+
r2_new = r2
285+
r3_new = r3
286+
r4_new = r4
287+
end
288+
if TC3 < new_tol
289+
new_tol = TC3
290+
isTC2 = false
291+
isTC3 = true
292+
r1_new = r1
293+
r2_new = r2
294+
r3_new = r3
295+
r4_new = r4
296+
end
297+
end
298+
299+
#### Phase 3.3: construct baby tetrahedrons with r1,r2,r3,r4 and create a new portal ###
300+
# Construction of three baby tetrahedrons
301+
(nextPortal, r1,r2,r3) = createBabyTetrahedrons(r0,r1,r2,r3,r4)
302+
303+
if !nextPortal # createBabyTetrahedrons failed
304+
@warn("MPR (phase 3): Numerical issues with distance computation between $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)). tol_rel increased locally for this computation to $new_tol.")
305+
if isTC2
306+
(distance,r1,r2,r3,r4) = finalTC2(r1_new,r2_new,r3_new,r4_new)
307+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
308+
end
309+
if isTC3
310+
(distance,r1,r2,r3,r4) = finalTC3(r0, r1_new, r2_new, r3_new, r4_new)
311+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
312+
end
313+
end
314+
end
315+
if niter_max <= 100
316+
@warn("MPR (phase 3): Numerical issues with distance computation between $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)). Max. number of iterations (= $niter_max) is reached. niter_max increased locally by 10 and phase 3 is rerun.")
317+
phase3(r0, r1org, r2org, r3org, neps, niter_max + 10, tol_rel, shapeA, shapeB, scale)
318+
else
319+
@warn("MPR (phase 3): Max. number of iterations (= $niter_max) is reached and $niter_max > 100, look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)). tol_rel increased locally for this computation to $new_tol.")
320+
if isTC2
321+
(distance,r1,r2,r3,r4) = finalTC2(r1_new,r2_new,r3_new,r4_new)
322+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
323+
end
324+
if isTC3
325+
(distance,r1,r2,r3,r4) = finalTC3(r0, r1_new, r2_new, r3_new, r4_new)
326+
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
327+
end
328+
end
329+
end
224330

225331
# MPR - Minkowski Portal Refinement algorithm
226332
# construction of points r0 is in the interior of Minkowski Difference and points r1,r2,r3,r4 are on the boundary of Minkowski Difference
@@ -301,59 +407,7 @@ function mprGeneral(ch::Composition.ContactDetectionMPR_handler, shapeA::Composi
301407

302408

303409
########### Phase 3, Minkowski Portal Refinement ###################
304-
for i in 1:niter_max
305-
### Phase 3.1: construct r4 ###
306-
# Find support point using the tetrahedron face
307-
(r3,r4,n4) = constructR4(r0,r1,r2,r3,neps,shapeA,shapeB, scale)
308-
309-
310-
### Phase 3.2: check if r4 is close to the origin ###
311-
# check if the new point r4 is already on the plane of the triangle r1,r2,r3,
312-
# we're already as close as we can get to the origin
313-
314-
## TERMINATION CONDITION 2 ##
315-
if norm(cross(r4.p,r4.n)) < tol_rel
316-
#println("TC 2")
317-
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
318-
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
319-
#end
320-
distance = -dot(r4.n, r4.p)
321-
barycentric(r1,r2,r3,r4)
322-
323-
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
324-
325-
## TERMINATION CONDITION 3 ##
326-
elseif abs(dot(r4.p-r1.p, r4.n)) < tol_rel
327-
#println("TC 3")
328-
329-
#doesRayIntersectPortal(r1.p,r2.p,r3.p, r4.p,neps)
330-
#println("r1.p = ", r1.p , " r2.p = ", r2.p ," r3.p = ", r3.p)
331-
#println("r4.p = ", r4.p)
332-
#println(" ")
333-
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
334-
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
335-
#end
336-
(r4.p, distance) = signedDistanceToPortal(r0.p,r1.p,r2.p,r3.p)
337-
barycentric(r1,r2,r3,r4)
338-
339-
return (distance, r4.a, r4.b, r4.n, true, r1.a, r1.b, r2.a, r2.b, r3.a, r3.b)
340-
end
341-
342-
#### Phase 3.3: construct baby tetrahedrons with r1,r2,r3,r4 and create a new portal ###
343-
# Construction of three baby tetrahedrons
344-
(r1,r2,r3) = createBabyTetrahedrons(r0,r1,r2,r3,r4,shapeA,shapeB)
345-
346-
347-
#=
348-
r0RayOnPortal = isr0RayOnPortal(r0.p,r1.p,r2.p,r3.p)
349-
if r0RayOnPortal[1] != true
350-
println("r0RayOnPortal = ", r0RayOnPortal, ": Wrong baby-tetrahedron selected. " , i)
351-
end
352-
=#
353-
354-
end
355-
error("MPR: Should never get here! Computation failed. Look at shapeA = ", Modia3D.instanceName(shapeA),
356-
" shapeB = ", Modia3D.instanceName(shapeB))
410+
phase3(r0, r1, r2, r3, neps, niter_max, tol_rel, shapeA, shapeB, scale)
357411
end
358412

359413

@@ -367,7 +421,7 @@ function mprTwoSpheres(ch::Composition.ContactDetectionMPR_handler, shapeA::Comp
367421
n = centroidSphereB - centroidSphereA
368422
distanceCentroids = norm(n)
369423
if distanceCentroids <= neps
370-
error("Centers of two spheres are overlapping. SphereA = ", shapeA, " sphereB = ", shapeB)
424+
error("Centers of two spheres are overlapping. Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
371425
else
372426
normal = n/distanceCentroids
373427
end

0 commit comments

Comments
 (0)