41
41
mat43 = wp .types .matrix (shape = (4 , 3 ), dtype = float )
42
42
mat63 = wp .types .matrix (shape = (6 , 3 ), dtype = float )
43
43
44
- MULTI_CONTACT_COUNT = 4
44
+ MULTI_CONTACT_COUNT = 8
45
45
mat3c = wp .types .matrix (shape = (MULTI_CONTACT_COUNT , 3 ), dtype = float )
46
46
47
47
@@ -93,6 +93,13 @@ class SupportPoint:
93
93
vertex_index : int
94
94
95
95
96
+ @wp .func
97
+ def discrete_geoms (g1 : int , g2 : int ):
98
+ return (g1 == int (GeomType .MESH .value ) or g1 == int (GeomType .BOX .value ) or g1 == int (GeomType .HFIELD .value )) and (
99
+ g2 == int (GeomType .MESH .value ) or g2 == int (GeomType .BOX .value ) or g2 == int (GeomType .HFIELD .value )
100
+ )
101
+
102
+
96
103
@wp .func
97
104
def _support_margin (geom : Geom , geomtype : int , dir : wp .vec3 ):
98
105
sp = SupportPoint ()
@@ -590,6 +597,7 @@ def _gjk(
590
597
use_margin : bool ,
591
598
):
592
599
"""Find distance within a tolerance between two geoms."""
600
+ is_discrete = discrete_geoms (geomtype1 , geomtype2 )
593
601
cutoff2 = cutoff * cutoff
594
602
simplex = mat43 ()
595
603
simplex1 = mat43 ()
@@ -598,7 +606,7 @@ def _gjk(
598
606
simplex_index2 = wp .vec4i ()
599
607
n = int (0 )
600
608
coordinates = wp .vec4 () # barycentric coordinates
601
- epsilon = 0. 5 * tolerance * tolerance
609
+ epsilon = wp . where ( is_discrete , 0.0 , 0. 5 * tolerance * tolerance )
602
610
603
611
# set initial guess
604
612
x_k = x1_0 - x2_0
@@ -1193,12 +1201,14 @@ def _polytope4(
1193
1201
1194
1202
1195
1203
@wp .func
1196
- def _epa (tolerance2 : float , epa_iterations : int , pt : Polytope , geom1 : Geom , geom2 : Geom , geomtype1 : int , geomtype2 : int ):
1204
+ def _epa (tolerance : float , epa_iterations : int , pt : Polytope , geom1 : Geom , geom2 : Geom , geomtype1 : int , geomtype2 : int ):
1197
1205
"""Recover penetration data from two geoms in contact given an initial polytope."""
1206
+ is_discrete = discrete_geoms (geomtype1 , geomtype2 )
1198
1207
upper = FLOAT_MAX
1199
1208
upper2 = FLOAT_MAX
1200
1209
idx = int (- 1 )
1201
1210
pidx = int (- 1 )
1211
+ epsilon = wp .where (is_discrete , 1e-15 , tolerance * tolerance )
1202
1212
1203
1213
for k in range (epa_iterations ):
1204
1214
pidx = int (idx )
@@ -1235,9 +1245,19 @@ def _epa(tolerance2: float, epa_iterations: int, pt: Polytope, geom1: Geom, geom
1235
1245
upper = upper_k
1236
1246
upper2 = upper * upper
1237
1247
1238
- if upper - lower < tolerance2 :
1248
+ if upper - lower < epsilon :
1239
1249
break
1240
1250
1251
+ # check if vertex wi is a repeated support point
1252
+ if is_discrete :
1253
+ found_repeated = bool (False )
1254
+ for i in range (pt .nvert - 1 ):
1255
+ if pt .vert_index1 [i ] == pt .vert_index1 [wi ] and pt .vert_index2 [i ] == pt .vert_index2 [wi ]:
1256
+ found_repeated = True
1257
+ break
1258
+ if found_repeated :
1259
+ break
1260
+
1241
1261
pt .nmap = _delete_face (pt , idx )
1242
1262
pt .nhorizon = _add_edge (pt , pt .face [idx ][0 ], pt .face [idx ][1 ])
1243
1263
pt .nhorizon = _add_edge (pt , pt .face [idx ][1 ], pt .face [idx ][2 ])
@@ -1251,7 +1271,7 @@ def _epa(tolerance2: float, epa_iterations: int, pt: Polytope, geom1: Geom, geom
1251
1271
if pt .face_index [i ] == - 2 :
1252
1272
continue
1253
1273
1254
- if wp .dot (pt .face_pr [i ], pt .vert [wi ]) - pt .face_norm2 [i ] > MJ_MINVAL :
1274
+ if wp .dot (pt .face_pr [i ], pt .vert [wi ]) - pt .face_norm2 [i ] > 1e-10 :
1255
1275
pt .nmap = _delete_face (pt , i )
1256
1276
pt .nhorizon = _add_edge (pt , pt .face [i ][0 ], pt .face [i ][1 ])
1257
1277
pt .nhorizon = _add_edge (pt , pt .face [i ][1 ], pt .face [i ][2 ])
@@ -1694,7 +1714,7 @@ def plane_normal(v1: wp.vec3, v2: wp.vec3, n: wp.vec3):
1694
1714
1695
1715
@wp .func
1696
1716
def halfspace (a : wp .vec3 , n : wp .vec3 , p : wp .vec3 ):
1697
- return wp .dot (p - a , n ) > - MJ_MINVAL
1717
+ return wp .dot (p - a , n ) > - 1e-10
1698
1718
1699
1719
1700
1720
@wp .func
@@ -1725,7 +1745,7 @@ def polygon_clip(face1: polyverts, nface1: int, face2: polyverts, nface2: int, n
1725
1745
# compute plane normal and distance to plane for each vertex
1726
1746
pn = polyverts ()
1727
1747
pd = polyvec ()
1728
- for i in range (nface1 ):
1748
+ for i in range (nface1 - 1 ):
1729
1749
pdi , pni = plane_normal (face1 [i ], face1 [i + 1 ], n )
1730
1750
pd [i ] = pdi
1731
1751
pn [i ] = pni
@@ -1734,14 +1754,11 @@ def polygon_clip(face1: polyverts, nface1: int, face2: polyverts, nface2: int, n
1734
1754
pn [nface1 - 1 ] = pni
1735
1755
1736
1756
# reserve 2 * max_sides as max sides for a clipped polygon
1737
- polygon1 = polyclip ()
1738
- polygon2 = polyclip ()
1757
+ polygon = polyclip ()
1758
+ clipped = polyclip ()
1739
1759
npolygon = nface2
1740
1760
nclipped = int (0 )
1741
1761
1742
- polygon = polygon1
1743
- clipped = polygon2
1744
-
1745
1762
for i in range (nface2 ):
1746
1763
polygon [i ] = face2 [i ]
1747
1764
@@ -1768,7 +1785,7 @@ def polygon_clip(face1: polyverts, nface1: int, face2: polyverts, nface2: int, n
1768
1785
1769
1786
# add new vertex to clipped polygon where PQ intersects the clipping edge
1770
1787
t , res = plane_intersect (pn [e ], pd [e ], P , Q )
1771
- if t < 0.0 or t > 1.0 :
1788
+ if t >= 0.0 and t <= 1.0 :
1772
1789
clipped [nclipped ] = res
1773
1790
nclipped += 1
1774
1791
@@ -1790,8 +1807,8 @@ def polygon_clip(face1: polyverts, nface1: int, face2: polyverts, nface2: int, n
1790
1807
# no pruning needed
1791
1808
for i in range (npolygon ):
1792
1809
witness2 [i ] = polygon [i ]
1793
- witness1 [i ] = witness2 [i ] + dir
1794
- return npolygon , witness2 , witness1
1810
+ witness1 [i ] = witness2 [i ] - dir
1811
+ return npolygon , witness1 , witness2
1795
1812
1796
1813
1797
1814
# recover multiple contacts from EPA polytope
@@ -2125,11 +2142,14 @@ def ccd(
2125
2142
witness2 [0 ] = result .x2
2126
2143
return result .dist , 1 , witness1 , witness2
2127
2144
2128
- dist , x1 , x2 , idx = _epa (tolerance * tolerance , epa_iterations , pt , geom1 , geom2 , geomtype1 , geomtype2 )
2145
+ dist , x1 , x2 , idx = _epa (tolerance , epa_iterations , pt , geom1 , geom2 , geomtype1 , geomtype2 )
2146
+ if idx == - 1 :
2147
+ return FLOAT_MAX , 0 , witness1 , witness2
2148
+
2129
2149
if (
2130
2150
multiccd
2131
- and (geomtype1 == int (GeomType .BOX .value ) or geomtype1 == int (GeomType .MESH .value ))
2132
- and (geomtype2 == int (GeomType .BOX .value ) or geomtype2 == int (GeomType .MESH .value ))
2151
+ and (geomtype1 == int (GeomType .BOX .value ) or ( geomtype1 == int (GeomType .MESH .value ) and geom1 . mesh_polyadr > - 1 ))
2152
+ and (geomtype2 == int (GeomType .BOX .value ) or ( geomtype2 == int (GeomType .MESH .value ) and geom2 . mesh_polyadr > - 1 ))
2133
2153
):
2134
2154
num , w1 , w2 = multicontact (pt , pt .face [idx ], x1 , x2 , geom1 , geom2 , geomtype1 , geomtype2 )
2135
2155
if num > 0 :
0 commit comments