Skip to content

Commit 37fd23e

Browse files
committed
use nepsMPR instead of neps defined in collision handler
1 parent 5c7e856 commit 37fd23e

File tree

6 files changed

+49
-49
lines changed

6 files changed

+49
-49
lines changed

src/Basics/_module.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Modia3D
1717

1818
export trailingPartOfName
1919

20-
export neps, sign_eps, radToDeg
20+
export nepsMPR, neps, sign_eps, radToDeg
2121
export getAndCheckFullLibraryPath, getEnvironmentVariable
2222

2323
export normalizeVector, BoundingBox

src/Basics/constantsAndFunctions.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@
99
# Epsilon and sign
1010
const neps = sqrt( eps(Modia3D.MPRFloatType) )
1111

12+
nepsMPR(::Type{T}) where {T} = sqrt( eps(T) )
13+
1214
function sign_eps(value::T; ) where {T}
1315
seps::T = 100.0*neps
1416
return value > seps ? T(1.0) : (value < -seps ? T(-1.0) : T(0.0))
1517
end
1618

1719
function normalizeVector(n::SVector{3,T}) where {T}
1820
nabs = norm(n)
19-
if nabs <= neps
20-
println("neps ", neps)
21+
if nabs <= nepsMPR(T)
22+
println("neps ", nepsMPR(T))
2123
println("nabs ", nabs)
22-
@assert(nabs > neps) # && norm(vec) > eps()
24+
@assert(nabs > nepsMPR(T)) # && norm(vec) > eps()
2325
# return nothing
2426
end
2527
return n/nabs

