1
2 package org.catacomb.numeric.mesh;
3
4 import java.util.ArrayList;
5
6
7 public abstract class Discretizer {
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 public static MeshPoint[] discretize(MeshPoint[] pt,
29 double disqrtr, int maxnpt) {
30
31 int np = pt.length;
32 double[][][] subdiv = new double[np][6][];
33 for (int i = 0; i < np; i++) {
34 pt[i].setWork(i);
35 }
36
37 int nnp = 0;
38 for (int i = 0; i < np; i++) {
39 MeshPoint cpa = pt[i];
40
41 int nnbr = cpa.getNeighborCount();
42 MeshPoint[] anbrs = cpa.getNeighbors();
43
44 for (int j = 0; j < nnbr; j++) {
45 MeshPoint cpb = anbrs[j];
46
47 if (cpa.getWork() < cpb.getWork()) {
48 subdiv[i][j] = getSubdivision(cpa, cpb, disqrtr);
49 nnp += subdiv[i][j].length;
50 }
51 }
52 }
53
54 if (np + nnp > maxnpt) {
55 Sp("WARNING - not discretizing: needs too many points ("+np+nnp+")");
56 return null;
57 }
58
59 MeshPoint[] pr = new MeshPoint[np+nnp];
60 for (int i = 0; i < np; i++) {
61 pr[i] = pt[i];
62 }
63 int nxp = np;
64
65 for (int i = 0; i < np; i++) {
66 MeshPoint cpa = pt[i];
67
68 int nnbr = cpa.getNeighborCount();
69 MeshPoint[] anbrs = cpa.getNeighbors();
70
71 for (int j = 0; j < nnbr; j++) {
72 double[] div = subdiv[i][j];
73 if (div != null && div.length > 0) {
74
75 MeshPoint cpb = anbrs[j];
76 MeshPoint clast = null;
77
78 for (int id = 0; id < div.length; id++) {
79
80 MeshPoint cp = cpa.newPoint();
81
82 locateBetween(cpa, cpb, div[id], cp);
83 pr[nxp++] = cp;
84 if (id == 0) {
85 cpa.replaceNeighbor(cpb, cp);
86 cp.addNeighbor(cpa);
87 }
88 if (id == div.length-1) {
89 cpb.replaceNeighbor(cpa, cp);
90 cp.addNeighbor(cpb);
91 }
92 if (clast != null) {
93 cp.addNeighbor(clast);
94 clast.addNeighbor(cp);
95 }
96 clast = cp;
97 }
98 }
99 }
100 }
101 return pr;
102 }
103
104
105
106 public static void locateBetween(MeshPoint cpa, MeshPoint cpb, double f,
107 MeshPoint cpn) {
108 double wf = 1. - f;
109 cpn.setX(f * cpb.getX() + wf * cpa.getX());
110 cpn.setY(f * cpb.getY() + wf * cpa.getY());
111 cpn.setZ(f * cpb.getZ() + wf * cpa.getZ());
112 cpn.setR(f * cpb.getR() + wf * cpa.getR());
113
114 }
115
116
117
118 public static double distanceBetween(MeshPoint cp, MeshPoint cq) {
119 double dx = cp.getX() - cq.getX();
120 double dy = cp.getY() - cq.getY();
121 double dz = cp.getZ() - cq.getZ();
122 double d = Math.sqrt(dx*dx + dy*dy + dz*dz);
123 return d;
124 }
125
126
127
128 public static void movePerp(MeshPoint ca, MeshPoint cb, double dperp,
129 MeshPoint cm) {
130 double dx = cb.getX() - ca.getX();
131 double dy = cb.getY() - ca.getY();
132 double f = Math.sqrt(dx*dx + dy*dy);
133 dx /= f;
134 dy /= f;
135 double x = cm.getX();
136 double y = cm.getY();
137 x += dperp * dy;
138 y -= dperp * dx;
139
140 cm.setX(x);
141 cm.setY(y);
142 }
143
144
145
146 public static MeshPoint[] merge(MeshPoint[] pt,
147 double maxdr, double maxlen,
148 double tol) {
149
150
151 for (int i = 0; i < pt.length; i++) {
152 pt[i].setWork(2);
153 }
154
155
156 MeshPoint p0 = pt[0];
157 recMerge(p0, maxdr, maxlen, tol);
158
159
160 int nl = 0;
161 for (int i = 0; i < pt.length; i++) {
162 if (pt[i].getWork() > 0) {
163 nl++;
164 }
165 }
166 MeshPoint[] pr = p0.newPointArray(nl);
167 nl = 0;
168 for (int i = 0; i < pt.length; i++) {
169 if (pt[i].getWork() > 0) {
170 pr[nl++] = pt[i];
171 }
172 }
173 return pr;
174 }
175
176
177
178 public static void recMerge(MeshPoint cp, double maxdr, double maxlen,
179 double tol) {
180
181 cp.setWork(1);
182
183 int nnbr = cp.getNeighborCount();
184 MeshPoint[] anbrs = cp.getNeighbors();
185
186 for (int j = 0; j < nnbr; j++) {
187 MeshPoint cq = anbrs[j];
188
189 double rp = cp.getR();
190 double rq = cq.getR();
191
192
193 if (cq.getWork() == 2 &&
194 cq.getNeighborCount() == 2 &&
195 Math.abs((rq - rp) / (rq + rp)) < 0.5 * maxdr &&
196 distanceBetween(cp, cq) < maxlen) {
197
198
199
200
201 MeshPoint cprev = cp;
202 ArrayList<MeshPoint> vpt = new ArrayList<MeshPoint>();
203 double ltot = 0.;
204 double ldtot = 0.;
205
206
207 while (cq.getNeighborCount() == 2 &&
208 distanceBetween(cprev, cq) < maxlen &&
209 Math.abs((rq-rp)/(rq+rp)) < 0.5 * maxdr) {
210 vpt.add(cq);
211 double dl = distanceBetween(cprev, cq);
212 ltot += dl;
213 ldtot += dl * (cprev.getR() + cq.getR());
214
215 MeshPoint cnxt;
216 MeshPoint[] acqn = cq.getNeighbors();
217 if (acqn[0] == cprev) {
218 cnxt = acqn[1];
219 } else {
220 cnxt = acqn[0];
221 }
222
223 cprev = cq;
224 cq = cnxt;
225 rq = cq.getR();
226 }
227
228 double dl = distanceBetween(cprev, cq);
229 ltot += dl;
230 ldtot += dl * (cprev.getR() + cq.getR());
231
232
233 double lab = distanceBetween(cp, cq);
234 double ldab = lab * (cp.getR() + cq.getR());
235
236 int nadd = (int)(ltot / maxlen);
237
238 if (nadd > vpt.size()) {
239 nadd = vpt.size();
240 }
241
242
243 boolean cor = (Math.abs((lab-ltot)/(lab+ltot)) > 0.5 * tol ||
244 Math.abs((ldab-ldtot)/(ldab+ldtot)) > 0.5 * tol);
245 if (cor && nadd == 0) {
246 nadd = 1;
247 }
248
249 if (nadd == 0) {
250 cp.replaceNeighbor(vpt.get(0), cq);
251 cq.replaceNeighbor(vpt.get(vpt.size()-1), cp);
252
253 } else {
254
255 for (int i = 0; i < nadd; i++) {
256 MeshPoint cm = vpt.get(i);
257 cm.setWork(1);
258 locateBetween(cp, cq, (1.+ i)/(1.+ nadd), cm);
259 if (i == nadd-1 && nadd < vpt.size()) {
260 cm.replaceNeighbor(vpt.get(nadd), cq);
261 cq.replaceNeighbor(vpt.get(vpt.size()-1), cm);
262 }
263 }
264 }
265
266
267
268 for (int jd = nadd; jd < vpt.size(); jd++) {
269 MeshPoint cd = vpt.get(jd);
270 cd.disconnect();
271 cd.setWork(0);
272 }
273
274
275 if (cor) {
276 double dpar = lab / (nadd+1);
277 double fl = ltot / lab;
278 double dperp = Math.sqrt((fl*fl - 1) * dpar*dpar);
279 double fr = ldtot / (fl * ldab);
280 for (int i = 0; i < nadd; i++) {
281 MeshPoint cm = vpt.get(i);
282
283 double cmr = cm.getR();
284 cm.setR(cmr * fr);
285
286 if (i % 2 == 0) {
287 movePerp(cp, cq, ((i/2) % 2 == 0 ? dperp : - dperp), cm);
288 }
289 }
290
291 }
292
293
294
295
296 }
297 if (cq.getWork() == 2) {
298 recMerge(cq, maxdr, maxlen, tol);
299 }
300 }
301 }
302
303
304
305
306
307 public static double[] getSubdivision(MeshPoint cpa, MeshPoint cpb,
308 double disqrtr) {
309 double dab = distanceBetween(cpa, cpb);
310 double ra = cpa.getR();
311 double rb = cpb.getR();
312
313
314
315 double fdist = 0.0;
316
317 if (rb != ra) {
318 fdist = ((2./3.) * dab / (rb - ra) *
319 (Math.pow(rb, 3./2.) - Math.pow(ra, 3./2.)));
320
321
322 } else {
323 fdist = dab * Math.sqrt(ra);
324
325 }
326
327
328 int nadd = (int)(fdist / disqrtr);
329
330 double[] dpos = new double[nadd];
331
332 if (nadd > 0) {
333
334 if (Math.abs((ra-rb)/(ra+rb)) < 0.01) {
335 for (int i = 0; i < nadd; i++) dpos[i] = (1.+i) / (nadd+1.);
336
337 } else {
338
339 double delf = fdist / (nadd+1);
340 double ffa = (rb - ra) / dab;
341 double xa = ra / ffa;
342 double xb = rb / ffa;
343
344
345 double x = xa;
346
347
348
349
350
351 for (int i = 0; i < nadd+1; i++) {
352 double ttt = (delf * ffa * 3./2. +
353 Math.pow(ffa * x, 3./2.));
354 double dx = Math.pow(ttt, (2./3.)) / ffa - x;
355 x += dx;
356 if (i < nadd) {
357 dpos[i] = (x - xa) / dab;
358 }
359 }
360 if (Math.abs(xb - x) > 1.e-5) {
361 Sp("ERROR : ECNet segment division " + xa + " " + xb +
362 " " + x + " " + nadd + " " +dab + " " +ra+ " " + rb);
363 }
364 }
365 }
366 return dpos;
367 }
368
369
370 public static void Sp(String s) {
371 System.out.println(s);
372 }
373
374
375 }
376
377
378