1+ import math
2+ import numpy as np
3+
4+ import distance .PointEdgeDistance as PE
5+ import distance .CCD as CCD
6+
7+ import utils
8+
9+ dhat = 0.01
10+ kappa = 1e5
11+
12+ def val (x , n , o , bp , be , contact_area ):
13+ sum = 0.0
14+ # floor:
15+ for i in range (0 , len (x )):
16+ d = n .dot (x [i ] - o )
17+ if d < dhat :
18+ s = d / dhat
19+ sum += contact_area [i ] * dhat * kappa / 2 * (s - 1 ) * math .log (s )
20+ # ceil:
21+ n = np .array ([0.0 , - 1.0 ])
22+ for i in range (0 , len (x ) - 1 ):
23+ d = n .dot (x [i ] - x [- 1 ])
24+ if d < dhat :
25+ s = d / dhat
26+ sum += contact_area [i ] * dhat * kappa / 2 * (s - 1 ) * math .log (s )
27+ # self-contact
28+ dhat_sqr = dhat * dhat
29+ for xI in bp :
30+ for eI in be :
31+ if xI != eI [0 ] and xI != eI [1 ]: # do not consider a point and its incident edge
32+ d_sqr = PE .val (x [xI ], x [eI [0 ]], x [eI [1 ]])
33+ if d_sqr < dhat_sqr :
34+ s = d_sqr / dhat_sqr
35+ # since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
36+ sum += contact_area [xI ] * dhat * kappa / 8 * (s - 1 ) * math .log (s )
37+ return sum
38+
39+ def grad (x , n , o , bp , be , contact_area ):
40+ g = np .array ([[0.0 , 0.0 ]] * len (x ))
41+ # floor:
42+ for i in range (0 , len (x )):
43+ d = n .dot (x [i ] - o )
44+ if d < dhat :
45+ s = d / dhat
46+ g [i ] = contact_area [i ] * dhat * (kappa / 2 * (math .log (s ) / dhat + (s - 1 ) / d )) * n
47+ # ceil:
48+ n = np .array ([0.0 , - 1.0 ])
49+ for i in range (0 , len (x ) - 1 ):
50+ d = n .dot (x [i ] - x [- 1 ])
51+ if d < dhat :
52+ s = d / dhat
53+ local_grad = contact_area [i ] * dhat * (kappa / 2 * (math .log (s ) / dhat + (s - 1 ) / d )) * n
54+ g [i ] += local_grad
55+ g [- 1 ] -= local_grad
56+ # self-contact
57+ dhat_sqr = dhat * dhat
58+ for xI in bp :
59+ for eI in be :
60+ if xI != eI [0 ] and xI != eI [1 ]: # do not consider a point and its incident edge
61+ d_sqr = PE .val (x [xI ], x [eI [0 ]], x [eI [1 ]])
62+ if d_sqr < dhat_sqr :
63+ s = d_sqr / dhat_sqr
64+ # since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
65+ local_grad = contact_area [xI ] * dhat * (kappa / 8 * (math .log (s ) / dhat_sqr + (s - 1 ) / d_sqr )) * PE .grad (x [xI ], x [eI [0 ]], x [eI [1 ]])
66+ g [xI ] += local_grad [0 :2 ]
67+ g [eI [0 ]] += local_grad [2 :4 ]
68+ g [eI [1 ]] += local_grad [4 :6 ]
69+ return g
70+
71+ def hess (x , n , o , bp , be , contact_area ):
72+ IJV = [[0 ] * 0 , [0 ] * 0 , np .array ([0.0 ] * 0 )]
73+ # floor:
74+ for i in range (0 , len (x )):
75+ d = n .dot (x [i ] - o )
76+ if d < dhat :
77+ local_hess = contact_area [i ] * dhat * kappa / (2 * d * d * dhat ) * (d + dhat ) * np .outer (n , n )
78+ for c in range (0 , 2 ):
79+ for r in range (0 , 2 ):
80+ IJV [0 ].append (i * 2 + r )
81+ IJV [1 ].append (i * 2 + c )
82+ IJV [2 ] = np .append (IJV [2 ], local_hess [r , c ])
83+ # ceil:
84+ n = np .array ([0.0 , - 1.0 ])
85+ for i in range (0 , len (x ) - 1 ):
86+ d = n .dot (x [i ] - x [- 1 ])
87+ if d < dhat :
88+ local_hess = contact_area [i ] * dhat * kappa / (2 * d * d * dhat ) * (d + dhat ) * np .outer (n , n )
89+ index = [i , len (x ) - 1 ]
90+ for nI in range (0 , 2 ):
91+ for nJ in range (0 , 2 ):
92+ for c in range (0 , 2 ):
93+ for r in range (0 , 2 ):
94+ IJV [0 ].append (index [nI ] * 2 + r )
95+ IJV [1 ].append (index [nJ ] * 2 + c )
96+ IJV [2 ] = np .append (IJV [2 ], ((- 1 ) ** (nI != nJ )) * local_hess [r , c ])
97+ # self-contact
98+ dhat_sqr = dhat * dhat
99+ for xI in bp :
100+ for eI in be :
101+ if xI != eI [0 ] and xI != eI [1 ]: # do not consider a point and its incident edge
102+ d_sqr = PE .val (x [xI ], x [eI [0 ]], x [eI [1 ]])
103+ if d_sqr < dhat_sqr :
104+ d_sqr_grad = PE .grad (x [xI ], x [eI [0 ]], x [eI [1 ]])
105+ s = d_sqr / dhat_sqr
106+ # since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
107+ local_hess = contact_area [xI ] * dhat * utils .make_PD (kappa / (8 * d_sqr * d_sqr * dhat_sqr ) * (d_sqr + dhat_sqr ) * np .outer (d_sqr_grad , d_sqr_grad ) \
108+ + (kappa / 8 * (math .log (s ) / dhat_sqr + (s - 1 ) / d_sqr )) * PE .hess (x [xI ], x [eI [0 ]], x [eI [1 ]]))
109+ index = [xI , eI [0 ], eI [1 ]]
110+ for nI in range (0 , 3 ):
111+ for nJ in range (0 , 3 ):
112+ for c in range (0 , 2 ):
113+ for r in range (0 , 2 ):
114+ IJV [0 ].append (index [nI ] * 2 + r )
115+ IJV [1 ].append (index [nJ ] * 2 + c )
116+ IJV [2 ] = np .append (IJV [2 ], local_hess [nI * 2 + r , nJ * 2 + c ])
117+ return IJV
118+
119+ def init_step_size (x , n , o , bp , be , p ):
120+ alpha = 1
121+ # floor:
122+ for i in range (0 , len (x )):
123+ p_n = p [i ].dot (n )
124+ if p_n < 0 :
125+ alpha = min (alpha , 0.9 * n .dot (x [i ] - o ) / - p_n )
126+ # ceil:
127+ n = np .array ([0.0 , - 1.0 ])
128+ for i in range (0 , len (x ) - 1 ):
129+ p_n = (p [i ] - p [- 1 ]).dot (n )
130+ if p_n < 0 :
131+ alpha = min (alpha , 0.9 * n .dot (x [i ] - x [- 1 ]) / - p_n )
132+ # self-contact
133+ for xI in bp :
134+ for eI in be :
135+ if xI != eI [0 ] and xI != eI [1 ]: # do not consider a point and its incident edge
136+ if CCD .bbox_overlap (x [xI ], x [eI [0 ]], x [eI [1 ]], p [xI ], p [eI [0 ]], p [eI [1 ]], alpha ):
137+ toc = CCD .narrow_phase_CCD (x [xI ], x [eI [0 ]], x [eI [1 ]], p [xI ], p [eI [0 ]], p [eI [1 ]], alpha )
138+ if alpha > toc :
139+ alpha = toc
140+ return alpha
141+
142+ def compute_mu_lambda (x , n , o , bp , be , contact_area , mu ):
143+ # floor:
144+ mu_lambda = np .array ([0.0 ] * len (x ))
145+ for i in range (0 , len (x )):
146+ d = n .dot (x [i ] - o )
147+ if d < dhat :
148+ s = d / dhat
149+ mu_lambda [i ] = mu * - contact_area [i ] * dhat * (kappa / 2 * (math .log (s ) / dhat + (s - 1 ) / d ))
150+ # self-contact
151+ mu_lambda_self = []
152+ dhat_sqr = dhat * dhat
153+ for xI in bp :
154+ for eI in be :
155+ if xI != eI [0 ] and xI != eI [1 ]: # do not consider a point and its incident edge
156+ d_sqr = PE .val (x [xI ], x [eI [0 ]], x [eI [1 ]])
157+ if d_sqr < dhat_sqr :
158+ s = d_sqr / dhat_sqr
159+ # since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity
160+ # also, lambda = -\partial b / \partial d = -(\partial b / \partial d^2) * (\partial d^2 / \partial d)
161+ mu_lam = mu * - contact_area [xI ] * dhat * (kappa / 8 * (math .log (s ) / dhat_sqr + (s - 1 ) / d_sqr )) * 2 * math .sqrt (d_sqr )
162+ [n , r ] = PE .tangent (x [xI ], x [eI [0 ]], x [eI [1 ]]) # normal and closest point parameterization on the edge
163+ mu_lambda_self .append ([xI , eI [0 ], eI [1 ], mu_lam , n , r ])
164+ return [mu_lambda , mu_lambda_self ]
0 commit comments