src/Shapes/boundingBoxes.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,21 @@ end
7878
halfDiameter = T(0.5*shape.diameter)
7979
if shape.axis == 1
8080
enorm = norm(SVector(e_abs[2], e_abs[3]))
81-
if enorm <= Modia3D.neps
81+
if enorm <= Modia3D.nepsMPR(T)
8282
return Basics.sign_eps(e_abs[1])*SVector(halfLength, 0.0, 0.0)
8383
else
8484
return Basics.sign_eps(e_abs[1])*SVector(halfLength, 0.0, 0.0) + SVector(0.0, (halfDiameter)*e_abs[2], (halfDiameter)*e_abs[3])/enorm
8585
end
8686
elseif shape.axis == 2
8787
enorm = norm(SVector(e_abs[3], e_abs[1]))
88-
if enorm <= Modia3D.neps
88+
if enorm <= Modia3D.nepsMPR(T)
8989
return Basics.sign_eps(e_abs[2])*SVector(0.0, halfLength, 0.0)
9090
else
9191
return Basics.sign_eps(e_abs[2])*SVector(0.0, halfLength, 0.0) + SVector((halfDiameter)*e_abs[1], 0.0, (halfDiameter)*e_abs[3])/enorm
9292
end
9393
else
9494
enorm = norm(SVector(e_abs[1], e_abs[2]))
95-
if enorm <= Modia3D.neps
95+
if enorm <= Modia3D.nepsMPR(T)
9696
return Basics.sign_eps(e_abs[3])*SVector(0.0, 0.0, halfLength)
9797
else
9898
return Basics.sign_eps(e_abs[3])*SVector(0.0, 0.0, halfLength) + SVector((halfDiameter)*e_abs[1], (halfDiameter)*e_abs[2], 0.0)/enorm
@@ -137,15 +137,15 @@ end
137137
return SVector(shapeLength, 0.0, 0.0) # apex is support point
138138
else # frustum of a cone
139139
enorm = norm(SVector(e_abs[2], e_abs[3]))
140-
if enorm > Modia3D.neps
140+
if enorm > Modia3D.nepsMPR(T)
141141
return SVector(shapeLength, 0.0, 0.0) + SVector(0.0, topRadius*e_abs[2], topRadius*e_abs[3]) / enorm # point on top circle is support point
142142
else
143143
return SVector(shapeLength, 0.0, 0.0) # top circle center is support point
144144
end
145145
end
146146
else
147147
enorm = norm(SVector(e_abs[2], e_abs[3]))
148-
if enorm > Modia3D.neps
148+
if enorm > Modia3D.nepsMPR(T)
149149
return SVector(0.0, baseRadius*e_abs[2], baseRadius*e_abs[3]) / enorm # point on base circle is support point
150150
else
151151
return SVector{3,T}(0.0, 0.0, 0.0) # base circle center is support point
@@ -158,15 +158,15 @@ end
158158
return SVector(0.0, shapeLength, 0.0) # apex is support point
159159
else # frustum of a cone
160160
enorm = norm(SVector(e_abs[3], e_abs[1]))
161-
if enorm > Modia3D.neps
161+
if enorm > Modia3D.nepsMPR(T)
162162
return SVector(0.0, shapeLength, 0.0) + SVector(topRadius*e_abs[1], 0.0, topRadius*e_abs[3]) / enorm # point on top circle is support point
163163
else
164164
return SVector(0.0, shapeLength, 0.0) # top circle center is support point
165165
end
166166
end
167167
else
168168
enorm = norm(SVector(e_abs[3], e_abs[1]))
169-
if enorm > Modia3D.neps
169+
if enorm > Modia3D.nepsMPR(T)
170170
return SVector(baseRadius*e_abs[1], 0.0, baseRadius*e_abs[3]) / enorm # point on base circle is support point
171171
else
172172
return SVector{3,T}(0.0, 0.0, 0.0) # base circle center is support point
@@ -179,15 +179,15 @@ end
179179
return SVector(0.0, 0.0, shapeLength) # apex is support point
180180
else # frustum of a cone
181181
enorm = norm(SVector(e_abs[1], e_abs[2]))
182-
if enorm > Modia3D.neps
182+
if enorm > Modia3D.nepsMPR(T)
183183
return SVector(0.0, 0.0, shapeLength) + SVector(topRadius*e_abs[1], topRadius*e_abs[2], 0.0) / enorm # point on top circle is support point
184184
else
185185
return SVector(0.0, 0.0, shapeLength) # top circle center is support point
186186
end
187187
end
188188
else
189189
enorm = norm(SVector(e_abs[1], e_abs[2]))
190-
if enorm > Modia3D.neps
190+
if enorm > Modia3D.nepsMPR(T)
191191
return SVector(baseRadius*e_abs[1], baseRadius*e_abs[2], 0.0) / enorm # point on base circle is support point
192192
else
193193
return SVector{3,T}(0.0, 0.0, 0.0) # base circle center is support point
@@ -205,21 +205,21 @@ end
205205
halfThickness = T(0.5*shape.thickness)
206206
if shape.axis == 1
207207
enorm = norm(SVector(e_abs[1], e_abs[2]))
208-
if enorm <= Modia3D.neps
208+
if enorm <= Modia3D.nepsMPR(T)
209209
return SVector(Basics.sign_eps(e_abs[1])*halfLength, 0.0, Basics.sign_eps(e_abs[3])*halfThickness)
210210
else
211211
return SVector(Basics.sign_eps(e_abs[1])*halfLength, 0.0, Basics.sign_eps(e_abs[3])*halfThickness) + SVector(halfWidth*e_abs[1], halfWidth*e_abs[2], 0.0)/enorm
212212
end
213213
elseif shape.axis == 2
214214
enorm = norm(SVector(e_abs[2], e_abs[3]))
215-
if enorm <= Modia3D.neps
215+
if enorm <= Modia3D.nepsMPR(T)
216216
return SVector(Basics.sign_eps(e_abs[1])*halfThickness, Basics.sign_eps(e_abs[2])*halfLength, 0.0)
217217
else
218218
return SVector(Basics.sign_eps(e_abs[1])*halfThickness, Basics.sign_eps(e_abs[2])*halfLength, 0.0) + SVector(0.0, halfWidth*e_abs[2], halfWidth*e_abs[3])/enorm
219219
end
220220
else
221221
enorm = norm(SVector(e_abs[3], e_abs[1]))
222-
if enorm <= Modia3D.neps
222+
if enorm <= Modia3D.nepsMPR(T)
223223
return SVector(0.0, Basics.sign_eps(e_abs[2])*halfThickness, Basics.sign_eps(e_abs[3])*halfLength)
224224
else
225225
return SVector(0.0, Basics.sign_eps(e_abs[2])*halfThickness, Basics.sign_eps(e_abs[3])*halfLength) + SVector(halfWidth*e_abs[1], 0.0, halfWidth*e_abs[3])/enorm

src/contactDetection/ContactDetectionMPR/ContactDetectionMPR_handler.jl

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Base.:isequal(key1::DistanceKey, key2::DistanceKey) =
9494

9595

9696
"""
97-
handler = ContactDetectionMPR_handler(;tol_rel = 1e-4, niter_max=100, neps=sqrt(eps()))
97+
handler = ContactDetectionMPR_handler(;tol_rel = 1e-7, niter_max=100)
9898
9999
Generate a new contact handler for usage of the MPR algorithm
100100
The handler instance contains all information
@@ -105,8 +105,6 @@ about the contact situation.
105105
- `tol_rel`: Relative tolerance to compute the contact point (> 0.0)
106106
- `niter_max`: Maximum number of iterations of the MPR algorithm. If this number is reached,
107107
an error occurs (> 0).
108-
- `neps`: Small number used to check whether a floating number is close to zero (> 0.0).
109-
110108
"""
111109
mutable struct ContactDetectionMPR_handler{T} <: Modia3D.AbstractContactDetection
112110
distanceComputed::Bool
@@ -117,7 +115,6 @@ mutable struct ContactDetectionMPR_handler{T} <: Modia3D.AbstractContactDetectio
117115

118116
tol_rel::T
119117
niter_max::Int
120-
neps::T
121118

122119
contactPairs::Composition.ContactPairs
123120

@@ -127,12 +124,10 @@ mutable struct ContactDetectionMPR_handler{T} <: Modia3D.AbstractContactDetectio
127124
defaultContactSphereDiameter::Float64
128125

129126
function ContactDetectionMPR_handler{T}(;tol_rel = 1.0e-7,
130-
niter_max = 100 ,
131-
neps = sqrt(eps(T))) where {T}
127+
niter_max = 100) where {T}
132128
@assert(tol_rel > 0.0)
133129
@assert(niter_max > 0)
134-
@assert(neps > 0.0)
135-
new(false, Dict{PairID,ContactPair}(), Dict{PairID,ContactPair}(), 42.0, tol_rel, niter_max, neps)
130+
new(false, Dict{PairID,ContactPair}(), Dict{PairID,ContactPair}(), 42.0, tol_rel, niter_max)
136131
end
137132
end
138133
ContactDetectionMPR_handler() = ContactDetectionMPR_handler{Modia3D.MPRFloatType}()

src/contactDetection/ContactDetectionMPR/analyzeMPR.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ mutable struct Plane
2020
end
2121

2222

23-
function intersect3DSegmentPlane(seg::Segment, plane::Plane, neps)
23+
function intersect3DSegmentPlane(seg::Segment, plane::Plane)
2424
u = seg.P1 - seg.P0
2525
w = seg.P0 - plane.V0
2626

2727
dividend = -dot(plane.n, w)
2828
divisor = dot(plane.n, u)
29+
neps = Modia3D.nepsMPR(T)
2930

3031
# checks if segment and plane are parallel
3132
if abs(divisor) < neps # segment is parallel to plane
@@ -53,11 +54,11 @@ end
5354
pointInTriangle(p,a,b,c) = (sameSideTriangle(p,a,b,c) && sameSideTriangle(p,b,a,c) && sameSideTriangle(p,c,a,b))
5455

5556

56-
function doesRayIntersectPortal(r1,r2,r3,point,neps)
57+
function doesRayIntersectPortal(r1,r2,r3,point)
5758
plane = Plane(r1,r2,r3)
5859
segment = Segment(point, SVector(0.0, 0.0, 0.0))
5960

60-
(value, intersectionPoint) = intersect3DSegmentPlane(segment, plane, neps)
61+
(value, intersectionPoint) = intersect3DSegmentPlane(segment, plane)
6162
if value == 1
6263
if !pointInTriangle(intersectionPoint, r1, r2, r3)
6364
error("Ray = ", point ," does not intersect portal (r1,r2,r3) = ", r1, r2, r3)
@@ -68,10 +69,10 @@ function doesRayIntersectPortal(r1,r2,r3,point,neps)
6869
return true
6970
end
7071

71-
function analyzeFinalPortal(r1, r2, r3, r4, neps)
72+
function analyzeFinalPortal(r1, r2, r3, r4)
7273
plane = Plane(r1,r2,r3)
7374
segment = Segment(r4, SVector(0.0, 0.0, 0.0))
74-
(value, intersectionPoint) = intersect3DSegmentPlane(segment, plane, neps)
75+
(value, intersectionPoint) = intersect3DSegmentPlane(segment, plane)
7576
if value == 1
7677
if !pointInTriangle(intersectionPoint, r1, r2, r3)
7778
println("Ray r4 = ", r4 ," is not intersecting last portal (r1,r2,r3) = ", r1, r2, r3)

src/contactDetection/ContactDetectionMPR/mpr.jl

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,18 @@ end
6565

6666
# checks if centers of shapeA and shapeB are overlapping
6767
# belongs to construction of r0
68-
function checkCentersOfShapesOverlapp(r0::SupportPoint, neps::T, shapeA::Composition.Object3D, shapeB::Composition.Object3D) where {T}
69-
if norm(r0.p) <= neps
68+
function checkCentersOfShapesOverlapp(r0::SupportPoint{T}, shapeA::Composition.Object3D, shapeB::Composition.Object3D) where {T}
69+
if norm(r0.p) <= Modia3D.nepsMPR(T)
7070
error("MPR: Too large penetration (prerequisite of MPR violated). Centers are overlapping. Look at $(Modia3D.fullName(shapeA)) and $(Modia3D.fullName(shapeB)).")
7171
end
7272
end
7373

7474

75-
function checkIfShapesArePlanar(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,n2::SVector{3,T}, neps::T,
75+
function checkIfShapesArePlanar(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,n2::SVector{3,T},
7676
shapeA::Composition.Object3D,shapeB::Composition.Object3D) where {T}
7777
# r3 is in the direction of plane normal that contains triangle r0-r1-r2
7878
n3 = cross(r1.p-r0.p, r2.p-r0.p)
79+
neps = Modia3D.nepsMPR(T)
7980
# the triangle r0-r1-r2 has degenerated into a line segment
8081
if norm(n3) <= neps
8182
# change search direction for r2
@@ -120,12 +121,13 @@ end
120121
# Der Ursprung muss nicht enthalten sein!!!
121122
function tetrahedronEncloseOrigin(r0::SupportPoint, r1::SupportPoint,
122123
r2::SupportPoint, r3::SupportPoint,
123-
neps::T, niter_max::Int64,
124+
niter_max::Int64,
124125
shapeA::Composition.Object3D, shapeB::Composition.Object3D, scale::T) where {T}
125126
r1org = r1
126127
r2org = r2
127128
r3org = r3
128129
aux = SVector{3, T}(Modia3D.ZeroVector3D)
130+
neps = Modia3D.nepsMPR(T)
129131
success = false
130132
for i in 1:niter_max
131133
aux = cross(r1.p-r0.p,r3.p-r0.p)
@@ -146,7 +148,7 @@ function tetrahedronEncloseOrigin(r0::SupportPoint, r1::SupportPoint,
146148
if success != true
147149
if niter_max <= 100
148150
@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)
151+
tetrahedronEncloseOrigin(r0, r1org, r2org, r3org, niter_max + 10, shapeA, shapeB, scale)
150152
else
151153
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)).")
152154
end
@@ -158,8 +160,9 @@ end
158160
########### Phase 3, Minkowski Portal Refinement ###################
159161
# construction of r4
160162
function constructR4(r0::SupportPoint,r1::SupportPoint,r2::SupportPoint,r3::SupportPoint,
161-
neps::T, shapeA::Composition.Object3D,shapeB::Composition.Object3D, scale::T) where {T}
163+
shapeA::Composition.Object3D,shapeB::Composition.Object3D, scale::T) where {T}
162164
n4 = cross(r2.p-r1.p, r3.p-r1.p)
165+
neps = Modia3D.nepsMPR(T)
163166
if norm(n4) <= neps
164167
r3 = getSupportPoint(shapeA, shapeB, -r3.n, scale=scale) # change search direction
165168
if abs(dot((r3.p-r1.p),r3.n)) <= neps
@@ -219,7 +222,7 @@ end
219222

220223
function finalTC2(r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, r4::SupportPoint)
221224
#println("TC 2")
222-
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
225+
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p)
223226
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
224227
#end
225228
distance = -dot(r4.n, r4.p)
@@ -231,11 +234,11 @@ end
231234
function finalTC3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, r4::SupportPoint)
232235
#println("TC 3")
233236

234-
#doesRayIntersectPortal(r1.p,r2.p,r3.p, r4.p,neps)
237+
#doesRayIntersectPortal(r1.p,r2.p,r3.p, r4.p)
235238
#println("r1.p = ", r1.p , " r2.p = ", r2.p ," r3.p = ", r3.p)
236239
#println("r4.p = ", r4.p)
237240
#println(" ")
238-
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p, neps)
241+
#if !analyzeFinalPortal(r1.p, r2.p, r3.p, r4.p)
239242
# error("shapeA = ", shapeA, " shapeB = ", shapeB)
240243
#end
241244
(r4.p, distance) = signedDistanceToPortal(r0.p,r1.p,r2.p,r3.p)
@@ -244,7 +247,7 @@ function finalTC3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::Supp
244247
end
245248

246249

247-
function phase3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, neps::T, niter_max::Int64, tol_rel::T, shapeA::Composition.Object3D, shapeB::Composition.Object3D, scale::T) where {T}
250+
function phase3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::SupportPoint, niter_max::Int64, tol_rel::T, shapeA::Composition.Object3D, shapeB::Composition.Object3D, scale::T) where {T}
248251
r1org = r1
249252
r2org = r2
250253
r3org = r3
@@ -258,7 +261,7 @@ function phase3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::Suppor
258261
for i in 1:niter_max
259262
### Phase 3.1: construct r4 ###
260263
# Find support point using the tetrahedron face
261-
(r3,r4,n4) = constructR4(r0,r1,r2,r3,neps,shapeA,shapeB, scale)
264+
(r3,r4,n4) = constructR4(r0,r1,r2,r3,shapeA,shapeB, scale)
262265

263266

264267
### Phase 3.2: check if r4 is close to the origin ###
@@ -314,7 +317,7 @@ function phase3(r0::SupportPoint, r1::SupportPoint, r2::SupportPoint, r3::Suppor
314317
end
315318
if niter_max <= 100
316319
@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)
320+
phase3(r0, r1org, r2org, r3org, niter_max + 10, tol_rel, shapeA, shapeB, scale)
318321
else
319322
@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.")
320323
if isTC2
@@ -357,7 +360,7 @@ end
357360
function mprGeneral(ch::Composition.ContactDetectionMPR_handler{T}, shapeA::Composition.Object3D, shapeB::Modia3D.Composition.Object3D) where {T}
358361
tol_rel = ch.tol_rel
359362
niter_max = ch.niter_max
360-
neps = ch.neps
363+
neps = Modia3D.nepsMPR(T)
361364

362365
########### Phase 1, Minkowski Portal Refinement ###################
363366
# Construction of r0 and initial portal triangle points r1, r2, r3
@@ -369,7 +372,7 @@ function mprGeneral(ch::Composition.ContactDetectionMPR_handler{T}, shapeA::Comp
369372
centroidB = getCentroid(shapeB)
370373
r0 = SupportPoint{T}(centroidA-centroidB, -(centroidA-centroidB), SVector{3,T}(0.0,0.0,0.0), SVector{3,T}(0.0,0.0,0.0))
371374
# check if centers of shapes are overlapping
372-
checkCentersOfShapesOverlapp(r0, neps, shapeA, shapeB)
375+
checkCentersOfShapesOverlapp(r0, shapeA, shapeB)
373376

374377
### Phase 1.2: construction of initial r1 ###
375378
# r1 is the farthest point in the direction to the origin
@@ -397,26 +400,25 @@ function mprGeneral(ch::Composition.ContactDetectionMPR_handler{T}, shapeA::Comp
397400

398401
### Phase 1.4: construction of initial r3 ###
399402
# r3 is in the direction of plane normal that contains triangle r0-r1-r2
400-
(r2, r3, n2, n3) = checkIfShapesArePlanar(r0, r1, r2, n2, neps, shapeA, shapeB)
403+
(r2, r3, n2, n3) = checkIfShapesArePlanar(r0, r1, r2, n2, shapeA, shapeB)
401404

402405
(r0,r1,r2,r3,scale) = skalarization(r0,r1,r2,r3)
403406

404407

405408
########### Phase 2, Minkowski Portal Refinement ###################
406409
# loop around to "ensure" the tetrahedron r0,r1,r2 and r3 encloses the origin
407-
(r1,r2,r3) = tetrahedronEncloseOrigin(r0,r1,r2,r3,neps,niter_max,shapeA,shapeB, scale)
408-
# doesRayIntersectPortal(r1.p,r2.p,r3.p, r0.p,neps) # Portal.A, Portal.B, Portal.C, point, neps
409-
410+
(r1,r2,r3) = tetrahedronEncloseOrigin(r0,r1,r2,r3,niter_max,shapeA,shapeB, scale)
411+
# doesRayIntersectPortal(r1.p,r2.p,r3.p, r0.p) # Portal.A, Portal.B, Portal.C, point,
410412

411413
########### Phase 3, Minkowski Portal Refinement ###################
412-
(distance, r1, r2, r3, r4) = phase3(r0, r1, r2, r3, neps, niter_max, tol_rel, shapeA, shapeB, scale)
414+
(distance, r1, r2, r3, r4) = phase3(r0, r1, r2, r3, niter_max, tol_rel, shapeA, shapeB, scale)
413415
return (Float64(distance), SVector{3,Float64}(r4.a), SVector{3,Float64}(r4.b), SVector{3,Float64}(r4.n), true, SVector{3,Float64}(r1.a), SVector{3,Float64}(r1.b), SVector{3,Float64}(r2.a), SVector{3,Float64}(r2.b), SVector{3,Float64}(r3.a), SVector{3,Float64}(r3.b) )
414416
end
415417

416418

417419
function mprTwoSpheres(ch::Composition.ContactDetectionMPR_handler{T}, shapeA::Composition.Object3D, shapeB::Modia3D.Composition.Object3D,
418420
sphereA::Shapes.Sphere, sphereB::Shapes.Sphere) where {T}
419-
neps = ch.neps
421+
neps = Modia3D.nepsMPR(T)
420422
radiusA = T(sphereA.diameter*0.5)
421423
radiusB = T(sphereB.diameter*0.5)
422424
centroidSphereA = getCentroid(shapeA)

0 commit comments

Comments
 (0)