PageRenderTime 52ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 1ms

/deps/hemesh2010/src/wblut/hemesh/core/HE_Mesh.java

https://bitbucket.org/filtercake/bodyextensions
Java | 4265 lines | 3100 code | 319 blank | 846 comment | 640 complexity | 13eb13e1bb95916b982e725eaa14315f MD5 | raw file
  1. /*
  2. * Copyright (c) 2010, Frederik Vanhoutte This library is free software; you can
  3. * redistribute it and/or modify it under the terms of the GNU Lesser General
  4. * Public License as published by the Free Software Foundation; either version
  5. * 2.1 of the License, or (at your option) any later version.
  6. * http://creativecommons.org/licenses/LGPL/2.1/ This library is distributed in
  7. * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
  8. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  9. * the GNU Lesser General Public License for more details. You should have
  10. * received a copy of the GNU Lesser General Public License along with this
  11. * library; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
  12. * Fifth Floor, Boston, MA 02110-1301 USA
  13. */
  14. package wblut.hemesh.core;
  15. import java.util.ArrayList;
  16. import java.util.Arrays;
  17. import java.util.HashMap;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import javolution.util.FastList;
  21. import javolution.util.FastMap;
  22. import javolution.util.FastTable;
  23. import wblut.frame.WB_Frame;
  24. import wblut.geom.WB_AABB;
  25. import wblut.geom.WB_ClassifyPointToPlane;
  26. import wblut.geom.WB_ClosestPoint;
  27. import wblut.geom.WB_Distance;
  28. import wblut.geom.WB_ExplicitPolygon;
  29. import wblut.geom.WB_ExplicitSegment;
  30. import wblut.geom.WB_IndexedSegment;
  31. import wblut.geom.WB_IndexedTriangle;
  32. import wblut.geom.WB_Intersection;
  33. import wblut.geom.WB_IntersectionResult;
  34. import wblut.geom.WB_Normal;
  35. import wblut.geom.WB_Plane;
  36. import wblut.geom.WB_Point;
  37. import wblut.geom.WB_Ray;
  38. import wblut.geom.WB_Transform;
  39. import wblut.geom.WB_Vector;
  40. import wblut.geom.WB_XYZ;
  41. import wblut.geom2D.WB_IndexedTriangle2D;
  42. import wblut.geom2D.WB_PolygonType2D;
  43. import wblut.hemesh.creators.HEC_Creator;
  44. import wblut.hemesh.modifiers.HEM_Modifier;
  45. import wblut.hemesh.options.HE_CycleOption;
  46. import wblut.hemesh.subdividors.HES_Subdividor;
  47. import wblut.math.WB_Epsilon;
  48. import wblut.tree.WB_KDNeighbor;
  49. import wblut.tree.WB_KDTree;
  50. /**
  51. * Half-edge mesh data structure.
  52. *
  53. * @author Frederik Vanhoutte (W:Blut)
  54. *
  55. */
  56. public class HE_Mesh extends HE_MeshStructure {
  57. /** Stored mesh center. */
  58. private WB_Point _center;
  59. /** Status of mesh center. */
  60. private boolean _centerUpdated;
  61. /** General purpose label. */
  62. protected int label;
  63. /**
  64. * Instantiates a new HE_Mesh.
  65. *
  66. */
  67. public HE_Mesh() {
  68. super();
  69. _center = new WB_Point();
  70. _centerUpdated = false;
  71. label = -1;
  72. }
  73. public void setLabel(final int lab) {
  74. label = lab;
  75. }
  76. public int getLabel() {
  77. return label;
  78. }
  79. // CREATE
  80. /**
  81. * Constructor.
  82. *
  83. * @param creator
  84. * HE_Creator that generates this mesh
  85. */
  86. public HE_Mesh(final HEC_Creator creator) {
  87. super();
  88. setNoCopy(creator.create());
  89. _centerUpdated = false;
  90. label = -1;
  91. }
  92. // MODIFY
  93. /**
  94. * Modify the mesh.
  95. *
  96. * @param modifier
  97. * HE_Modifier to apply
  98. * @return self
  99. */
  100. public HE_Mesh modify(final HEM_Modifier modifier) {
  101. return modifier.apply(this);
  102. }
  103. /**
  104. * Modify selection. Elements should be part of this mesh.
  105. *
  106. * @param modifier
  107. * HE_Modifier to apply
  108. * @return self
  109. */
  110. public HE_Mesh modifySelected(final HEM_Modifier modifier,
  111. final HE_Selection selection) {
  112. return modifier.apply(selection.get());
  113. }
  114. // SUBDIVIDE
  115. /**
  116. * Subdivide the mesh.
  117. *
  118. * @param subdividor
  119. * HE_Subdividor to apply
  120. * @return self
  121. */
  122. public HE_Mesh subdivide(final HES_Subdividor subdividor) {
  123. return subdividor.apply(this);
  124. }
  125. /**
  126. * Subdivide selection of the mesh.
  127. *
  128. * @param subdividor
  129. * HE_Subdividor to apply
  130. * @param selection
  131. * HE_Selection
  132. * @return self
  133. */
  134. public HE_Mesh subdivideSelected(final HES_Subdividor subdividor,
  135. final HE_Selection selection) {
  136. return subdividor.apply(selection);
  137. }
  138. /**
  139. * Subdivide the mesh a number of times.
  140. *
  141. * @param subdividor HE_Subdividor to apply
  142. * @param rep subdivision iterations. WARNING: higher values will lead to
  143. * unmanageable number of faces.
  144. * @return self
  145. */
  146. public HE_Mesh subdivide(final HES_Subdividor subdividor, final int rep) {
  147. for (int i = 0; i < rep; i++) {
  148. subdivide(subdividor);
  149. }
  150. return this;
  151. }
  152. /**
  153. * Subdivide a selection of the mesh a number of times.
  154. *
  155. * @param subdividor
  156. * HE_Subdividor to apply
  157. * @param selection
  158. * HE_Selection initial selection
  159. * @param rep subdivision iterations
  160. * @return self
  161. */
  162. public HE_Mesh subdivideSelected(final HES_Subdividor subdividor,
  163. final HE_Selection selection, final int rep) {
  164. for (int i = 0; i < rep; i++) {
  165. subdivideSelected(subdividor, selection);
  166. }
  167. return this;
  168. }
  169. /**
  170. * Deep copy of mesh.
  171. *
  172. * @return copy as new HE_Mesh, includes selection
  173. */
  174. public HE_Mesh get() {
  175. final HE_Mesh result = new HE_Mesh();
  176. final HashMap<Integer, Integer> vertexCorrelation = new HashMap<Integer, Integer>();
  177. final HashMap<Integer, Integer> faceCorrelation = new HashMap<Integer, Integer>();
  178. final HashMap<Integer, Integer> halfedgeCorrelation = new HashMap<Integer, Integer>();
  179. final HashMap<Integer, Integer> edgeCorrelation = new HashMap<Integer, Integer>();
  180. HE_Vertex rv;
  181. HE_Vertex v;
  182. final Iterator<HE_Vertex> vItr = vItr();
  183. while (vItr.hasNext()) {
  184. v = vItr.next();
  185. rv = new HE_Vertex();
  186. result.add(rv);
  187. vertexCorrelation.put(v.key(), rv.key());
  188. }
  189. HE_Face rf;
  190. HE_Face f;
  191. final Iterator<HE_Face> fItr = fItr();
  192. while (fItr.hasNext()) {
  193. f = fItr.next();
  194. rf = new HE_Face();
  195. result.add(rf);
  196. rf.label = f.label;
  197. faceCorrelation.put(f.key(), rf.key());
  198. }
  199. HE_Halfedge rhe;
  200. HE_Halfedge he;
  201. final Iterator<HE_Halfedge> heItr = heItr();
  202. while (heItr.hasNext()) {
  203. he = heItr.next();
  204. rhe = new HE_Halfedge();
  205. result.add(rhe);
  206. halfedgeCorrelation.put(he.key(), rhe.key());
  207. }
  208. HE_Edge re;
  209. final Iterator<HE_Edge> eItr = eItr();
  210. HE_Edge e;
  211. while (eItr.hasNext()) {
  212. e = eItr.next();
  213. re = new HE_Edge();
  214. result.add(re);
  215. edgeCorrelation.put(e.key(), re.key());
  216. }
  217. HE_Vertex sv;
  218. HE_Vertex tv;
  219. final Iterator<HE_Vertex> svItr = vItr();
  220. final Iterator<HE_Vertex> tvItr = result.vItr();
  221. Integer key;
  222. while (svItr.hasNext()) {
  223. sv = svItr.next();
  224. tv = tvItr.next();
  225. tv.set(sv);
  226. if (sv.getHalfedge() != null) {
  227. key = halfedgeCorrelation.get(sv.getHalfedge().key());
  228. tv.setHalfedge(result.getHalfedgeByKey(key));
  229. }
  230. }
  231. HE_Face sf;
  232. HE_Face tf;
  233. final Iterator<HE_Face> sfItr = fItr();
  234. final Iterator<HE_Face> tfItr = result.fItr();
  235. while (sfItr.hasNext()) {
  236. sf = sfItr.next();
  237. tf = tfItr.next();
  238. if (sf.getHalfedge() != null) {
  239. key = halfedgeCorrelation.get(sf.getHalfedge().key());
  240. tf.setHalfedge(result.getHalfedgeByKey(key));
  241. }
  242. }
  243. final Iterator<HE_Edge> seItr = eItr();
  244. final Iterator<HE_Edge> teItr = result.eItr();
  245. HE_Edge se;
  246. HE_Edge te;
  247. while (seItr.hasNext()) {
  248. se = seItr.next();
  249. te = teItr.next();
  250. if (se.getHalfedge() != null) {
  251. key = halfedgeCorrelation.get(se.getHalfedge().key());
  252. te.setHalfedge(result.getHalfedgeByKey(key));
  253. }
  254. }
  255. HE_Halfedge she;
  256. HE_Halfedge the;
  257. final Iterator<HE_Halfedge> sheItr = heItr();
  258. final Iterator<HE_Halfedge> theItr = result.heItr();
  259. while (sheItr.hasNext()) {
  260. she = sheItr.next();
  261. the = theItr.next();
  262. if (she.getPair() != null) {
  263. key = halfedgeCorrelation.get(she.getPair().key());
  264. the.setPair(result.getHalfedgeByKey(key));
  265. }
  266. if (she.getNextInFace() != null) {
  267. key = halfedgeCorrelation.get(she.getNextInFace().key());
  268. the.setNext(result.getHalfedgeByKey(key));
  269. }
  270. if (she.getVertex() != null) {
  271. key = vertexCorrelation.get(she.getVertex().key());
  272. the.setVertex(result.getVertexByKey(key));
  273. }
  274. if (she.getFace() != null) {
  275. key = faceCorrelation.get(she.getFace().key());
  276. the.setFace(result.getFaceByKey(key));
  277. }
  278. if (she.getEdge() != null) {
  279. key = edgeCorrelation.get(she.getEdge().key());
  280. the.setEdge(result.getEdgeByKey(key));
  281. }
  282. }
  283. result._center.set(_center);
  284. result._centerUpdated = _centerUpdated;
  285. return result;
  286. }
  287. /**
  288. * Add all mesh elements to this mesh. No copies are made.
  289. *
  290. * @param mesh mesh to add
  291. */
  292. public void add(final HE_Mesh mesh) {
  293. addVertices(mesh.getVerticesAsArray());
  294. addFaces(mesh.getFacesAsArray());
  295. addEdges(mesh.getEdgesAsArray());
  296. addHalfedges(mesh.getHalfedgesAsArray());
  297. }
  298. /**
  299. * Replace mesh with deep copy of target.
  300. *
  301. * @param target
  302. * HE_Mesh to be duplicated
  303. */
  304. public void set(final HE_Mesh target) {
  305. final HE_Mesh result = target.get();
  306. replaceVertices(result.getVerticesAsArray());
  307. replaceFaces(result.getFacesAsArray());
  308. replaceHalfedges(result.getHalfedgesAsArray());
  309. replaceEdges(result.getEdgesAsArray());
  310. }
  311. /**
  312. * Replace mesh with shallow copy of target.
  313. *
  314. * @param target
  315. * HE_Mesh to be duplicated
  316. */
  317. private void setNoCopy(final HE_Mesh target) {
  318. _hashedVertices = target._hashedVertices;
  319. _hashedHalfedges = target._hashedHalfedges;
  320. _hashedEdges = target._hashedEdges;
  321. _hashedFaces = target._hashedFaces;
  322. _center = target._center;
  323. _centerUpdated = target._centerUpdated;
  324. }
  325. // CONVERT
  326. /**
  327. * Return all vertex positions as an array .
  328. *
  329. * @return 2D array of float. First index gives vertex. Second index gives
  330. * x-,y- or z-coordinate.
  331. */
  332. public float[][] getVerticesAsFloat() {
  333. final float[][] result = new float[numberOfVertices()][3];
  334. int i = 0;
  335. HE_Vertex v;
  336. final Iterator<HE_Vertex> vItr = vItr();
  337. while (vItr.hasNext()) {
  338. v = vItr.next();
  339. result[i][0] = (float) (v.x);
  340. result[i][1] = (float) (v.y);
  341. result[i][2] = (float) (v.z);
  342. i++;
  343. }
  344. return result;
  345. }
  346. /**
  347. * Return all vertex positions as an array .
  348. *
  349. * @return 2D array of double. First index gives vertex. Second index gives
  350. * x-,y- or z-coordinate.
  351. */
  352. public double[][] getVerticesAsDouble() {
  353. final double[][] result = new double[numberOfVertices()][3];
  354. int i = 0;
  355. HE_Vertex v;
  356. final Iterator<HE_Vertex> vItr = vItr();
  357. while (vItr.hasNext()) {
  358. v = vItr.next();
  359. result[i][0] = (float) (v.x);
  360. result[i][1] = (float) (v.y);
  361. result[i][2] = (float) (v.z);
  362. i++;
  363. }
  364. return result;
  365. }
  366. public HashMap<Integer, Integer> vertexKeyToIndex() {
  367. final HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
  368. int i = 0;
  369. final Iterator<HE_Vertex> vItr = vItr();
  370. while (vItr.hasNext()) {
  371. map.put(vItr.next().key(), i);
  372. i++;
  373. }
  374. return map;
  375. }
  376. /**
  377. * Return all vertex positions.
  378. *
  379. * @return array of WB_Point, values are copied.
  380. */
  381. public WB_Point[] getVerticesAsNewPoint() {
  382. final WB_Point[] result = new WB_Point[numberOfVertices()];
  383. int i = 0;
  384. HE_Vertex v;
  385. final Iterator<HE_Vertex> vItr = vItr();
  386. while (vItr.hasNext()) {
  387. v = vItr.next();
  388. result[i] = new WB_Point(v);
  389. i++;
  390. }
  391. return result;
  392. }
  393. /**
  394. * Return all vertex positions.
  395. *
  396. * @return array of WB_Point, no copies are made.
  397. */
  398. public WB_Point[] getVerticesAsPoint() {
  399. final WB_Point[] result = new WB_Point[numberOfVertices()];
  400. int i = 0;
  401. HE_Vertex v;
  402. final Iterator<HE_Vertex> vItr = vItr();
  403. while (vItr.hasNext()) {
  404. v = vItr.next();
  405. result[i] = v;
  406. i++;
  407. }
  408. return result;
  409. }
  410. /**
  411. * Return all vertex normal.
  412. *
  413. * @return array of WB_Normal.
  414. */
  415. public WB_Normal[] getVertexNormals() {
  416. final WB_Normal[] result = new WB_Normal[numberOfVertices()];
  417. int i = 0;
  418. HE_Vertex v;
  419. final Iterator<HE_Vertex> vItr = vItr();
  420. while (vItr.hasNext()) {
  421. v = vItr.next();
  422. result[i] = v.getVertexNormal();
  423. i++;
  424. }
  425. return result;
  426. }
  427. /**
  428. * Return all vertex normal.
  429. *
  430. * @return FastMap of WB_Normal.
  431. */
  432. public FastMap<Integer, WB_Normal> getKeyedVertexNormals() {
  433. final FastMap<Integer, WB_Normal> result = new FastMap<Integer, WB_Normal>(
  434. numberOfVertices());
  435. HE_Vertex v;
  436. final Iterator<HE_Vertex> vItr = vItr();
  437. while (vItr.hasNext()) {
  438. v = vItr.next();
  439. result.put(v.key(), v.getVertexNormal());
  440. }
  441. return result;
  442. }
  443. /**
  444. * Return the faces as array of vertex indices.
  445. *
  446. * @return 2D array of int. First index gives face. Second index gives
  447. * vertices.
  448. */
  449. public int[][] getFacesAsInt() {
  450. final int[][] result = new int[numberOfFaces()][];
  451. final FastMap<Integer, Integer> vertexKeys = new FastMap<Integer, Integer>();
  452. final Iterator<HE_Vertex> vItr = vItr();
  453. int i = 0;
  454. while (vItr.hasNext()) {
  455. vertexKeys.put(vItr.next().key(), i);
  456. i++;
  457. }
  458. final Iterator<HE_Face> fItr = fItr();
  459. HE_Halfedge he;
  460. HE_Face f;
  461. i = 0;
  462. while (fItr.hasNext()) {
  463. f = fItr.next();
  464. result[i] = new int[f.getFaceOrder()];
  465. he = f.getHalfedge();
  466. int j = 0;
  467. do {
  468. result[i][j] = vertexKeys.get(he.getVertex().key());
  469. he = he.getNextInFace();
  470. j++;
  471. } while (he != f.getHalfedge());
  472. i++;
  473. }
  474. return result;
  475. }
  476. /**
  477. * Return all face normals.
  478. *
  479. * @return array of WB_Normal.
  480. */
  481. public WB_Normal[] getFaceNormals() {
  482. final WB_Normal[] result = new WB_Normal[numberOfFaces()];
  483. int i = 0;
  484. HE_Face f;
  485. final Iterator<HE_Face> fItr = fItr();
  486. while (fItr.hasNext()) {
  487. f = fItr.next();
  488. result[i] = f.getFaceNormal();
  489. i++;
  490. }
  491. return result;
  492. }
  493. /**
  494. * Return all face normals.
  495. *
  496. * @return FastMap of WB_Normal.
  497. */
  498. public FastMap<Integer, WB_Normal> getKeyedFaceNormals() {
  499. final FastMap<Integer, WB_Normal> result = new FastMap<Integer, WB_Normal>(
  500. numberOfFaces());
  501. HE_Face f;
  502. final Iterator<HE_Face> fItr = fItr();
  503. while (fItr.hasNext()) {
  504. f = fItr.next();
  505. result.put(f.key(), f.getFaceNormal());
  506. }
  507. return result;
  508. }
  509. /**
  510. * Return all face centers.
  511. *
  512. * @return array of WB_Point.
  513. */
  514. public WB_Point[] getFaceCenters() {
  515. final WB_Point[] result = new WB_Point[numberOfFaces()];
  516. int i = 0;
  517. HE_Face f;
  518. final Iterator<HE_Face> fItr = fItr();
  519. while (fItr.hasNext()) {
  520. f = fItr.next();
  521. result[i] = f.getFaceCenter();
  522. i++;
  523. }
  524. return result;
  525. }
  526. /**
  527. * Return all face centers.
  528. *
  529. * @return FastMap of WB_Point.
  530. */
  531. public FastMap<Integer, WB_Point> getKeyedFaceCenters() {
  532. final FastMap<Integer, WB_Point> result = new FastMap<Integer, WB_Point>(
  533. numberOfFaces());
  534. HE_Face f;
  535. final Iterator<HE_Face> fItr = fItr();
  536. while (fItr.hasNext()) {
  537. f = fItr.next();
  538. result.put(f.key(), f.getFaceCenter());
  539. }
  540. return result;
  541. }
  542. /**
  543. * Return all edge normals.
  544. *
  545. * @return array of WB_Normal.
  546. */
  547. public WB_Normal[] getEdgeNormals() {
  548. final WB_Normal[] result = new WB_Normal[numberOfEdges()];
  549. int i = 0;
  550. HE_Edge e;
  551. final Iterator<HE_Edge> eItr = eItr();
  552. while (eItr.hasNext()) {
  553. e = eItr.next();
  554. result[i] = e.getEdgeNormal();
  555. i++;
  556. }
  557. return result;
  558. }
  559. /**
  560. * Return all edge normals.
  561. *
  562. * @return FastMap of WB_Normal.
  563. */
  564. public FastMap<Integer, WB_Normal> getKeyedEdgeNormals() {
  565. final FastMap<Integer, WB_Normal> result = new FastMap<Integer, WB_Normal>(
  566. numberOfEdges());
  567. HE_Edge e;
  568. final Iterator<HE_Edge> eItr = eItr();
  569. while (eItr.hasNext()) {
  570. e = eItr.next();
  571. result.put(e.key(), e.getEdgeNormal());
  572. }
  573. return result;
  574. }
  575. /**
  576. * Return all edge centers.
  577. *
  578. * @return array of WB_Point.
  579. */
  580. public WB_Point[] getEdgeCenters() {
  581. final WB_Point[] result = new WB_Point[numberOfEdges()];
  582. int i = 0;
  583. HE_Edge e;
  584. final Iterator<HE_Edge> eItr = eItr();
  585. while (eItr.hasNext()) {
  586. e = eItr.next();
  587. result[i] = e.getEdgeCenter();
  588. i++;
  589. }
  590. return result;
  591. }
  592. /**
  593. * Return all edge centers.
  594. *
  595. * @return FastMap of WB_Point.
  596. */
  597. public FastMap<Integer, WB_Point> getKeyedEdgeCenters() {
  598. final FastMap<Integer, WB_Point> result = new FastMap<Integer, WB_Point>(
  599. numberOfEdges());
  600. HE_Edge e;
  601. final Iterator<HE_Edge> eItr = eItr();
  602. while (eItr.hasNext()) {
  603. e = eItr.next();
  604. result.put(e.key(), e.getEdgeCenter());
  605. }
  606. return result;
  607. }
  608. /**
  609. * Set vertex positions to values in array.
  610. *
  611. * @param values 2D array of float. First index is number of vertices, second
  612. * index is 3 (x-,y- and z-coordinate)
  613. */
  614. public void setVerticesFromFloat(final float[][] values) {
  615. int i = 0;
  616. _center.set(0, 0, 0);
  617. HE_Vertex v;
  618. final Iterator<HE_Vertex> vItr = vItr();
  619. while (vItr.hasNext()) {
  620. v = vItr.next();
  621. v.set(values[i][0], values[i][1], values[i][2]);
  622. i++;
  623. }
  624. }
  625. /**
  626. * Set vertex positions to values in array.
  627. *
  628. * @param values array of WB_Point.
  629. */
  630. public void setVerticesFromPoint(final WB_Point[] values) {
  631. int i = 0;
  632. _center.set(0, 0, 0);
  633. HE_Vertex v;
  634. final Iterator<HE_Vertex> vItr = vItr();
  635. while (vItr.hasNext()) {
  636. v = vItr.next();
  637. v.set(values[i]);
  638. i++;
  639. }
  640. ;
  641. }
  642. /**
  643. * Set vertex positions to values in array.
  644. *
  645. * @param values 2D array of double. First index is number of vertices, second
  646. * index is 3 (x-,y- and z-coordinate)
  647. */
  648. public void setVerticesFromDouble(final double[][] values) {
  649. int i = 0;
  650. HE_Vertex v;
  651. final Iterator<HE_Vertex> vItr = vItr();
  652. while (vItr.hasNext()) {
  653. v = vItr.next();
  654. v.set(values[i][0], values[i][1], values[i][2]);
  655. i++;
  656. }
  657. ;
  658. }
  659. /**
  660. * Set vertex positions to values in array.
  661. *
  662. * @param values 2D array of int. First index is number of vertices, second
  663. * index is 3 (x-,y- and z-coordinate)
  664. */
  665. public void setVerticesFromInt(final int[][] values) {
  666. int i = 0;
  667. HE_Vertex v;
  668. final Iterator<HE_Vertex> vItr = vItr();
  669. while (vItr.hasNext()) {
  670. v = vItr.next();
  671. v.set(values[i][0], values[i][1], values[i][2]);
  672. i++;
  673. }
  674. ;
  675. }
  676. /**
  677. * Return the mesh as polygon soup.
  678. *
  679. * @return array of WB_polygon
  680. *
  681. */
  682. public WB_ExplicitPolygon[] getPolygons() {
  683. final WB_ExplicitPolygon[] result = new WB_ExplicitPolygon[numberOfFaces()];
  684. final Iterator<HE_Face> fItr = fItr();
  685. HE_Face f;
  686. int i = 0;
  687. while (fItr.hasNext()) {
  688. f = fItr.next();
  689. result[i] = f.toPolygon();
  690. i++;
  691. }
  692. return result;
  693. }
  694. public ArrayList<WB_ExplicitPolygon> getPolygonArrayList() {
  695. final ArrayList<WB_ExplicitPolygon> result = new ArrayList<WB_ExplicitPolygon>();
  696. final Iterator<HE_Face> fItr = fItr();
  697. HE_Face f;
  698. while (fItr.hasNext()) {
  699. f = fItr.next();
  700. result.add(f.toPolygon());
  701. }
  702. return result;
  703. }
  704. public WB_ExplicitSegment[] getSegments() {
  705. final WB_ExplicitSegment[] result = new WB_ExplicitSegment[numberOfEdges()];
  706. final Iterator<HE_Edge> eItr = eItr();
  707. HE_Edge e;
  708. int i = 0;
  709. while (eItr.hasNext()) {
  710. e = eItr.next();
  711. result[i] = new WB_ExplicitSegment(e.getStartVertex(),
  712. e.getEndVertex(), false);
  713. i++;
  714. }
  715. return result;
  716. }
  717. public WB_IndexedSegment[] getIndexedSegments() {
  718. final WB_IndexedSegment[] result = new WB_IndexedSegment[numberOfEdges()];
  719. final WB_Point[] points = getVerticesAsPoint();
  720. final FastMap<Integer, Integer> map = new FastMap<Integer, Integer>();
  721. map.putAll(vertexKeyToIndex());
  722. final Iterator<HE_Edge> eItr = eItr();
  723. HE_Edge e;
  724. int i = 0;
  725. while (eItr.hasNext()) {
  726. e = eItr.next();
  727. result[i] = new WB_IndexedSegment(
  728. map.get(e.getStartVertex().key()), map.get(e.getEndVertex()
  729. .key()), points);
  730. i++;
  731. }
  732. return result;
  733. }
  734. public WB_Frame getFrame() {
  735. final WB_Frame frame = new WB_Frame(getVerticesAsPoint());
  736. final FastMap<Integer, Integer> map = new FastMap<Integer, Integer>();
  737. map.putAll(vertexKeyToIndex());
  738. final Iterator<HE_Edge> eItr = eItr();
  739. HE_Edge e;
  740. while (eItr.hasNext()) {
  741. e = eItr.next();
  742. frame.addStrut(map.get(e.getStartVertex().key()),
  743. map.get(e.getEndVertex().key()));
  744. }
  745. return frame;
  746. }
  747. // TRANSFORM
  748. /**
  749. * Apply transform to entire mesh.
  750. *
  751. * @param T WB_Transform to apply
  752. * @return self
  753. */
  754. public HE_Mesh transform(final WB_Transform T) {
  755. final Iterator<HE_Vertex> vItr = vItr();
  756. while (vItr.hasNext()) {
  757. T.apply(vItr.next());
  758. }
  759. return this;
  760. }
  761. /**
  762. * Translate entire mesh.
  763. *
  764. * @param x the x
  765. * @param y the y
  766. * @param z the z
  767. * @return self
  768. */
  769. public HE_Mesh move(final double x, final double y, final double z) {
  770. _center.add(x, y, z);
  771. final Iterator<HE_Vertex> vItr = vItr();
  772. while (vItr.hasNext()) {
  773. vItr.next().add(x, y, z);
  774. }
  775. return this;
  776. }
  777. /**
  778. * Translate entire mesh.
  779. *
  780. * @param v
  781. * @return self
  782. */
  783. public HE_Mesh move(final WB_XYZ v) {
  784. return move(v.x, v.y, v.z);
  785. }
  786. /**
  787. * Translate entire mesh to given position.
  788. *
  789. * @param x
  790. * @param y
  791. * @param z
  792. * @return self
  793. */
  794. public HE_Mesh moveTo(final double x, final double y, final double z) {
  795. if (!_centerUpdated) {
  796. getCenter();
  797. }
  798. final Iterator<HE_Vertex> vItr = vItr();
  799. while (vItr.hasNext()) {
  800. vItr.next().add(x - _center.x, y - _center.y, z - _center.z);
  801. }
  802. _center.set(x, y, z);
  803. return this;
  804. }
  805. /**
  806. * Translate entire mesh to given position.
  807. *
  808. * @param v the v
  809. * @return self
  810. */
  811. public HE_Mesh moveTo(final WB_Point v) {
  812. return moveTo(v.x, v.y, v.z);
  813. }
  814. /**
  815. * Rotate entire mesh around an arbitrary axis.
  816. *
  817. * @param angle angle
  818. * @param p1x x-coordinate of first point on axis
  819. * @param p1y y-coordinate of first point on axis
  820. * @param p1z z-coordinate of first point on axis
  821. * @param p2x x-coordinate of second point on axis
  822. * @param p2y y-coordinate of second point on axis
  823. * @param p2z z-coordinate of second point on axis
  824. * @return self
  825. */
  826. public HE_Mesh rotateAboutAxis(final double angle, final double p1x,
  827. final double p1y, final double p1z, final double p2x,
  828. final double p2y, final double p2z) {
  829. if (!_centerUpdated) {
  830. getCenter();
  831. }
  832. HE_Vertex v;
  833. final Iterator<HE_Vertex> vItr = vItr();
  834. final WB_Transform raa = new WB_Transform();
  835. raa.addRotateAboutAxis(angle, new WB_Point(p1x, p1y, p1z),
  836. new WB_Vector(p2x - p1x, p2y - p1y, p2z - p1z));
  837. while (vItr.hasNext()) {
  838. v = vItr.next();
  839. raa.applyInto(v, v);
  840. }
  841. raa.applyInto(_center, _center);
  842. ;
  843. return this;
  844. }
  845. /**
  846. * Rotate entire mesh around an arbitrary axis.
  847. *
  848. * @param angle angle
  849. * @param p1 first point on axis
  850. * @param p2 second point on axis
  851. * @return self
  852. */
  853. public HE_Mesh rotateAboutAxis(final double angle, final WB_Point p1,
  854. final WB_Point p2) {
  855. if (!_centerUpdated) {
  856. getCenter();
  857. }
  858. HE_Vertex v;
  859. final Iterator<HE_Vertex> vItr = vItr();
  860. final WB_Transform raa = new WB_Transform();
  861. raa.addRotateAboutAxis(angle, p1, p2.subToVector(p1));
  862. while (vItr.hasNext()) {
  863. v = vItr.next();
  864. raa.applyInto(v, v);
  865. }
  866. raa.applyInto(_center, _center);
  867. ;
  868. return this;
  869. }
  870. /**
  871. * Rotate entire mesh around an arbitrary axis.
  872. *
  873. * @param angle angle
  874. * @param p rotation point
  875. * @param a axis
  876. * @return self
  877. */
  878. public HE_Mesh rotateAboutAxis(final double angle, final WB_Point p,
  879. final WB_Vector a) {
  880. if (!_centerUpdated) {
  881. getCenter();
  882. }
  883. HE_Vertex v;
  884. final Iterator<HE_Vertex> vItr = vItr();
  885. final WB_Transform raa = new WB_Transform();
  886. raa.addRotateAboutAxis(angle, p, a);
  887. while (vItr.hasNext()) {
  888. v = vItr.next();
  889. raa.applyInto(v, v);
  890. }
  891. raa.applyInto(_center, _center);
  892. ;
  893. return this;
  894. }
  895. /**
  896. * Rotate entire mesh around an arbitrary axis.
  897. *
  898. * @param angle angle
  899. * @param p rotation point
  900. * @param a axis
  901. * @return self
  902. */
  903. public HE_Mesh rotateAboutAxis(final double angle, final WB_Point p,
  904. final WB_Normal a) {
  905. if (!_centerUpdated) {
  906. getCenter();
  907. }
  908. HE_Vertex v;
  909. final Iterator<HE_Vertex> vItr = vItr();
  910. final WB_Transform raa = new WB_Transform();
  911. raa.addRotateAboutAxis(angle, p, a);
  912. while (vItr.hasNext()) {
  913. v = vItr.next();
  914. raa.applyInto(v, v);
  915. }
  916. raa.applyInto(_center, _center);
  917. ;
  918. return this;
  919. }
  920. /**
  921. * Scale entire mesh around center point.
  922. *
  923. * @param scaleFactorx
  924. * x-coordinate of scale factor
  925. * @param scaleFactory
  926. * y-coordinate of scale factor
  927. * @param scaleFactorz
  928. * z-coordinate of scale factor
  929. * @param c
  930. * center
  931. * @return self
  932. */
  933. public HE_Mesh scale(final double scaleFactorx, final double scaleFactory,
  934. final double scaleFactorz, final WB_Point c) {
  935. if (!_centerUpdated) {
  936. getCenter();
  937. }
  938. HE_Vertex v;
  939. final Iterator<HE_Vertex> vItr = vItr();
  940. while (vItr.hasNext()) {
  941. v = vItr.next();
  942. v.set(c.x + scaleFactorx * (v.x - c.x), c.y + scaleFactory
  943. * (v.y - c.y), c.z + scaleFactorz * (v.z - c.z));
  944. }
  945. _center.set(c.x + scaleFactorx * (-c.x + _center.x), c.y + scaleFactory
  946. * (-c.y + _center.y), c.z + scaleFactorz * (-c.z + _center.z));
  947. ;
  948. return this;
  949. }
  950. /**
  951. * Scale entire mesh around center point.
  952. *
  953. * @param scaleFactor
  954. * scale
  955. * @param c
  956. * center
  957. * @return self
  958. */
  959. public HE_Mesh scale(final double scaleFactor, final WB_Point c) {
  960. return scale(scaleFactor, scaleFactor, scaleFactor, c);
  961. }
  962. /**
  963. * Scale entire mesh around bodycenter.
  964. *
  965. * @param scaleFactorx
  966. * x-coordinate of scale factor
  967. * @param scaleFactory
  968. * y-coordinate of scale factor
  969. * @param scaleFactorz
  970. * z-coordinate of scale factor
  971. * @return self
  972. */
  973. public HE_Mesh scale(final double scaleFactorx, final double scaleFactory,
  974. final double scaleFactorz) {
  975. if (!_centerUpdated) {
  976. getCenter();
  977. }
  978. HE_Vertex v;
  979. final Iterator<HE_Vertex> vItr = vItr();
  980. while (vItr.hasNext()) {
  981. v = vItr.next();
  982. v.set(_center.x + scaleFactorx * (v.x - _center.x), _center.y
  983. + scaleFactory * (v.y - _center.y), _center.z
  984. + scaleFactorz * (v.z - _center.z));
  985. }
  986. ;
  987. return this;
  988. }
  989. /**
  990. * Scale entire mesh around bodycenter.
  991. *
  992. * @param scaleFactor
  993. * scale
  994. * @return self
  995. */
  996. public HE_Mesh scale(final double scaleFactor) {
  997. return scale(scaleFactor, scaleFactor, scaleFactor);
  998. }
  999. // DERIVED ELEMENTS
  1000. /**
  1001. * Get the center (average of all vertex positions).
  1002. *
  1003. * @return the center
  1004. */
  1005. public WB_Point getCenter() {
  1006. if (_centerUpdated) {
  1007. return _center;
  1008. } else {
  1009. resetCenter();
  1010. return _center;
  1011. }
  1012. }
  1013. /**
  1014. * Reset the center to the average of all vertex positions).
  1015. *
  1016. */
  1017. public void resetCenter() {
  1018. _center.set(0, 0, 0);
  1019. final Iterator<HE_Vertex> vItr = vItr();
  1020. while (vItr.hasNext()) {
  1021. _center.add(vItr.next());
  1022. }
  1023. _center.div(numberOfVertices());
  1024. _centerUpdated = true;
  1025. }
  1026. // HELPERS
  1027. /**
  1028. * Assign face to halfedge loop.
  1029. *
  1030. * @param face face
  1031. * @param halfedge halfedge loop
  1032. */
  1033. protected static void assignFaceToLoop(final HE_Face face,
  1034. final HE_Halfedge halfedge) {
  1035. HE_Halfedge he = halfedge;
  1036. do {
  1037. he.setFace(face);
  1038. he = he.getNextInFace();
  1039. } while (he != halfedge);
  1040. }
  1041. /**
  1042. * Cycle halfedges.
  1043. *
  1044. * @param halfedges halfedges to cycle
  1045. * @param cycle HE_CycleOption.NORMAL, HE_CycleOption.REVERSE
  1046. */
  1047. public static void cycleHalfedges(final List<HE_Halfedge> halfedges,
  1048. final HE_CycleOption cycle) {
  1049. HE_Halfedge he;
  1050. final int n = halfedges.size();
  1051. if (n > 0) {
  1052. if (cycle == HE_CycleOption.NORMAL) {
  1053. for (int j = 0; j < n - 1; j++) {
  1054. he = halfedges.get(j);
  1055. he.setNext(halfedges.get(j + 1));
  1056. }
  1057. he = halfedges.get(n - 1);
  1058. he.setNext(halfedges.get(0));
  1059. } else {
  1060. he = halfedges.get(0);
  1061. he.setNext(halfedges.get(n - 1));
  1062. for (int j = 1; j < n; j++) {
  1063. he = halfedges.get(j);
  1064. he.setNext(halfedges.get(j - 1));
  1065. }
  1066. }
  1067. }
  1068. }
  1069. /**
  1070. * Collect all unpaired halfedges.
  1071. *
  1072. * @return the unpaired halfedges
  1073. */
  1074. public ArrayList<HE_Halfedge> getUnpairedHalfedges() {
  1075. final ArrayList<HE_Halfedge> unpairedHalfedges = new ArrayList<HE_Halfedge>();
  1076. HE_Halfedge he;
  1077. final Iterator<HE_Halfedge> heItr = heItr();
  1078. while (heItr.hasNext()) {
  1079. he = heItr.next();
  1080. if (he.getPair() == null) {
  1081. unpairedHalfedges.add(he);
  1082. }
  1083. }
  1084. return unpairedHalfedges;
  1085. }
  1086. /**
  1087. * Collect all boundary halfedges.
  1088. *
  1089. * @return boundary halfedges
  1090. */
  1091. public ArrayList<HE_Halfedge> getBoundaryHalfedges() {
  1092. final ArrayList<HE_Halfedge> boundaryHalfedges = new ArrayList<HE_Halfedge>();
  1093. HE_Halfedge he;
  1094. final Iterator<HE_Halfedge> heItr = heItr();
  1095. while (heItr.hasNext()) {
  1096. he = heItr.next();
  1097. if (he.getFace() == null) {
  1098. boundaryHalfedges.add(he);
  1099. }
  1100. }
  1101. return boundaryHalfedges;
  1102. }
  1103. /**
  1104. * Try to pair all unpaired halfedges.
  1105. */
  1106. public void pairHalfedges() {
  1107. class VertexInfo {
  1108. FastList<HE_Halfedge> out;
  1109. FastList<HE_Halfedge> in;
  1110. VertexInfo() {
  1111. out = new FastList<HE_Halfedge>();
  1112. in = new FastList<HE_Halfedge>();
  1113. }
  1114. }
  1115. final FastMap<Integer, VertexInfo> vertexLists = new FastMap<Integer, VertexInfo>();
  1116. final ArrayList<HE_Halfedge> unpairedHalfedges = getUnpairedHalfedges();
  1117. HE_Vertex v;
  1118. VertexInfo vi;
  1119. System.out.println("HE_Mesh : collating " + unpairedHalfedges.size()
  1120. + " unpaired halfedges per vertex.");
  1121. for (final HE_Halfedge he : unpairedHalfedges) {
  1122. v = he.getVertex();
  1123. vi = vertexLists.get(v.key());
  1124. if (vi == null) {
  1125. vi = new VertexInfo();
  1126. vertexLists.put(v.key(), vi);
  1127. }
  1128. vi.out.add(he);
  1129. v = he.getNextInFace().getVertex();
  1130. vi = vertexLists.get(v.key());
  1131. if (vi == null) {
  1132. vi = new VertexInfo();
  1133. vertexLists.put(v.key(), vi);
  1134. }
  1135. vi.in.add(he);
  1136. }
  1137. HE_Halfedge he;
  1138. HE_Halfedge he2;
  1139. HE_Edge e;
  1140. System.out.println("HE_Mesh : pairing unpaired halfedges per vertex.");
  1141. for (final VertexInfo vInfo : vertexLists.values()) {
  1142. for (int i = 0; i < vInfo.out.size(); i++) {
  1143. he = vInfo.out.get(i);
  1144. if (he.getPair() == null) {
  1145. for (int j = 0; j < vInfo.in.size(); j++) {
  1146. he2 = vInfo.in.get(j);
  1147. if ((he2.getPair() == null)
  1148. && (he.getVertex() == he2.getNextInFace()
  1149. .getVertex())
  1150. && (he2.getVertex() == he.getNextInFace()
  1151. .getVertex())) {
  1152. he.setPair(he2);
  1153. e = new HE_Edge();
  1154. e.setHalfedge(he);
  1155. he.setEdge(e);
  1156. he2.setEdge(e);
  1157. add(e);
  1158. break;
  1159. }
  1160. }
  1161. }
  1162. }
  1163. }
  1164. }
  1165. public void pairHalfedgesSilent() {
  1166. class VertexInfo {
  1167. FastList<HE_Halfedge> out;
  1168. FastList<HE_Halfedge> in;
  1169. VertexInfo() {
  1170. out = new FastList<HE_Halfedge>();
  1171. in = new FastList<HE_Halfedge>();
  1172. }
  1173. }
  1174. final FastMap<Integer, VertexInfo> vertexLists = new FastMap<Integer, VertexInfo>();
  1175. final ArrayList<HE_Halfedge> unpairedHalfedges = getUnpairedHalfedges();
  1176. HE_Vertex v;
  1177. VertexInfo vi;
  1178. for (final HE_Halfedge he : unpairedHalfedges) {
  1179. v = he.getVertex();
  1180. vi = vertexLists.get(v.key());
  1181. if (vi == null) {
  1182. vi = new VertexInfo();
  1183. vertexLists.put(v.key(), vi);
  1184. }
  1185. vi.out.add(he);
  1186. v = he.getNextInFace().getVertex();
  1187. vi = vertexLists.get(v.key());
  1188. if (vi == null) {
  1189. vi = new VertexInfo();
  1190. vertexLists.put(v.key(), vi);
  1191. }
  1192. vi.in.add(he);
  1193. }
  1194. HE_Halfedge he;
  1195. HE_Halfedge he2;
  1196. HE_Edge e;
  1197. for (final VertexInfo vInfo : vertexLists.values()) {
  1198. for (int i = 0; i < vInfo.out.size(); i++) {
  1199. he = vInfo.out.get(i);
  1200. if (he.getPair() == null) {
  1201. for (int j = 0; j < vInfo.in.size(); j++) {
  1202. he2 = vInfo.in.get(j);
  1203. if ((he2.getPair() == null)
  1204. && (he.getVertex() == he2.getNextInFace()
  1205. .getVertex())
  1206. && (he2.getVertex() == he.getNextInFace()
  1207. .getVertex())) {
  1208. he.setPair(he2);
  1209. e = new HE_Edge();
  1210. e.setHalfedge(he);
  1211. he.setEdge(e);
  1212. he2.setEdge(e);
  1213. add(e);
  1214. break;
  1215. }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. }
  1221. public void pairHalfedges(final List<HE_Halfedge> unpairedHalfedges) {
  1222. class VertexInfo {
  1223. FastList<HE_Halfedge> out;
  1224. FastList<HE_Halfedge> in;
  1225. VertexInfo() {
  1226. out = new FastList<HE_Halfedge>();
  1227. in = new FastList<HE_Halfedge>();
  1228. }
  1229. }
  1230. final FastMap<Integer, VertexInfo> vertexLists = new FastMap<Integer, VertexInfo>();
  1231. HE_Vertex v;
  1232. VertexInfo vi;
  1233. System.out.println("HE_Mesh : collating " + unpairedHalfedges.size()
  1234. + " unpaired halfedges per vertex.");
  1235. for (final HE_Halfedge he : unpairedHalfedges) {
  1236. v = he.getVertex();
  1237. vi = vertexLists.get(v.key());
  1238. if (vi == null) {
  1239. vi = new VertexInfo();
  1240. vertexLists.put(v.key(), vi);
  1241. }
  1242. vi.out.add(he);
  1243. v = he.getNextInFace().getVertex();
  1244. vi = vertexLists.get(v.key());
  1245. if (vi == null) {
  1246. vi = new VertexInfo();
  1247. vertexLists.put(v.key(), vi);
  1248. }
  1249. vi.in.add(he);
  1250. }
  1251. HE_Halfedge he;
  1252. HE_Halfedge he2;
  1253. HE_Edge e;
  1254. System.out.println("HE_Mesh : pairing unpaired halfedges per vertex.");
  1255. for (final VertexInfo vInfo : vertexLists.values()) {
  1256. for (int i = 0; i < vInfo.out.size(); i++) {
  1257. he = vInfo.out.get(i);
  1258. if (he.getPair() == null) {
  1259. for (int j = 0; j < vInfo.in.size(); j++) {
  1260. he2 = vInfo.in.get(j);
  1261. if ((he2.getPair() == null)
  1262. && (he.getVertex() == he2.getNextInFace()
  1263. .getVertex())
  1264. && (he2.getVertex() == he.getNextInFace()
  1265. .getVertex())) {
  1266. he.setPair(he2);
  1267. e = new HE_Edge();
  1268. e.setHalfedge(he);
  1269. he.setEdge(e);
  1270. he2.setEdge(e);
  1271. add(e);
  1272. break;
  1273. }
  1274. }
  1275. }
  1276. }
  1277. }
  1278. }
  1279. /**
  1280. * Cap all remaining unpaired halfedges. Only use after pairHalfedges();
  1281. */
  1282. public void capHalfedges() {
  1283. final ArrayList<HE_Halfedge> unpairedHalfedges = getUnpairedHalfedges();
  1284. final int nuh = unpairedHalfedges.size();
  1285. final HE_Halfedge[] newHalfedges = new HE_Halfedge[nuh];
  1286. HE_Halfedge he1, he2;
  1287. HE_Edge e;
  1288. for (int i = 0; i < nuh; i++) {
  1289. he1 = unpairedHalfedges.get(i);
  1290. he2 = new HE_Halfedge();
  1291. he2.setVertex(he1.getNextInFace().getVertex());
  1292. he1.setPair(he2);
  1293. newHalfedges[i] = he2;
  1294. add(he2);
  1295. e = new HE_Edge();
  1296. add(e);
  1297. e.setHalfedge(he1);
  1298. he1.setEdge(e);
  1299. he2.setEdge(e);
  1300. }
  1301. for (int i = 0; i < nuh; i++) {
  1302. he1 = newHalfedges[i];
  1303. if (he1.getNextInFace() == null) {
  1304. for (int j = 0; j < nuh; j++) {
  1305. he2 = newHalfedges[j];
  1306. if (he2.getVertex() == he1.getPair().getVertex()) {
  1307. he1.setNext(he2);
  1308. break;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. }
  1314. public void uncapHalfedges() {
  1315. final Iterator<HE_Halfedge> heItr = heItr();
  1316. HE_Halfedge he;
  1317. while (heItr.hasNext()) {
  1318. he = heItr.next();
  1319. if (he.getFace() == null) {
  1320. he.getVertex().setHalfedge(he.getPair());
  1321. he.getEdge().setHalfedge(he.getPair());
  1322. he.getPair().clearPair();
  1323. heItr.remove();
  1324. }
  1325. }
  1326. }
  1327. /**
  1328. * Cap holes.
  1329. *
  1330. * @return all new faces as ArrayList<HE_Face>
  1331. */
  1332. public ArrayList<HE_Face> capHoles() {
  1333. final ArrayList<HE_Face> caps = new ArrayList<HE_Face>();
  1334. final ArrayList<HE_Halfedge> unpairedEdges = getUnpairedHalfedges();
  1335. ArrayList<HE_Halfedge> loopedHalfedges;
  1336. HE_Halfedge start;
  1337. HE_Halfedge he;
  1338. HE_Halfedge hen;
  1339. HE_Face nf;
  1340. ArrayList<HE_Halfedge> newHalfedges;
  1341. HE_Halfedge phe;
  1342. HE_Halfedge nhe;
  1343. HE_Edge ne;
  1344. while (unpairedEdges.size() > 0) {
  1345. loopedHalfedges = new ArrayList<HE_Halfedge>();
  1346. start = unpairedEdges.get(0);
  1347. loopedHalfedges.add(start);
  1348. he = start;
  1349. hen = start;
  1350. boolean stuck = false;
  1351. do {
  1352. for (int i = 0; i < unpairedEdges.size(); i++) {
  1353. hen = unpairedEdges.get(i);
  1354. if (hen.getVertex() == he.getNextInFace().getVertex()) {
  1355. if (!loopedHalfedges.contains(hen)) {
  1356. loopedHalfedges.add(hen);
  1357. } else {
  1358. stuck = true;
  1359. }
  1360. break;
  1361. }
  1362. }
  1363. if (hen.getVertex() != he.getNextInFace().getVertex()) {
  1364. stuck = true;
  1365. }
  1366. he = hen;
  1367. } while ((hen.getNextInFace().getVertex() != start.getVertex())
  1368. && (!stuck));
  1369. unpairedEdges.removeAll(loopedHalfedges);
  1370. nf = new HE_Face();
  1371. add(nf);
  1372. caps.add(nf);
  1373. newHalfedges = new ArrayList<HE_Halfedge>();
  1374. for (int i = 0; i < loopedHalfedges.size(); i++) {
  1375. phe = loopedHalfedges.get(i);
  1376. nhe = new HE_Halfedge();
  1377. add(nhe);
  1378. newHalfedges.add(nhe);
  1379. nhe.setVertex(phe.getNextInFace().getVertex());
  1380. nhe.setPair(phe);
  1381. nhe.setFace(nf);
  1382. if (nf.getHalfedge() == null) {
  1383. nf.setHalfedge(nhe);
  1384. }
  1385. ne = new HE_Edge();
  1386. add(ne);
  1387. ne.setHalfedge(nhe);
  1388. nhe.setEdge(ne);
  1389. phe.setEdge(ne);
  1390. }
  1391. cycleHalfedges(newHalfedges, HE_CycleOption.REVERSE);
  1392. }
  1393. return caps;
  1394. }
  1395. /**
  1396. * Clean all mesh elements not used by any faces.
  1397. *
  1398. * @return self
  1399. */
  1400. public HE_Mesh cleanUnusedElementsByFace() {
  1401. final ArrayList<HE_Vertex> cleanedVertices = new ArrayList<HE_Vertex>();
  1402. final ArrayList<HE_Halfedge> cleanedHalfedges = new ArrayList<HE_Halfedge>();
  1403. final ArrayList<HE_Edge> cleanedEdges = new ArrayList<HE_Edge>();
  1404. HE_Halfedge he;
  1405. HE_Edge e;
  1406. HE_Face f;
  1407. final Iterator<HE_Face> fItr = fItr();
  1408. while (fItr.hasNext()) {
  1409. f = fItr.next();
  1410. he = f.getHalfedge();
  1411. do {
  1412. if (!cleanedVertices.contains(he.getVertex())) {
  1413. cleanedVertices.add(he.getVertex());
  1414. }
  1415. if (!cleanedHalfedges.contains(he)) {
  1416. cleanedHalfedges.add(he);
  1417. }
  1418. // if (!cleanedHalfedges.contains(he.pair())) {
  1419. // cleanedHalfedges.add(he.pair());
  1420. // }
  1421. he.clearEdge();
  1422. // he.pair().clearEdge();
  1423. he = he.getNextInFace();
  1424. } while (he != f.getHalfedge());
  1425. }
  1426. final int n = cleanedHalfedges.size();
  1427. for (int i = 0; i < n; i++) {
  1428. he = cleanedHalfedges.get(i);
  1429. if (!cleanedHalfedges.contains(he.getPair())) {
  1430. he.clearPair();
  1431. he.getVertex().setHalfedge(he);
  1432. } else {
  1433. if (he.getEdge() == null) {
  1434. e = new HE_Edge();
  1435. e.setHalfedge(he);
  1436. he.setEdge(e);
  1437. he.getPair().setEdge(e);
  1438. cleanedEdges.add(e);
  1439. }
  1440. }
  1441. }
  1442. replaceVertices(cleanedVertices);
  1443. replaceHalfedges(cleanedHalfedges);
  1444. replaceEdges(cleanedEdges);
  1445. return this;
  1446. }
  1447. // MESH OPERATIONS
  1448. /**
  1449. * Reverse all faces. Flips normals.
  1450. *
  1451. */
  1452. public HE_Mesh flipAllFaces() {
  1453. HE_Edge edge;
  1454. HE_Halfedge he1;
  1455. HE_Halfedge he2;
  1456. HE_Vertex tmp;
  1457. HE_Halfedge[] prevHe;
  1458. HE_Halfedge he;
  1459. final Iterator<HE_Edge> eItr = eItr();
  1460. while (eItr.hasNext()) {
  1461. edge = eItr.next();
  1462. he1 = edge.getHalfedge();
  1463. he2 = he1.getPair();
  1464. tmp = he1.getVertex();
  1465. he1.setVertex(he2.getVertex());
  1466. he2.setVertex(tmp);
  1467. he1.getVertex().setHalfedge(he1);
  1468. he2.getVertex().setHalfedge(he2);
  1469. }
  1470. prevHe = new HE_Halfedge[numberOfHalfedges()];
  1471. int i = 0;
  1472. Iterator<HE_Halfedge> heItr = heItr();
  1473. while (heItr.hasNext()) {
  1474. he = heItr.next();
  1475. prevHe[i] = he.getPrevInFace();
  1476. i++;
  1477. }
  1478. i = 0;
  1479. heItr = heItr();
  1480. while (heItr.hasNext()) {
  1481. he = heItr.next();
  1482. he.setNext(prevHe[i]);
  1483. i++;
  1484. }
  1485. return this;
  1486. }
  1487. /**
  1488. * Collapse edge. End vertices are averaged.
  1489. *
  1490. * @param e
  1491. * edge to collapse
  1492. */
  1493. public void collapseEdge(final HE_Edge e) {
  1494. if (contains(e)) {
  1495. final HE_Halfedge he = e.getHalfedge();
  1496. final HE_Vertex v = he.getVertex();
  1497. final HE_Halfedge hePair = e.getHalfedge().getPair();
  1498. final HE_Vertex vp = hePair.getVertex();
  1499. vp.add(v).div(2);
  1500. final ArrayList<HE_Halfedge> tmp = v.getHalfedgeStar();
  1501. for (int i = 0; i < tmp.size(); i++) {
  1502. tmp.get(i).setVertex(vp);
  1503. }
  1504. final HE_Halfedge hen = he.getNextInFace();
  1505. final HE_Halfedge hep = he.getPrevInFace();
  1506. final HE_Halfedge hePairn = hePair.getNextInFace();
  1507. final HE_Halfedge hePairp = hePair.getPrevInFace();
  1508. if (he.getFace() != null) {
  1509. he.getFace().setHalfedge(hen);
  1510. }
  1511. if (hePair.getFace() != null) {
  1512. hePair.getFace().setHalfedge(hePairn);
  1513. }
  1514. hep.setNext(hen);
  1515. hePairp.setNext(hePairn);
  1516. remove(he);
  1517. remove(hePair);
  1518. remove(e);
  1519. remove(v);
  1520. if (hen.getNextInFace() == hep) { // if face only contains 2 edges,
  1521. // remove
  1522. // face
  1523. hePairp.setPair(hePairn);
  1524. remove(hePairp.getEdge());
  1525. hePairp.setEdge(hePairn.getEdge());
  1526. remove(hep.getFace());
  1527. remove(hep);
  1528. remove(hen);
  1529. }
  1530. }
  1531. }
  1532. /**
  1533. * Collapse all zero-length edges.
  1534. *
  1535. */
  1536. public void collapseDegenerateEdges() {
  1537. final ArrayList<HE_Edge> edgesToRemove = new ArrayList<HE_Edge>();
  1538. final Iterator<HE_Edge> eItr = eItr();
  1539. HE_Edge e;
  1540. while (eItr.hasNext()) {
  1541. e = eItr.next();
  1542. if (WB_Epsilon.isZeroSq(WB_Distance.sqDistance(e.getStartVertex(),
  1543. e.getEndVertex()))) {
  1544. edgesToRemove.add(e);
  1545. }
  1546. }
  1547. for (int i = 0; i < edgesToRemove.size(); i++) {
  1548. collapseEdge(edgesToRemove.get(i));
  1549. }
  1550. }
  1551. /**
  1552. * Delete face and remove all references.
  1553. *
  1554. * @param f face to delete
  1555. */
  1556. public void deleteFace(final HE_Face f) {
  1557. HE_Halfedge he = f.getHalfedge();
  1558. do {
  1559. he.clearFace();
  1560. he = he.getNextInFace();
  1561. } while (he != f.getHalfedge());
  1562. remove(f);
  1563. }
  1564. /**
  1565. * Delete edge. Adjacent faces are fused.
  1566. *
  1567. * @param e
  1568. * edge to delete
  1569. * @return fused face (or null)
  1570. */
  1571. public HE_Face deleteEdge(final HE_Edge e) {
  1572. HE_Face f = null;
  1573. final HE_Halfedge he1 = e.getHalfedge();
  1574. final HE_Halfedge he2 = e.getHalfedge().getPair();
  1575. final HE_Halfedge he1n = e.getHalfedge().getNextInFace();
  1576. final HE_Halfedge he2n = e.getHalfedge().getPair().getNextInFace();
  1577. final HE_Halfedge he1p = e.getHalfedge().getPrevInFace();
  1578. final HE_Halfedge he2p = e.getHalfedge().getPair().getPrevInFace();
  1579. he1p.setNext(he2n);
  1580. he2p.setNext(he1n);
  1581. HE_Vertex v = he1.getVertex();
  1582. if (v.getHalfedge() == he1) {
  1583. v.setHalfedge(he1.getNextInVertex());
  1584. }
  1585. v = he2.getVertex();
  1586. if (v.getHalfedge() == he2) {
  1587. v.setHalfedge(he2.getNextInVertex());
  1588. }
  1589. if ((e.getFirstFace() != null) && (e.getSecondFace() != null)) {
  1590. f = new HE_Face();
  1591. add(f);
  1592. f.setHalfedge(he1p);
  1593. HE_Halfedge he = he1p;
  1594. do {
  1595. he.setFace(f);
  1596. he = he.getNextInFace();
  1597. } while (he != he1p);
  1598. }
  1599. if (e.getFirstFace() != null) {
  1600. remove(e.getFirstFace());
  1601. }
  1602. if (e.getSecondFace() != null) {
  1603. remove(e.getSecondFace());
  1604. }
  1605. remove(he1);
  1606. remove(he2);
  1607. remove(e);
  1608. return f;
  1609. }
  1610. /**
  1611. * Insert vertex in edge.
  1612. *
  1613. * @param edge edge to split
  1614. * @param v position of new vertex
  1615. * @return selection of new vertex and new edge
  1616. */
  1617. public HE_Selection splitEdge(final HE_Edge edge, final WB_Point v) {
  1618. final HE_Selection out = new HE_Selection(this);
  1619. final HE_Halfedge he0 = edge.getHalfedge();
  1620. final HE_Halfedge he1 = he0.getPair();
  1621. final HE_Vertex vNew = new HE_Vertex(v);
  1622. final HE_Halfedge he0new = new HE_Halfedge();
  1623. final HE_Halfedge he1new = new HE_Halfedge();
  1624. he0new.setVertex(vNew);
  1625. he1new.setVertex(vNew);
  1626. vNew.setHalfedge(he0new);
  1627. he0new.setNext(he0.getNextInFace());
  1628. he1new.setNext(he1.getNextInFace());
  1629. he0.setNext(he0new);
  1630. he1.setNext(he1new);
  1631. he0.setPair(he1new);
  1632. he0new.setPair(he1);
  1633. final HE_Edge edgeNew = new HE_Edge();
  1634. edgeNew.label = edge.label;
  1635. edgeNew.setHalfedge(he0new);
  1636. he1new.setEdge(edge);
  1637. he1.setEdge(edgeNew);
  1638. he0new.setEdge(edgeNew);
  1639. if (he0.getFace() != null) {
  1640. he0new.setFace(he0.getFace());
  1641. }
  1642. if (he1.getFace() != null) {
  1643. he1new.setFace(he1.getFace());
  1644. }
  1645. vNew.setLabel(1);
  1646. add(vNew);
  1647. add(he0new);
  1648. add(he1new);
  1649. add(edgeNew);
  1650. out.add(vNew);
  1651. out.add(edgeNew);
  1652. return out;
  1653. }
  1654. /**
  1655. * Insert vertex in edge.
  1656. *
  1657. * @param key key of edge to split
  1658. * @param v position of new vertex
  1659. * @return selection of new vertex and new edge
  1660. */
  1661. public HE_Selection splitEdge(final Integer key, final WB_Point v) {
  1662. final HE_Edge edge = getEdgeByKey(key);
  1663. return splitEdge(edge, v);
  1664. }
  1665. /**
  1666. * Insert vertex in edge.
  1667. *
  1668. * @param edge
  1669. * edge to split
  1670. * @param x
  1671. * x-coordinate of new vertex
  1672. * @param y
  1673. * y-coordinate of new vertex
  1674. * @param z
  1675. * z-coordinate of new vertex
  1676. */
  1677. public void splitEdge(final HE_Edge edge, final double x, final double y,
  1678. final double z) {
  1679. splitEdge(edge, new WB_Point(x, y, z));
  1680. }
  1681. /**
  1682. * Insert vertex in edge.
  1683. *
  1684. * @param key
  1685. * key of edge to split
  1686. * @param x
  1687. * x-coordinate of new vertex
  1688. * @param y
  1689. * y-coordinate of new vertex
  1690. * @param z
  1691. * z-coordinate of new vertex
  1692. */
  1693. public void splitEdge(final Integer key, final double x, final double y,
  1694. final double z) {
  1695. splitEdge(key, new WB_Point(x, y, z));
  1696. }
  1697. /**
  1698. * Split edge in half.
  1699. *
  1700. * @param edge edge to split.
  1701. * @return selection of new vertex and new edge
  1702. */
  1703. public HE_Selection splitEdge(final HE_Edge edge) {
  1704. final WB_Point v = edge.getStartVertex()
  1705. .addAndCopy(edge.getEndVertex());
  1706. v.mult(0.5);
  1707. return splitEdge(edge, v);
  1708. }
  1709. /**
  1710. * Split edge in half.
  1711. *
  1712. * @param key key of edge to split.
  1713. * @return selection of new vertex and new edge
  1714. */
  1715. public HE_Selection splitEdge(final Integer key) {
  1716. final HE_Edge edge = getEdgeByKey(key);
  1717. final WB_Point v = edge.getStartVertex()
  1718. .addAndCopy(edge.getEndVertex());
  1719. v.mult(0.5);
  1720. return splitEdge(edge, v);
  1721. }
  1722. /**
  1723. * Split edge in two parts.
  1724. *
  1725. * @param edge edge to split
  1726. * @param f fraction of first part (0..1)
  1727. * @return selection of new vertex and new edge
  1728. */
  1729. public HE_Selection splitEdge(final HE_Edge edge, final double f) {
  1730. final WB_Point v = WB_Point.interpolate(edge.getStartVertex(),
  1731. edge.getEndVertex(), f);
  1732. return splitEdge(edge, v);
  1733. }
  1734. /**
  1735. * Split edge in two parts.
  1736. *
  1737. * @param key key of edge to split
  1738. * @param f fraction of first part (0..1)
  1739. * @return selection of new vertex and new edge
  1740. */
  1741. public HE_Selection splitEdge(final Integer key, final double f) {
  1742. final HE_Edge edge = getEdgeByKey(key);
  1743. return splitEdge(edge, f);
  1744. }
  1745. /**
  1746. * Split all edges in half.
  1747. *
  1748. * @return selection of new vertices and new edges
  1749. */
  1750. public HE_Selection splitEdges() {
  1751. final HE_Selection selectionOut = new HE_Selection(this);
  1752. final HE_Edge[] edges = getEdgesAsArray();
  1753. final int n = numberOfEdges();
  1754. for (int i = 0; i < n; i++) {
  1755. selectionOut.union(splitEdge(edges[i], 0.5));
  1756. }
  1757. return selectionOut;
  1758. }
  1759. /**
  1760. * Split all edges in half, offset the center by a given distance along the edge normal.
  1761. *
  1762. * @param offset
  1763. * @return selection of new vertices and new edges
  1764. */
  1765. public HE_Selection splitEdges(final double offset) {
  1766. final HE_Selection selectionOut = new HE_Selection(this);
  1767. final HE_Edge[] edges = getEdgesAsArray();
  1768. final int n = numberOfEdges();
  1769. for (int i = 0; i < n; i++) {
  1770. final WB_Point p = new WB_Point(edges[i].getEdgeNormal());
  1771. p.mult(offset).add(edges[i].getEdgeCenter());
  1772. selectionOut.union(splitEdge(edges[i], p));
  1773. }
  1774. return selectionOut;
  1775. }
  1776. /**
  1777. * Split edge in half.
  1778. *
  1779. * @param selection edges to split.
  1780. * @return selection of new vertices and new edges
  1781. */
  1782. public HE_Selection splitEdges(final HE_Selection selection) {
  1783. final HE_Selection selectionOut = new HE_Selection(this);
  1784. selection.collectEdges();
  1785. final Iterator<HE_Edge> eItr = selection.eItr();
  1786. while (eItr.hasNext()) {
  1787. selectionOut.union(splitEdge(eItr.next(), 0.5));
  1788. }
  1789. selection.addEdges(selectionOut.getEdgesAsArray());
  1790. return selectionOut;
  1791. }
  1792. /**
  1793. * Split edge in half, offset the center by a given distance along the edge normal.
  1794. *
  1795. * @param offset
  1796. * @param selection edges to split.
  1797. * @return selection of new vertices and new edges
  1798. */
  1799. public HE_Selection splitEdges(final HE_Selection selection,
  1800. final double offset) {
  1801. final HE_Selection selectionOut = new HE_Selection(this);
  1802. selection.collectEdges();
  1803. final Iterator<HE_Edge> eItr = selection.eItr();
  1804. HE_Edge e;
  1805. while (eItr.hasNext()) {
  1806. e = eItr.next();
  1807. final WB_Point p = new WB_Point(e.getEdgeNormal());
  1808. p.mult(offset).add(e.getEdgeCenter());
  1809. selectionOut.union(splitEdge(e, p));
  1810. }
  1811. selection.addEdges(selectionOut.getEdgesAsArray());
  1812. return selectionOut;
  1813. }
  1814. /**
  1815. * Split edge in multiple parts.
  1816. *
  1817. * @param edge
  1818. * edge to split
  1819. * @param f
  1820. * array of fractions (0..1)
  1821. */
  1822. public void splitEdge(final HE_Edge edge, final double[] f) {
  1823. final double[] fArray = Arrays.copyOf(f, f.length);
  1824. Arrays.sort(fArray);
  1825. HE_Edge e = edge;
  1826. final HE_Halfedge he0 = edge.getHalfedge();
  1827. final HE_Halfedge he1 = he0.getPair();
  1828. final HE_Vertex v0 = he0.getVertex();
  1829. final HE_Vertex v1 = he1.getVertex();
  1830. HE_Vertex v = new HE_Vertex();
  1831. for (int i = 0; i < f.length; i++) {
  1832. final double fi = fArray[i];
  1833. if ((fi > 0) && (fi < 1)) {
  1834. v = new HE_Vertex(WB_XYZ.interpolate(v0, v1, fi));
  1835. e = (splitEdge(e, v).eItr().next());
  1836. }
  1837. }
  1838. }
  1839. /**
  1840. * Split edge in multiple parts.
  1841. *
  1842. * @param key
  1843. * key of edge to split
  1844. * @param f
  1845. * array of fractions (0..1)
  1846. */
  1847. public void splitEdge(final Integer key, final double[] f) {
  1848. final HE_Edge edge = getEdgeByKey(key);
  1849. splitEdge(edge, f);
  1850. }
  1851. /**
  1852. * Split edge in multiple parts.
  1853. *
  1854. * @param edge
  1855. * edge to split
  1856. * @param f
  1857. * array of fractions (0..1)
  1858. */
  1859. public void splitEdge(final HE_Edge edge, final float[] f) {
  1860. final float[] fArray = Arrays.copyOf(f, f.length);
  1861. Arrays.sort(fArray);
  1862. HE_Edge e = edge;
  1863. final HE_Halfedge he0 = edge.getHalfedge();
  1864. final HE_Halfedge he1 = he0.getPair();
  1865. final HE_Vertex v0 = he0.getVertex();
  1866. final HE_Vertex v1 = he1.getVertex();
  1867. HE_Vertex v = new HE_Vertex();
  1868. for (int i = 0; i < f.length; i++) {
  1869. final double fi = fArray[i];
  1870. if ((fi > 0) && (fi < 1)) {
  1871. v = new HE_Vertex(WB_XYZ.interpolate(v0, v1, fi));
  1872. e = (splitEdge(e, v).eItr().next());
  1873. }
  1874. }
  1875. }
  1876. /**
  1877. * Split edge in multiple parts.
  1878. *
  1879. * @param key
  1880. * key of edge to split
  1881. * @param f
  1882. * array of fractions (0..1)
  1883. */
  1884. public void splitEdge(final Integer key, final float[] f) {
  1885. final HE_Edge edge = getEdgeByKey(key);
  1886. splitEdge(edge, f);
  1887. }
  1888. /**
  1889. * Divide edge.
  1890. *
  1891. * @param origE
  1892. * edge to divide
  1893. * @param n
  1894. * number of parts
  1895. */
  1896. public void divideEdge(final HE_Edge origE, final int n) {
  1897. if (n > 1) {
  1898. final double[] f = new double[n - 1];
  1899. final double in = 1.0 / n;
  1900. for (int i = 0; i < n - 1; i++) {
  1901. f[i] = (i + 1) * in;
  1902. }
  1903. splitEdge(origE, f);
  1904. }
  1905. }
  1906. /**
  1907. * Divide edge.
  1908. *
  1909. * @param key
  1910. * key of edge to divide
  1911. * @param n
  1912. * number of parts
  1913. */
  1914. public void divideEdge(final Integer key, final int n) {
  1915. final HE_Edge edge = getEdgeByKey(key);
  1916. divideEdge(edge, n);
  1917. }
  1918. /**
  1919. * Find halfedge shared by vertex and face.
  1920. *
  1921. * @param f face
  1922. * @param v vertex
  1923. * @return halfedge
  1924. */
  1925. private HE_Halfedge findHalfedge(final HE_Face f, final HE_Vertex v) {
  1926. HE_Halfedge he = f.getHalfedge();
  1927. do {
  1928. if (he.getVertex() == v) {
  1929. return he;
  1930. }
  1931. he = he.getNextInFace();
  1932. } while (he != f.getHalfedge());
  1933. return null;
  1934. }
  1935. /**
  1936. * Divide face along two vertices.
  1937. *
  1938. * @param face face to divide
  1939. * @param vi first vertex
  1940. * @param vj second vertex
  1941. * @return new face and edge
  1942. */
  1943. public HE_Selection splitFace(final HE_Face face, final HE_Vertex vi,
  1944. final HE_Vertex vj) {
  1945. final HE_Selection out = new HE_Selection(this);
  1946. final HE_Halfedge hei = findHalfedge(face, vi);
  1947. final HE_Halfedge hej = findHalfedge(face, vj);
  1948. HE_Halfedge heiPrev;
  1949. HE_Halfedge hejPrev;
  1950. HE_Halfedge he0new;
  1951. HE_Halfedge he1new;
  1952. HE_Edge edgeNew;
  1953. HE_Face faceNew;
  1954. HE_Halfedge he;
  1955. if ((hei.getNextInFace() != hej) || (hei.getPrevInFace() != hej)) {
  1956. heiPrev = hei.getPrevInFace();
  1957. hejPrev = hej.getPrevInFace();
  1958. he0new = new HE_Halfedge();
  1959. he1new = new HE_Halfedge();
  1960. he0new.setVertex(vj);
  1961. he1new.setVertex(vi);
  1962. he0new.setNext(hei);
  1963. he1new.setNext(hej);
  1964. heiPrev.setNext(he1new);
  1965. hejPrev.setNext(he0new);
  1966. he0new.setPair(he1new);
  1967. edgeNew = new HE_Edge();
  1968. edgeNew.setHalfedge(he0new);
  1969. he0new.setEdge(edgeNew);
  1970. he1new.setEdge(edgeNew);
  1971. he0new.setFace(face);
  1972. faceNew = new HE_Face();
  1973. face.setHalfedge(hei);
  1974. faceNew.setHalfedge(hej);
  1975. faceNew.label = face.label;
  1976. assignFaceToLoop(faceNew, hej);
  1977. add(he0new);
  1978. add(he1new);
  1979. add(edgeNew);
  1980. add(faceNew);
  1981. out.add(edgeNew);
  1982. out.add(faceNew);
  1983. he = face.getHalfedge();
  1984. do {
  1985. he = he.getNextInFace();
  1986. } while (he != face.getHalfedge());
  1987. return out;
  1988. }
  1989. return null;
  1990. }
  1991. /**
  1992. * Divide face along two vertices.
  1993. *
  1994. * @param fkey key of face
  1995. * @param vkeyi key of first vertex
  1996. * @param vkeyj key of second vertex
  1997. * @return new face and edge
  1998. */
  1999. public HE_Selection splitFace(final Integer fkey, final Integer vkeyi,
  2000. final Integer vkeyj) {
  2001. return splitFace(getFaceByKey(fkey), getVertexByKey(vkeyi),
  2002. getVertexByKey(vkeyj));
  2003. }
  2004. /**
  2005. * Tri split face.
  2006. *
  2007. * @param face face
  2008. * @param v new vertex
  2009. * @return selection of new faces and new vertex
  2010. */
  2011. public HE_Selection triSplitFace(final HE_Face face, final WB_Point v) {
  2012. HE_Halfedge he = face.getHalfedge();
  2013. final HE_Vertex vi = new HE_Vertex(v);
  2014. vi.setLabel(2);
  2015. final HE_Selection out = new HE_Selection(this);
  2016. int c = 0;
  2017. boolean onEdge = false;
  2018. do {
  2019. c++;
  2020. final WB_Plane P = new WB_Plane(he.getHalfedgeCenter(),
  2021. he.getHalfedgeNormal());
  2022. final double d = WB_Distance.distance(v, P);
  2023. if (WB_Epsilon.isZero(d)) {
  2024. onEdge = true;
  2025. break;
  2026. }
  2027. he = he.getNextInFace();
  2028. } while (he != face.getHalfedge());
  2029. if (!onEdge) {
  2030. add(vi);
  2031. final HE_Halfedge[] he0 = new HE_Halfedge[c];
  2032. final HE_Halfedge[] he1 = new HE_Halfedge[c];
  2033. final HE_Halfedge[] he2 = new HE_Halfedge[c];
  2034. c = 0;
  2035. do {
  2036. HE_Face f;
  2037. if (c == 0) {
  2038. f = face;
  2039. } else {
  2040. f = new HE_Face();
  2041. f.label = face.label;
  2042. add(f);
  2043. out.add(f);
  2044. }
  2045. he0[c] = he;
  2046. he.setFace(f);
  2047. f.setHalfedge(he);
  2048. he1[c] = new HE_Halfedge();
  2049. he2[c] = new HE_Halfedge();
  2050. add(he1[c]);
  2051. add(he2[c]);
  2052. he1[c].setVertex(he.getNextInFace().getVertex());
  2053. he2[c].setVertex(vi);
  2054. he1[c].setNext(he2[c]);
  2055. he2[c].setNext(he);
  2056. he1[c].setFace(f);
  2057. he2[c].setFace(f);
  2058. c++;
  2059. he = he.getNextInFace();
  2060. } while (he != face.getHalfedge());
  2061. vi.setHalfedge(he2[0]);
  2062. for (int i = 0; i < c; i++) {
  2063. he0[i].setNext(he1[i]);
  2064. he1[i].setPair(he2[i == c - 1 ? 0 : i + 1]);
  2065. final HE_Edge e = new HE_Edge();
  2066. add(e);
  2067. e.setHalfedge(he1[i]);
  2068. he1[i].setEdge(e);
  2069. he1[i].getPair().setEdge(e);
  2070. }
  2071. out.add(vi);
  2072. return out;
  2073. }
  2074. return null;
  2075. }
  2076. /**
  2077. * Tri split face.
  2078. *
  2079. * @param face face
  2080. * @param x x-coordinate of new vertex
  2081. * @param y y-coordinate of new vertex
  2082. * @param z z-coordinate of new vertex
  2083. * @return selection of new faces and new vertex
  2084. */
  2085. public HE_Selection triSplitFace(final HE_Face face, final double x,
  2086. final double y, final double z) {
  2087. return triSplitFace(face, new WB_Point(x, y, z));
  2088. }
  2089. /**
  2090. * Tri split face.
  2091. *
  2092. * @param face face
  2093. * @return selection of new faces and new vertex
  2094. */
  2095. public HE_Selection triSplitFace(final HE_Face face) {
  2096. return triSplitFace(face, face.getFaceCenter());
  2097. }
  2098. /**
  2099. * Tri split face with offset along face normal.
  2100. *
  2101. * @param face face
  2102. * @param d offset along face normal
  2103. * @return selection of new faces and new vertex
  2104. */
  2105. public HE_Selection triSplitFace(final HE_Face face, final double d) {
  2106. return triSplitFace(face,
  2107. face.getFaceCenter().add(face.getFaceNormal(), d));
  2108. }
  2109. /**
  2110. * Tri split faces with offset along face normal.
  2111. *
  2112. * @param d offset along face normal
  2113. * @return selection of new faces and new vertex
  2114. */
  2115. public HE_Selection triSplitFaces(final double d) {
  2116. final HE_Selection selectionOut = new HE_Selection(this);
  2117. final HE_Face[] faces = getFacesAsArray();
  2118. final int n = numberOfFaces();
  2119. for (int i = 0; i < n; i++) {
  2120. selectionOut.union(triSplitFace(faces[i], d));
  2121. }
  2122. return selectionOut;
  2123. }
  2124. /**
  2125. * Tri split faces.
  2126. *
  2127. * @return selection of new faces and new vertex
  2128. */
  2129. public HE_Selection triSplitFaces() {
  2130. final HE_Selection selectionOut = new HE_Selection(this);
  2131. final HE_Face[] faces = getFacesAsArray();
  2132. final int n = numberOfFaces();
  2133. for (int i = 0; i < n; i++) {
  2134. selectionOut.union(triSplitFace(faces[i]));
  2135. }
  2136. return selectionOut;
  2137. }
  2138. /**
  2139. * Tri split faces.
  2140. *
  2141. * @param selection face selection to split
  2142. * @return selection of new faces and new vertex
  2143. */
  2144. public HE_Selection triSplitFaces(final HE_Selection selection) {
  2145. final HE_Selection selectionOut = new HE_Selection(this);
  2146. final HE_Face[] faces = selection.getFacesAsArray();
  2147. final int n = selection.numberOfFaces();
  2148. for (int i = 0; i < n; i++) {
  2149. selectionOut.union(triSplitFace(faces[i]));
  2150. }
  2151. selection.union(selectionOut);
  2152. return selectionOut;
  2153. }
  2154. /**
  2155. * Tri split faces with offset along face normal.
  2156. *
  2157. * @param d offset along face normal
  2158. * @param selection face selection to split
  2159. * @return selection of new faces and new vertex
  2160. */
  2161. public HE_Selection triSplitFaces(final HE_Selection selection,
  2162. final double d) {
  2163. final HE_Selection selectionOut = new HE_Selection(this);
  2164. final HE_Face[] faces = selection.getFacesAsArray();
  2165. final int n = selection.numberOfFaces();
  2166. for (int i = 0; i < n; i++) {
  2167. selectionOut.union(triSplitFace(faces[i], d));
  2168. }
  2169. selection.union(selectionOut);
  2170. return selectionOut;
  2171. }
  2172. /**
  2173. * Split face by connecting all face vertices with new vertex.
  2174. *
  2175. * @param key key of face
  2176. * @param v position of new vertex
  2177. * @return selection of new faces and new vertex
  2178. */
  2179. public HE_Selection triSplitFace(final Integer key, final WB_Point v) {
  2180. return triSplitFace(getFaceByKey(key), v);
  2181. }
  2182. /**
  2183. * Split face by connecting all face vertices with new vertex.
  2184. *
  2185. * @param key key of face
  2186. * @param x x-coordinate of new vertex
  2187. * @param y y-coordinate of new vertex
  2188. * @param z z-coordinate of new vertex
  2189. * @return selection of new faces and new vertex
  2190. */
  2191. public HE_Selection triSplitFace(final Integer key, final double x,
  2192. final double y, final double z) {
  2193. return triSplitFace(getFaceByKey(key), new WB_Point(x, y, z));
  2194. }
  2195. /**
  2196. * Quad split faces.
  2197. *
  2198. * @return selection of new faces and new vertices
  2199. */
  2200. public HE_Selection quadSplitFaces() {
  2201. final HE_Selection selectionOut = new HE_Selection(this);
  2202. final int n = numberOfFaces();
  2203. final WB_Point[] faceCenters = new WB_Point[n];
  2204. final int[] faceOrders = new int[n];
  2205. HE_Face f;
  2206. int i = 0;
  2207. final Iterator<HE_Face> fItr = fItr();
  2208. while (fItr.hasNext()) {
  2209. f = fItr.next();
  2210. faceCenters[i] = f.getFaceCenter();
  2211. faceOrders[i] = f.getFaceOrder();
  2212. i++;
  2213. }
  2214. final HE_Selection orig = new HE_Selection(this);
  2215. orig.addFaces(getFacesAsArray());
  2216. orig.collectVertices();
  2217. orig.collectEdges();
  2218. selectionOut.addVertices(splitEdges().getVerticesAsArray());
  2219. final HE_Face[] faces = getFacesAsArray();
  2220. HE_Vertex vi = new HE_Vertex();
  2221. for (i = 0; i < n; i++) {
  2222. f = faces[i];
  2223. vi = new HE_Vertex(faceCenters[i]);
  2224. vi.setLabel(2);
  2225. add(vi);
  2226. selectionOut.add(vi);
  2227. HE_Halfedge startHE = f.getHalfedge();
  2228. while (orig.contains(startHE.getVertex())) {
  2229. startHE = startHE.getNextInFace();
  2230. }
  2231. HE_Halfedge he = startHE;
  2232. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2233. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2234. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2235. final HE_Halfedge[] he3 = new HE_Halfedge[faceOrders[i]];
  2236. int c = 0;
  2237. do {
  2238. HE_Face fc;
  2239. if (c == 0) {
  2240. fc = f;
  2241. } else {
  2242. fc = new HE_Face();
  2243. fc.label = f.label;
  2244. add(fc);
  2245. }
  2246. he0[c] = he;
  2247. he.setFace(fc);
  2248. fc.setHalfedge(he);
  2249. he1[c] = he.getNextInFace();
  2250. he2[c] = new HE_Halfedge();
  2251. he3[c] = new HE_Halfedge();
  2252. add(he2[c]);
  2253. add(he3[c]);
  2254. he2[c].setVertex(he.getNextInFace().getNextInFace().getVertex());
  2255. he3[c].setVertex(vi);
  2256. he2[c].setNext(he3[c]);
  2257. he3[c].setNext(he);
  2258. he1[c].setFace(fc);
  2259. he2[c].setFace(fc);
  2260. he3[c].setFace(fc);
  2261. c++;
  2262. he = he.getNextInFace().getNextInFace();
  2263. } while (he != startHE);
  2264. vi.setHalfedge(he3[0]);
  2265. for (int j = 0; j < c; j++) {
  2266. he1[j].setNext(he2[j]);
  2267. }
  2268. }
  2269. pairHalfedgesSilent();
  2270. return selectionOut;
  2271. }
  2272. /**
  2273. * Quad split selected faces.
  2274. *
  2275. * @param sel selection to split
  2276. * @return selection of new faces and new vertices
  2277. */
  2278. public HE_Selection quadSplitFaces(final HE_Selection sel) {
  2279. final HE_Selection selectionOut = new HE_Selection(this);
  2280. final int n = sel.numberOfFaces();
  2281. final WB_Point[] faceCenters = new WB_Point[n];
  2282. final int[] faceOrders = new int[n];
  2283. HE_Face face;
  2284. final Iterator<HE_Face> fItr = sel.fItr();
  2285. int i = 0;
  2286. while (fItr.hasNext()) {
  2287. face = fItr.next();
  2288. faceCenters[i] = face.getFaceCenter();
  2289. faceOrders[i] = face.getFaceOrder();
  2290. i++;
  2291. }
  2292. final HE_Selection orig = new HE_Selection(this);
  2293. orig.addFaces(sel.getFacesAsArray());
  2294. orig.collectVertices();
  2295. orig.collectEdges();
  2296. selectionOut.addVertices(splitEdges(orig).getVerticesAsArray());
  2297. final HE_Face[] faces = sel.getFacesAsArray();
  2298. for (i = 0; i < n; i++) {
  2299. face = faces[i];
  2300. final HE_Vertex vi = new HE_Vertex(faceCenters[i]);
  2301. add(vi);
  2302. vi.setLabel(2);
  2303. selectionOut.add(vi);
  2304. HE_Halfedge startHE = face.getHalfedge();
  2305. while (orig.contains(startHE.getVertex())) {
  2306. startHE = startHE.getNextInFace();
  2307. }
  2308. HE_Halfedge he = startHE;
  2309. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2310. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2311. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2312. final HE_Halfedge[] he3 = new HE_Halfedge[faceOrders[i]];
  2313. int c = 0;
  2314. do {
  2315. HE_Face f;
  2316. if (c == 0) {
  2317. f = face;
  2318. } else {
  2319. f = new HE_Face();
  2320. add(f);
  2321. f.label = face.label;
  2322. sel.add(f);
  2323. }
  2324. he0[c] = he;
  2325. he.setFace(f);
  2326. f.setHalfedge(he);
  2327. he1[c] = he.getNextInFace();
  2328. he2[c] = new HE_Halfedge();
  2329. he3[c] = new HE_Halfedge();
  2330. add(he2[c]);
  2331. add(he3[c]);
  2332. he2[c].setVertex(he.getNextInFace().getNextInFace().getVertex());
  2333. he3[c].setVertex(vi);
  2334. he2[c].setNext(he3[c]);
  2335. he3[c].setNext(he);
  2336. he1[c].setFace(f);
  2337. he2[c].setFace(f);
  2338. he3[c].setFace(f);
  2339. c++;
  2340. he = he.getNextInFace().getNextInFace();
  2341. } while (he != startHE);
  2342. vi.setHalfedge(he3[0]);
  2343. for (int j = 0; j < c; j++) {
  2344. he1[j].setNext(he2[j]);
  2345. }
  2346. }
  2347. pairHalfedgesSilent();
  2348. return selectionOut;
  2349. }
  2350. /**
  2351. * Hybrid split faces: midsplit for triangles, quad split otherwise.
  2352. *
  2353. * @return selection of new faces and new vertices
  2354. */
  2355. public HE_Selection hybridSplitFaces() {
  2356. final HE_Selection selectionOut = new HE_Selection(this);
  2357. final int n = numberOfFaces();
  2358. final WB_Point[] faceCenters = new WB_Point[n];
  2359. final int[] faceOrders = new int[n];
  2360. HE_Face f;
  2361. int i = 0;
  2362. final Iterator<HE_Face> fItr = fItr();
  2363. while (fItr.hasNext()) {
  2364. f = fItr.next();
  2365. faceCenters[i] = f.getFaceCenter();
  2366. faceOrders[i] = f.getFaceOrder();
  2367. i++;
  2368. }
  2369. final HE_Selection orig = new HE_Selection(this);
  2370. orig.addFaces(getFacesAsArray());
  2371. orig.collectVertices();
  2372. orig.collectEdges();
  2373. selectionOut.addVertices(splitEdges().getVerticesAsArray());
  2374. final HE_Face[] faces = getFacesAsArray();
  2375. HE_Vertex vi = new HE_Vertex();
  2376. for (i = 0; i < n; i++) {
  2377. f = faces[i];
  2378. if (f.getFaceOrder() == 3) {
  2379. HE_Halfedge startHE = f.getHalfedge();
  2380. while (orig.contains(startHE.getVertex())) {
  2381. startHE = startHE.getNextInFace();
  2382. }
  2383. HE_Halfedge he = startHE;
  2384. final HE_Halfedge[] hec = new HE_Halfedge[faceOrders[i]];
  2385. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2386. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2387. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2388. int c = 0;
  2389. do {
  2390. final HE_Face fn = new HE_Face();
  2391. fn.label = f.label;
  2392. add(fn);
  2393. he0[c] = he;
  2394. he.setFace(fn);
  2395. fn.setHalfedge(he);
  2396. he1[c] = he.getNextInFace();
  2397. he2[c] = new HE_Halfedge();
  2398. hec[c] = new HE_Halfedge();
  2399. add(he2[c]);
  2400. add(hec[c]);
  2401. hec[c].setVertex(he.getVertex());
  2402. hec[c].setPair(he2[c]);
  2403. hec[c].setFace(f);
  2404. final HE_Edge e = new HE_Edge();
  2405. add(e);
  2406. e.setHalfedge(hec[c]);
  2407. hec[c].setEdge(e);
  2408. he2[c].setEdge(e);
  2409. he2[c].setVertex(he.getNextInFace().getNextInFace()
  2410. .getVertex());
  2411. he2[c].setNext(he0[c]);
  2412. he1[c].setFace(fn);
  2413. he2[c].setFace(fn);
  2414. c++;
  2415. he = he.getNextInFace().getNextInFace();
  2416. } while (he != startHE);
  2417. f.setHalfedge(hec[0]);
  2418. for (int j = 0; j < c; j++) {
  2419. he1[j].setNext(he2[j]);
  2420. hec[j].setNext(hec[(j + 1) % c]);
  2421. }
  2422. }
  2423. else if (f.getFaceOrder() > 3) {
  2424. vi = new HE_Vertex(faceCenters[i]);
  2425. vi.setLabel(2);
  2426. add(vi);
  2427. selectionOut.add(vi);
  2428. HE_Halfedge startHE = f.getHalfedge();
  2429. while (orig.contains(startHE.getVertex())) {
  2430. startHE = startHE.getNextInFace();
  2431. }
  2432. HE_Halfedge he = startHE;
  2433. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2434. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2435. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2436. final HE_Halfedge[] he3 = new HE_Halfedge[faceOrders[i]];
  2437. int c = 0;
  2438. do {
  2439. HE_Face fc;
  2440. if (c == 0) {
  2441. fc = f;
  2442. } else {
  2443. fc = new HE_Face();
  2444. fc.label = f.label;
  2445. add(fc);
  2446. }
  2447. he0[c] = he;
  2448. he.setFace(fc);
  2449. fc.setHalfedge(he);
  2450. he1[c] = he.getNextInFace();
  2451. he2[c] = new HE_Halfedge();
  2452. he3[c] = new HE_Halfedge();
  2453. add(he2[c]);
  2454. add(he3[c]);
  2455. he2[c].setVertex(he.getNextInFace().getNextInFace()
  2456. .getVertex());
  2457. he3[c].setVertex(vi);
  2458. he2[c].setNext(he3[c]);
  2459. he3[c].setNext(he);
  2460. he1[c].setFace(fc);
  2461. he2[c].setFace(fc);
  2462. he3[c].setFace(fc);
  2463. c++;
  2464. he = he.getNextInFace().getNextInFace();
  2465. } while (he != startHE);
  2466. vi.setHalfedge(he3[0]);
  2467. for (int j = 0; j < c; j++) {
  2468. he1[j].setNext(he2[j]);
  2469. }
  2470. }
  2471. }
  2472. pairHalfedgesSilent();
  2473. return selectionOut;
  2474. }
  2475. /**
  2476. * Hybrid split faces: midsplit for triangles, quad split otherwise.
  2477. *
  2478. * @return selection of new faces and new vertices
  2479. */
  2480. public HE_Selection hybridSplitFaces(final HE_Selection sel) {
  2481. final HE_Selection selectionOut = new HE_Selection(this);
  2482. final int n = sel.numberOfFaces();
  2483. final WB_Point[] faceCenters = new WB_Point[n];
  2484. final int[] faceOrders = new int[n];
  2485. HE_Face f;
  2486. int i = 0;
  2487. final Iterator<HE_Face> fItr = sel.fItr();
  2488. while (fItr.hasNext()) {
  2489. f = fItr.next();
  2490. faceCenters[i] = f.getFaceCenter();
  2491. faceOrders[i] = f.getFaceOrder();
  2492. i++;
  2493. }
  2494. final HE_Selection orig = new HE_Selection(this);
  2495. orig.addFaces(sel.getFacesAsArray());
  2496. orig.collectVertices();
  2497. orig.collectEdges();
  2498. selectionOut.addVertices(splitEdges().getVerticesAsArray());
  2499. final HE_Face[] faces = sel.getFacesAsArray();
  2500. HE_Vertex vi = new HE_Vertex();
  2501. for (i = 0; i < n; i++) {
  2502. f = faces[i];
  2503. if (f.getFaceOrder() == 3) {
  2504. HE_Halfedge startHE = f.getHalfedge();
  2505. while (orig.contains(startHE.getVertex())) {
  2506. startHE = startHE.getNextInFace();
  2507. }
  2508. HE_Halfedge he = startHE;
  2509. final HE_Halfedge[] hec = new HE_Halfedge[faceOrders[i]];
  2510. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2511. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2512. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2513. int c = 0;
  2514. do {
  2515. final HE_Face fn = new HE_Face();
  2516. fn.label = f.label;
  2517. add(fn);
  2518. sel.add(fn);
  2519. he0[c] = he;
  2520. he.setFace(fn);
  2521. fn.setHalfedge(he);
  2522. he1[c] = he.getNextInFace();
  2523. he2[c] = new HE_Halfedge();
  2524. hec[c] = new HE_Halfedge();
  2525. add(he2[c]);
  2526. add(hec[c]);
  2527. hec[c].setVertex(he.getVertex());
  2528. hec[c].setPair(he2[c]);
  2529. hec[c].setFace(f);
  2530. final HE_Edge e = new HE_Edge();
  2531. add(e);
  2532. e.setHalfedge(hec[c]);
  2533. hec[c].setEdge(e);
  2534. he2[c].setEdge(e);
  2535. he2[c].setVertex(he.getNextInFace().getNextInFace()
  2536. .getVertex());
  2537. he2[c].setNext(he0[c]);
  2538. he1[c].setFace(fn);
  2539. he2[c].setFace(fn);
  2540. c++;
  2541. he = he.getNextInFace().getNextInFace();
  2542. } while (he != startHE);
  2543. f.setHalfedge(hec[0]);
  2544. for (int j = 0; j < c; j++) {
  2545. he1[j].setNext(he2[j]);
  2546. hec[j].setNext(hec[(j + 1) % c]);
  2547. }
  2548. }
  2549. else if (f.getFaceOrder() > 3) {
  2550. vi = new HE_Vertex(faceCenters[i]);
  2551. vi.setLabel(2);
  2552. add(vi);
  2553. selectionOut.add(vi);
  2554. HE_Halfedge startHE = f.getHalfedge();
  2555. while (orig.contains(startHE.getVertex())) {
  2556. startHE = startHE.getNextInFace();
  2557. }
  2558. HE_Halfedge he = startHE;
  2559. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2560. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2561. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2562. final HE_Halfedge[] he3 = new HE_Halfedge[faceOrders[i]];
  2563. int c = 0;
  2564. do {
  2565. HE_Face fc;
  2566. if (c == 0) {
  2567. fc = f;
  2568. } else {
  2569. fc = new HE_Face();
  2570. fc.label = f.label;
  2571. add(fc);
  2572. sel.add(fc);
  2573. }
  2574. he0[c] = he;
  2575. he.setFace(fc);
  2576. fc.setHalfedge(he);
  2577. he1[c] = he.getNextInFace();
  2578. he2[c] = new HE_Halfedge();
  2579. he3[c] = new HE_Halfedge();
  2580. add(he2[c]);
  2581. add(he3[c]);
  2582. he2[c].setVertex(he.getNextInFace().getNextInFace()
  2583. .getVertex());
  2584. he3[c].setVertex(vi);
  2585. he2[c].setNext(he3[c]);
  2586. he3[c].setNext(he);
  2587. he1[c].setFace(fc);
  2588. he2[c].setFace(fc);
  2589. he3[c].setFace(fc);
  2590. c++;
  2591. he = he.getNextInFace().getNextInFace();
  2592. } while (he != startHE);
  2593. vi.setHalfedge(he3[0]);
  2594. for (int j = 0; j < c; j++) {
  2595. he1[j].setNext(he2[j]);
  2596. }
  2597. }
  2598. }
  2599. pairHalfedgesSilent();
  2600. return selectionOut;
  2601. }
  2602. /**
  2603. * Mid split faces.
  2604. *
  2605. * @return selection of new faces and new vertices
  2606. */
  2607. public HE_Selection midSplitFaces() {
  2608. final HE_Selection selectionOut = new HE_Selection(this);
  2609. final int n = numberOfFaces();
  2610. final int[] faceOrders = new int[n];
  2611. HE_Face face;
  2612. int i = 0;
  2613. final Iterator<HE_Face> fItr = fItr();
  2614. while (fItr.hasNext()) {
  2615. face = fItr.next();
  2616. faceOrders[i] = face.getFaceOrder();
  2617. i++;
  2618. }
  2619. final HE_Selection orig = new HE_Selection(this);
  2620. orig.addFaces(getFacesAsArray());
  2621. orig.collectVertices();
  2622. orig.collectEdges();
  2623. selectionOut.addVertices(splitEdges().getVerticesAsArray());
  2624. final HE_Face[] faces = getFacesAsArray();
  2625. for (i = 0; i < n; i++) {
  2626. face = faces[i];
  2627. HE_Halfedge startHE = face.getHalfedge();
  2628. while (orig.contains(startHE.getVertex())) {
  2629. startHE = startHE.getNextInFace();
  2630. }
  2631. HE_Halfedge he = startHE;
  2632. final HE_Halfedge[] hec = new HE_Halfedge[faceOrders[i]];
  2633. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2634. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2635. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2636. int c = 0;
  2637. do {
  2638. final HE_Face f = new HE_Face();
  2639. f.label = face.label;
  2640. add(f);
  2641. he0[c] = he;
  2642. he.setFace(f);
  2643. f.setHalfedge(he);
  2644. he1[c] = he.getNextInFace();
  2645. he2[c] = new HE_Halfedge();
  2646. hec[c] = new HE_Halfedge();
  2647. add(he2[c]);
  2648. add(hec[c]);
  2649. hec[c].setVertex(he.getVertex());
  2650. hec[c].setPair(he2[c]);
  2651. hec[c].setFace(face);
  2652. final HE_Edge e = new HE_Edge();
  2653. add(e);
  2654. e.setHalfedge(hec[c]);
  2655. hec[c].setEdge(e);
  2656. he2[c].setEdge(e);
  2657. he2[c].setVertex(he.getNextInFace().getNextInFace().getVertex());
  2658. he2[c].setNext(he0[c]);
  2659. he1[c].setFace(f);
  2660. he2[c].setFace(f);
  2661. c++;
  2662. he = he.getNextInFace().getNextInFace();
  2663. } while (he != startHE);
  2664. face.setHalfedge(hec[0]);
  2665. for (int j = 0; j < c; j++) {
  2666. he1[j].setNext(he2[j]);
  2667. hec[j].setNext(hec[(j + 1) % c]);
  2668. }
  2669. }
  2670. return selectionOut;
  2671. }
  2672. /**
  2673. * Mid split selected faces.
  2674. *
  2675. * @param selection selection to split
  2676. * @return selection of new faces and new vertices
  2677. */
  2678. public HE_Selection midSplitFaces(final HE_Selection selection) {
  2679. final HE_Selection selectionOut = new HE_Selection(this);
  2680. final int n = selection.numberOfFaces();
  2681. final int[] faceOrders = new int[n];
  2682. HE_Face face;
  2683. final Iterator<HE_Face> fItr = selection.fItr();
  2684. int i = 0;
  2685. while (fItr.hasNext()) {
  2686. face = fItr.next();
  2687. faceOrders[i] = face.getFaceOrder();
  2688. i++;
  2689. }
  2690. final HE_Selection orig = new HE_Selection(this);
  2691. orig.addFaces(selection.getFacesAsArray());
  2692. orig.collectVertices();
  2693. orig.collectEdges();
  2694. selectionOut.addVertices(splitEdges(orig).getVerticesAsArray());
  2695. final HE_Face[] faces = selection.getFacesAsArray();
  2696. for (i = 0; i < n; i++) {
  2697. face = faces[i];
  2698. HE_Halfedge startHE = face.getHalfedge();
  2699. while (orig.contains(startHE.getVertex())) {
  2700. startHE = startHE.getNextInFace();
  2701. }
  2702. HE_Halfedge he = startHE;
  2703. final HE_Halfedge[] hec = new HE_Halfedge[faceOrders[i]];
  2704. final HE_Halfedge[] he0 = new HE_Halfedge[faceOrders[i]];
  2705. final HE_Halfedge[] he1 = new HE_Halfedge[faceOrders[i]];
  2706. final HE_Halfedge[] he2 = new HE_Halfedge[faceOrders[i]];
  2707. int c = 0;
  2708. do {
  2709. final HE_Face f = new HE_Face();
  2710. add(f);
  2711. f.label = face.label;
  2712. selection.add(f);
  2713. he0[c] = he;
  2714. he.setFace(f);
  2715. f.setHalfedge(he);
  2716. he1[c] = he.getNextInFace();
  2717. he2[c] = new HE_Halfedge();
  2718. hec[c] = new HE_Halfedge();
  2719. add(he2[c]);
  2720. add(hec[c]);
  2721. hec[c].setVertex(he.getVertex());
  2722. hec[c].setPair(he2[c]);
  2723. hec[c].setFace(face);
  2724. final HE_Edge e = new HE_Edge();
  2725. add(e);
  2726. e.setHalfedge(hec[c]);
  2727. hec[c].setEdge(e);
  2728. he2[c].setEdge(e);
  2729. he2[c].setVertex(he.getNextInFace().getNextInFace().getVertex());
  2730. he2[c].setNext(he0[c]);
  2731. he1[c].setFace(f);
  2732. he2[c].setFace(f);
  2733. c++;
  2734. he = he.getNextInFace().getNextInFace();
  2735. } while (he != startHE);
  2736. face.setHalfedge(hec[0]);
  2737. for (int j = 0; j < c; j++) {
  2738. he1[j].setNext(he2[j]);
  2739. hec[j].setNext(hec[(j + 1) % c]);
  2740. }
  2741. }
  2742. return selectionOut;
  2743. }
  2744. /**
  2745. * Triangulate face.
  2746. *
  2747. * @param key
  2748. * key of face
  2749. */
  2750. public void triangulateFace(final Integer key) {
  2751. triangulateFace(getFaceByKey(key));
  2752. }
  2753. public void triangulateFace(final HE_Face face) {
  2754. if (face.getFaceOrder() > 3) {
  2755. final ArrayList<WB_IndexedTriangle2D> tris = face.triangulate();
  2756. final ArrayList<HE_Vertex> vertices = face.getFaceVertices();
  2757. final ArrayList<HE_Halfedge> unpHalfedges = new ArrayList<HE_Halfedge>();
  2758. for (int i = 0; i < tris.size(); i++) {
  2759. final WB_IndexedTriangle2D tri = tris.get(i);
  2760. final HE_Face f = new HE_Face();
  2761. add(f);
  2762. f.label = face.label;
  2763. final HE_Halfedge he1 = new HE_Halfedge();
  2764. final HE_Halfedge he2 = new HE_Halfedge();
  2765. final HE_Halfedge he3 = new HE_Halfedge();
  2766. he1.setVertex(vertices.get(tri.i1));
  2767. he2.setVertex(vertices.get(tri.i2));
  2768. he3.setVertex(vertices.get(tri.i3));
  2769. he1.getVertex().setHalfedge(he1);
  2770. he2.getVertex().setHalfedge(he2);
  2771. he3.getVertex().setHalfedge(he3);
  2772. he1.setFace(f);
  2773. he2.setFace(f);
  2774. he3.setFace(f);
  2775. he1.setNext(he2);
  2776. he2.setNext(he3);
  2777. he3.setNext(he1);
  2778. f.setHalfedge(he1);
  2779. add(he1);
  2780. add(he2);
  2781. add(he3);
  2782. unpHalfedges.add(he1);
  2783. unpHalfedges.add(he2);
  2784. unpHalfedges.add(he3);
  2785. }
  2786. HE_Halfedge he = face.getHalfedge();
  2787. do {
  2788. he.getPair().clearEdge();
  2789. unpHalfedges.add(he.getPair());
  2790. he.getPair().clearPair();
  2791. remove(he.getEdge());
  2792. remove(he);
  2793. he = he.getNextInFace();
  2794. } while (he != face.getHalfedge());
  2795. remove(face);
  2796. pairHalfedgesSilent();
  2797. }
  2798. }
  2799. /**
  2800. * Triangulate all faces.
  2801. *
  2802. */
  2803. public void triangulateFaces() {
  2804. final HE_Face[] f = getFacesAsArray();
  2805. final int n = numberOfFaces();
  2806. for (int i = 0; i < n; i++) {
  2807. triangulateFace(f[i]);
  2808. }
  2809. }
  2810. /**
  2811. * Triangulate all concave faces.
  2812. *
  2813. */
  2814. public void triangulateConcaveFaces() {
  2815. final HE_Face[] f = getFacesAsArray();
  2816. final int n = numberOfFaces();
  2817. for (int i = 0; i < n; i++) {
  2818. if (f[i].getFaceType() == WB_PolygonType2D.CONCAVE) {
  2819. triangulateFace(f[i].key());
  2820. }
  2821. }
  2822. }
  2823. /**
  2824. * Triangulate face if concave.
  2825. *
  2826. * @param key
  2827. * key of face
  2828. */
  2829. public void triangulateConcaveFace(final Integer key) {
  2830. triangulateConcaveFace(getFaceByKey(key));
  2831. }
  2832. /**
  2833. * Triangulate face if concave.
  2834. *
  2835. * @param face
  2836. * key of face
  2837. */
  2838. public void triangulateConcaveFace(final HE_Face face) {
  2839. if (face.getFaceType() == WB_PolygonType2D.CONCAVE) {
  2840. triangulateFace(face);
  2841. }
  2842. }
  2843. /**
  2844. * Expand vertex to new edge.
  2845. *
  2846. * @param v vertex to expand
  2847. * @param f1 first face
  2848. * @param f2 second face
  2849. * @param vn position of new vertex
  2850. */
  2851. public void expandVertexToEdge(final HE_Vertex v, final HE_Face f1,
  2852. final HE_Face f2, final WB_Point vn) {
  2853. HE_Halfedge he = v.getHalfedge();
  2854. HE_Halfedge he1 = new HE_Halfedge();
  2855. HE_Halfedge he2 = new HE_Halfedge();
  2856. do {
  2857. if (he.getFace() == f1) {
  2858. he1 = he;
  2859. }
  2860. if (he.getFace() == f2) {
  2861. he2 = he;
  2862. }
  2863. he = he.getNextInVertex();
  2864. } while (he != v.getHalfedge());
  2865. final HE_Vertex vNew = new HE_Vertex(vn);
  2866. vNew.setHalfedge(he1);
  2867. add(vNew);
  2868. he = he1;
  2869. do {
  2870. he.setVertex(vNew);
  2871. he = he.getNextInVertex();
  2872. } while (he != he2);
  2873. final HE_Halfedge he1p = he1.getPrevInFace();
  2874. final HE_Halfedge he2p = he2.getPrevInFace();
  2875. final HE_Halfedge he1new = new HE_Halfedge();
  2876. final HE_Halfedge he2new = new HE_Halfedge();
  2877. add(he1new);
  2878. add(he2new);
  2879. he1new.setVertex(v);
  2880. he2new.setVertex(vNew);
  2881. he1p.setNext(he1new);
  2882. he1new.setNext(he1);
  2883. he2p.setNext(he2new);
  2884. he2new.setNext(he2);
  2885. he1new.setPair(he2new);
  2886. he1new.setFace(f1);
  2887. he2new.setFace(f2);
  2888. final HE_Edge eNew = new HE_Edge();
  2889. add(eNew);
  2890. eNew.setHalfedge(he1new);
  2891. he1new.setEdge(eNew);
  2892. he2new.setEdge(eNew);
  2893. }
  2894. /**
  2895. * Check consistency of datastructure.
  2896. *
  2897. * @param verbose true: print to console, HE.SILENT: no output
  2898. * @param force true: full scan, HE.BREAK: stop on first error
  2899. * @return true or false
  2900. */
  2901. public boolean validate(final boolean verbose, final boolean force) {
  2902. boolean result = true;
  2903. if (verbose == true) {
  2904. System.out.println("Checking face (" + numberOfFaces()
  2905. + ") properties");
  2906. }
  2907. HE_Face face;
  2908. final Iterator<HE_Face> fItr = fItr();
  2909. while (fItr.hasNext()) {
  2910. face = fItr.next();
  2911. if (face.getHalfedge() == null) {
  2912. if (verbose == true) {
  2913. System.out.println("Null reference in face " + face.key()
  2914. + ".");
  2915. }
  2916. if (force == true) {
  2917. result = false;
  2918. } else {
  2919. return false;
  2920. }
  2921. } else {
  2922. if (!contains(face.getHalfedge())) {
  2923. if (verbose == true) {
  2924. System.out.println("External reference in face "
  2925. + face.key() + ".");
  2926. }
  2927. if (force == true) {
  2928. result = false;
  2929. } else {
  2930. return false;
  2931. }
  2932. } else {
  2933. if (face.getHalfedge().getFace() != null) {
  2934. if (face.getHalfedge().getFace() != face) {
  2935. if (verbose == true) {
  2936. System.out.println("Wrong reference in face "
  2937. + face.key() + ".");
  2938. }
  2939. if (force == true) {
  2940. result = false;
  2941. } else {
  2942. return false;
  2943. }
  2944. }
  2945. }
  2946. }
  2947. }
  2948. }
  2949. if (verbose == true) {
  2950. System.out.println("Checking vertex (" + numberOfVertices()
  2951. + ") properties");
  2952. }
  2953. HE_Vertex v;
  2954. final Iterator<HE_Vertex> vItr = vItr();
  2955. while (vItr.hasNext()) {
  2956. v = vItr.next();
  2957. if (v.getHalfedge() == null) {
  2958. if (verbose == true) {
  2959. System.out.println("Null reference in vertex " + v.key()
  2960. + ".");
  2961. }
  2962. if (force == true) {
  2963. result = false;
  2964. } else {
  2965. return false;
  2966. }
  2967. } else {
  2968. if (!contains(v.getHalfedge())) {
  2969. if (verbose == true) {
  2970. System.out.println("External reference in vertex "
  2971. + v.key() + ".");
  2972. }
  2973. if (force == true) {
  2974. result = false;
  2975. } else {
  2976. return false;
  2977. }
  2978. }
  2979. if (v.getHalfedge().getVertex() != null) {
  2980. if (v.getHalfedge().getVertex() != v) {
  2981. if (verbose == true) {
  2982. System.out.println("Wrong reference in vertex "
  2983. + v.key() + ".");
  2984. }
  2985. if (force == true) {
  2986. result = false;
  2987. } else {
  2988. return false;
  2989. }
  2990. }
  2991. }
  2992. }
  2993. }
  2994. if (verbose == true) {
  2995. System.out.println("Checking edge (" + numberOfEdges()
  2996. + ") properties");
  2997. }
  2998. final Iterator<HE_Edge> eItr = eItr();
  2999. HE_Edge e;
  3000. while (eItr.hasNext()) {
  3001. e = eItr.next();
  3002. if (e.getHalfedge() == null) {
  3003. if (verbose == true) {
  3004. System.out.println("Null reference in edge " + e.key()
  3005. + ".");
  3006. }
  3007. if (force == true) {
  3008. result = false;
  3009. } else {
  3010. return false;
  3011. }
  3012. } else {
  3013. if (!contains(e.getHalfedge())) {
  3014. if (verbose == true) {
  3015. System.out.println("External reference in edge "
  3016. + e.key() + ".");
  3017. }
  3018. if (force == true) {
  3019. result = false;
  3020. } else {
  3021. return false;
  3022. }
  3023. }
  3024. if (e.getHalfedge().getEdge() != null) {
  3025. if (e.getHalfedge().getEdge() != e) {
  3026. if (verbose == true) {
  3027. System.out.println("Wrong reference in edge "
  3028. + e.key() + ".");
  3029. }
  3030. if (force == true) {
  3031. result = false;
  3032. } else {
  3033. return false;
  3034. }
  3035. }
  3036. }
  3037. }
  3038. }
  3039. if (verbose == true) {
  3040. System.out.println("Checking half edge (" + numberOfHalfedges()
  3041. + ") properties");
  3042. }
  3043. HE_Halfedge he;
  3044. final Iterator<HE_Halfedge> heItr = heItr();
  3045. while (heItr.hasNext()) {
  3046. he = heItr.next();
  3047. if (he.getNextInFace() == null) {
  3048. if (verbose == true) {
  3049. System.out.println("Null reference (next) in half edge "
  3050. + he.key() + ".");
  3051. }
  3052. if (force == true) {
  3053. result = false;
  3054. } else {
  3055. return false;
  3056. }
  3057. } else {
  3058. if (!contains(he.getNextInFace())) {
  3059. if (verbose == true) {
  3060. System.out
  3061. .println("External reference (next) in half edge "
  3062. + he.key() + ".");
  3063. }
  3064. if (force == true) {
  3065. result = false;
  3066. } else {
  3067. return false;
  3068. }
  3069. }
  3070. if ((he.getFace() != null)
  3071. && (he.getNextInFace().getFace() != null)) {
  3072. if (he.getFace() != he.getNextInFace().getFace()) {
  3073. if (verbose == true) {
  3074. System.out
  3075. .println("Incosistent reference (face) in half edge "
  3076. + he.key() + ".");
  3077. }
  3078. if (force == true) {
  3079. result = false;
  3080. } else {
  3081. return false;
  3082. }
  3083. }
  3084. }
  3085. }
  3086. if (he.getPair() == null) {
  3087. if (verbose == true) {
  3088. System.out.println("Null reference (pair) in half edge "
  3089. + he.key() + ".");
  3090. }
  3091. if (force == true) {
  3092. result = false;
  3093. } else {
  3094. return false;
  3095. }
  3096. } else {
  3097. if (!contains(he.getPair())) {
  3098. if (verbose == true) {
  3099. System.out
  3100. .println("External reference (pair) in half edge "
  3101. + he.key() + ".");
  3102. }
  3103. if (force == true) {
  3104. result = false;
  3105. } else {
  3106. return false;
  3107. }
  3108. }
  3109. if (he.getPair().getPair() == null) {
  3110. if (verbose == true) {
  3111. System.out
  3112. .println("No pair reference back to half edge "
  3113. + he.key() + ".");
  3114. }
  3115. } else {
  3116. if (he.getPair().getPair() != he) {
  3117. if (verbose == true) {
  3118. System.out
  3119. .println("Wrong pair reference back to half edge "
  3120. + he.key() + ".");
  3121. }
  3122. if (force == true) {
  3123. result = false;
  3124. } else {
  3125. return false;
  3126. }
  3127. }
  3128. }
  3129. if ((he.getEdge() != null) && (he.getPair().getEdge() != null)) {
  3130. if (he.getEdge() != he.getPair().getEdge()) {
  3131. if (verbose == true) {
  3132. System.out
  3133. .println("Inconsistent reference (edge) in half edge "
  3134. + he.key() + ".");
  3135. }
  3136. if (force == true) {
  3137. result = false;
  3138. } else {
  3139. return false;
  3140. }
  3141. }
  3142. }
  3143. }
  3144. if ((he.getNextInFace() != null) && (he.getPair() != null)) {
  3145. if ((he.getNextInFace().getVertex() != null)
  3146. && (he.getPair().getVertex() != null)) {
  3147. if (he.getNextInFace().getVertex() != he.getPair()
  3148. .getVertex()) {
  3149. if (verbose == true) {
  3150. System.out
  3151. .println("Inconsistent reference (pair)/(next) in half edge "
  3152. + he.key() + ".");
  3153. }
  3154. if (force == true) {
  3155. result = false;
  3156. } else {
  3157. return false;
  3158. }
  3159. }
  3160. }
  3161. }
  3162. if (he.getFace() == null) {
  3163. if (verbose == true) {
  3164. System.out.println("Null reference (face) in half edge "
  3165. + he.key() + ".");
  3166. }
  3167. if (force == true) {
  3168. result = false;
  3169. } else {
  3170. return false;
  3171. }
  3172. } else {
  3173. if (!contains(he.getFace())) {
  3174. if (verbose == true) {
  3175. System.out
  3176. .println("External reference (face) in half edge "
  3177. + he.key() + ".");
  3178. }
  3179. if (force == true) {
  3180. result = false;
  3181. } else {
  3182. return false;
  3183. }
  3184. }
  3185. }
  3186. if (he.getVertex() == null) {
  3187. if (verbose == true) {
  3188. System.out.println("Null reference (vert) in half edge "
  3189. + he.key() + ".");
  3190. }
  3191. if (force == true) {
  3192. result = false;
  3193. } else {
  3194. return false;
  3195. }
  3196. } else {
  3197. if (!contains(he.getVertex())) {
  3198. if (verbose == true) {
  3199. System.out
  3200. .println("External reference (vert) in half edge "
  3201. + he.key() + ".");
  3202. }
  3203. if (force == true) {
  3204. result = false;
  3205. } else {
  3206. return false;
  3207. }
  3208. }
  3209. }
  3210. if (he.getEdge() == null) {
  3211. if (verbose == true) {
  3212. System.out.println("Null reference (edge) in half edge "
  3213. + he.key() + ".");
  3214. }
  3215. if (force == true) {
  3216. result = false;
  3217. } else {
  3218. return false;
  3219. }
  3220. } else {
  3221. if (!contains(he.getEdge())) {
  3222. if (verbose == true) {
  3223. System.out
  3224. .println("External reference (edge) in half edge "
  3225. + he.key() + ".");
  3226. }
  3227. if (force == true) {
  3228. result = false;
  3229. } else {
  3230. return false;
  3231. }
  3232. }
  3233. }
  3234. }
  3235. if (verbose == true) {
  3236. System.out.println("Validation complete!");
  3237. }
  3238. return result;
  3239. }
  3240. /**
  3241. * Check if point lies inside mesh.
  3242. *
  3243. * @param p
  3244. * point to check
  3245. * @param isConvex
  3246. * do fast check, convex meshes only
  3247. * @return true or false
  3248. */
  3249. public boolean contains(final WB_Point p, final boolean isConvex) {
  3250. final WB_Point dir = new WB_Point(Math.random() - 0.5,
  3251. Math.random() - 0.5, Math.random() - 0.5);
  3252. final WB_Ray R = new WB_Ray(p, dir);
  3253. int c = 0;
  3254. WB_Plane P;
  3255. WB_IntersectionResult lpi;
  3256. HE_Face face;
  3257. final Iterator<HE_Face> fItr = fItr();
  3258. while (fItr.hasNext()) {
  3259. face = fItr.next();
  3260. P = face.toPlane();
  3261. if (isConvex) {
  3262. if (P.classifyPointToPlane(p) == WB_ClassifyPointToPlane.POINT_BEHIND_PLANE) {
  3263. return false;
  3264. }
  3265. } else {
  3266. lpi = WB_Intersection.getIntersection(R, P);
  3267. if (lpi.intersection) {
  3268. if (pointIsInFace(lpi.p1, face)) {
  3269. if (!HE_Mesh.pointIsStrictlyInFace(lpi.p1, face)) {
  3270. return contains(p, isConvex);
  3271. }
  3272. c++;
  3273. }
  3274. }
  3275. }
  3276. }
  3277. return (isConvex) ? true : (c % 2 == 1);
  3278. }
  3279. /**
  3280. * Check if point lies inside or on edge of face.
  3281. *
  3282. * @param p point
  3283. * @param f the f
  3284. * @return true/false
  3285. */
  3286. public static boolean pointIsInFace(final WB_Point p, final HE_Face f) {
  3287. return WB_Epsilon.isZeroSq(WB_Distance.sqDistance(p,
  3288. WB_ClosestPoint.closestPoint(p, f.toPolygon())));
  3289. }
  3290. /**
  3291. * Check if point lies strictly inside face.
  3292. *
  3293. * @param p point
  3294. * @param f the f
  3295. * @return true/false
  3296. */
  3297. public static boolean pointIsStrictlyInFace(final WB_Point p,
  3298. final HE_Face f) {
  3299. final WB_ExplicitPolygon poly = f.toPolygon();
  3300. final ArrayList<WB_IndexedTriangle> tris = poly.triangulate();
  3301. if (!WB_Epsilon.isZeroSq(WB_Distance.sqDistance(p,
  3302. WB_ClosestPoint.closestPoint(p, tris)))) {
  3303. return false;
  3304. }
  3305. if (WB_Epsilon.isZeroSq(WB_Distance.sqDistance(p,
  3306. WB_ClosestPoint.closestPointOnPeriphery(p, poly, tris)))) {
  3307. return false;
  3308. }
  3309. return true;
  3310. }
  3311. public void fitInAABB(final WB_AABB AABB) {
  3312. final WB_AABB self = getAABB();
  3313. move(AABB.getMin().subToVector(self.getMin()));
  3314. scale(AABB.getWidth() / self.getWidth(),
  3315. AABB.getHeight() / self.getHeight(),
  3316. AABB.getDepth() / self.getDepth(), AABB.getMin());
  3317. }
  3318. public void fitInAABBConstrained(final WB_AABB AABB) {
  3319. final WB_AABB self = getAABB();
  3320. move(AABB.getCenter().subToVector(self.getCenter()));
  3321. double f = Math.min(AABB.getWidth() / self.getWidth(), AABB.getHeight()
  3322. / self.getHeight());
  3323. f = Math.min(f, AABB.getDepth() / self.getDepth());
  3324. scale(f, AABB.getCenter());
  3325. }
  3326. /**
  3327. * Delete face and remove all references.
  3328. *
  3329. * @param faces faces to delete
  3330. */
  3331. public void delete(final HE_Selection faces) {
  3332. HE_Face f;
  3333. final Iterator<HE_Face> fItr = faces.fItr();
  3334. while (fItr.hasNext()) {
  3335. f = fItr.next();
  3336. remove(f);
  3337. }
  3338. cleanUnusedElementsByFace();
  3339. capHalfedges();
  3340. }
  3341. /**
  3342. * Select all faces.
  3343. */
  3344. public HE_Selection selectAllFaces() {
  3345. final HE_Selection _selection = new HE_Selection(this);
  3346. _selection.addFaces(getFacesAsArray());
  3347. return _selection;
  3348. }
  3349. /**
  3350. * Select all faces with given label.
  3351. */
  3352. public HE_Selection selectFaces(final int label) {
  3353. final HE_Selection _selection = new HE_Selection(this);
  3354. HE_Face f;
  3355. final Iterator<HE_Face> fItr = fItr();
  3356. while (fItr.hasNext()) {
  3357. f = fItr.next();
  3358. if (f.getLabel() == label) {
  3359. _selection.add(f);
  3360. }
  3361. }
  3362. return _selection;
  3363. }
  3364. public HE_Selection selectFaces(final WB_Vector v) {
  3365. final HE_Selection _selection = new HE_Selection(this);
  3366. final WB_Vector w = v.get();
  3367. w.normalize();
  3368. HE_Face f;
  3369. final Iterator<HE_Face> fItr = fItr();
  3370. while (fItr.hasNext()) {
  3371. f = fItr.next();
  3372. if (f.getFaceNormal().dot(v) > (1.0 - WB_Epsilon.EPSILON)) {
  3373. _selection.add(f);
  3374. }
  3375. }
  3376. return _selection;
  3377. }
  3378. /**
  3379. * Select all faces except with given label.
  3380. */
  3381. public HE_Selection selectOtherFaces(final int label) {
  3382. final HE_Selection _selection = new HE_Selection(this);
  3383. HE_Face f;
  3384. final Iterator<HE_Face> fItr = fItr();
  3385. while (fItr.hasNext()) {
  3386. f = fItr.next();
  3387. if (f.getLabel() != label) {
  3388. _selection.add(f);
  3389. }
  3390. }
  3391. return _selection;
  3392. }
  3393. /**
  3394. * Select all edges.
  3395. */
  3396. public HE_Selection selectAllEdges() {
  3397. final HE_Selection _selection = new HE_Selection(this);
  3398. _selection.addEdges(getEdgesAsArray());
  3399. return _selection;
  3400. }
  3401. /**
  3402. * Select all halfedges.
  3403. */
  3404. public HE_Selection selectAllHalfedges() {
  3405. final HE_Selection _selection = new HE_Selection(this);
  3406. _selection.addHalfedges(getHalfedgesAsArray());
  3407. return _selection;
  3408. }
  3409. /**
  3410. * Select all vertices.
  3411. */
  3412. public HE_Selection selectAllVertices() {
  3413. final HE_Selection _selection = new HE_Selection(this);
  3414. _selection.addVertices(getVerticesAsArray());
  3415. return _selection;
  3416. }
  3417. /**
  3418. * Select all vertices with given label.
  3419. */
  3420. public HE_Selection selectVertices(final int label) {
  3421. final HE_Selection _selection = new HE_Selection(this);
  3422. HE_Vertex v;
  3423. final Iterator<HE_Vertex> vItr = vItr();
  3424. while (vItr.hasNext()) {
  3425. v = vItr.next();
  3426. if (v.getLabel() == label) {
  3427. _selection.add(v);
  3428. }
  3429. }
  3430. return _selection;
  3431. }
  3432. /**
  3433. * Select all vertices except with given label.
  3434. */
  3435. public HE_Selection selectOtherVertices(final int label) {
  3436. final HE_Selection _selection = new HE_Selection(this);
  3437. HE_Vertex v;
  3438. final Iterator<HE_Vertex> vItr = vItr();
  3439. while (vItr.hasNext()) {
  3440. v = vItr.next();
  3441. if (v.getLabel() != label) {
  3442. _selection.add(v);
  3443. }
  3444. }
  3445. return _selection;
  3446. }
  3447. /**
  3448. * Select all halfedges on inside of boundary.
  3449. */
  3450. public HE_Selection selectAllInnerBoundaryHalfedges() {
  3451. final HE_Selection _selection = new HE_Selection(this);
  3452. final Iterator<HE_Halfedge> heItr = heItr();
  3453. HE_Halfedge he;
  3454. while (heItr.hasNext()) {
  3455. he = heItr.next();
  3456. if (he.getPair().getFace() == null) {
  3457. _selection.add(he);
  3458. }
  3459. }
  3460. return _selection;
  3461. }
  3462. /**
  3463. * Select all halfedges on outside of boundary.
  3464. */
  3465. public HE_Selection selectAllOuterBoundaryHalfedges() {
  3466. final HE_Selection _selection = new HE_Selection(this);
  3467. final Iterator<HE_Halfedge> heItr = heItr();
  3468. HE_Halfedge he;
  3469. while (heItr.hasNext()) {
  3470. he = heItr.next();
  3471. if (he.getFace() == null) {
  3472. _selection.add(he);
  3473. }
  3474. }
  3475. return _selection;
  3476. }
  3477. /**
  3478. * Select all edges on boundary.
  3479. */
  3480. public HE_Selection selectAllBoundaryEdges() {
  3481. final HE_Selection _selection = new HE_Selection(this);
  3482. final Iterator<HE_Halfedge> heItr = heItr();
  3483. HE_Halfedge he;
  3484. while (heItr.hasNext()) {
  3485. he = heItr.next();
  3486. if (he.getFace() == null) {
  3487. _selection.add(he.getEdge());
  3488. }
  3489. }
  3490. return _selection;
  3491. }
  3492. /**
  3493. * Select all faces on boundary.
  3494. */
  3495. public HE_Selection selectAllBoundaryFaces() {
  3496. final HE_Selection _selection = new HE_Selection(this);
  3497. final Iterator<HE_Halfedge> heItr = heItr();
  3498. HE_Halfedge he;
  3499. while (heItr.hasNext()) {
  3500. he = heItr.next();
  3501. if (he.getFace() == null) {
  3502. _selection.add(he.getPair().getFace());
  3503. }
  3504. }
  3505. return _selection;
  3506. }
  3507. /**
  3508. * Select all vertices on boundary.
  3509. */
  3510. public HE_Selection selectAllBoundaryVertices() {
  3511. final HE_Selection _selection = new HE_Selection(this);
  3512. final Iterator<HE_Halfedge> heItr = heItr();
  3513. HE_Halfedge he;
  3514. while (heItr.hasNext()) {
  3515. he = heItr.next();
  3516. if (he.getFace() == null) {
  3517. _selection.add(he.getVertex());
  3518. }
  3519. }
  3520. return _selection;
  3521. }
  3522. /**
  3523. * Fuse all coplanar faces connected to face. New face can be concave.
  3524. *
  3525. * @param face starting face
  3526. * @return new face
  3527. */
  3528. public HE_Face fuseCoplanarFace(final HE_Face face, final double a) {
  3529. ArrayList<HE_Face> neighbors;
  3530. FastTable<HE_Face> facesToCheck = new FastTable<HE_Face>();
  3531. final FastTable<HE_Face> newFacesToCheck = new FastTable<HE_Face>();
  3532. facesToCheck.add(face);
  3533. final HE_Selection sel = new HE_Selection(this);
  3534. sel.add(face);
  3535. HE_Face f;
  3536. HE_Face fn;
  3537. int ni = -1;
  3538. int nf = 0;
  3539. double sa = Math.sin(a);
  3540. sa *= sa;
  3541. while (ni < nf) {
  3542. newFacesToCheck.clear();
  3543. for (int i = 0; i < facesToCheck.size(); i++) {
  3544. f = facesToCheck.get(i);
  3545. neighbors = f.getNeighborFaces();
  3546. for (int j = 0; j < neighbors.size(); j++) {
  3547. fn = neighbors.get(j);
  3548. if (!sel.contains(fn)) {
  3549. if (f.getFaceNormal()
  3550. .isParallel(fn.getFaceNormal(), sa)) {
  3551. sel.add(fn);
  3552. newFacesToCheck.add(fn);
  3553. }
  3554. }
  3555. }
  3556. }
  3557. facesToCheck = newFacesToCheck;
  3558. ni = nf;
  3559. nf = sel.numberOfFaces();
  3560. }
  3561. if (sel.numberOfFaces() == 1) {
  3562. return face;
  3563. }
  3564. final ArrayList<HE_Halfedge> halfedges = sel.getOuterHalfedgesInside();
  3565. final HE_Face newFace = new HE_Face();
  3566. add(newFace);
  3567. newFace.setHalfedge(halfedges.get(0));
  3568. for (int i = 0; i < halfedges.size(); i++) {
  3569. final HE_Halfedge hei = halfedges.get(i);
  3570. final HE_Halfedge hep = halfedges.get(i).getPair();
  3571. for (int j = 0; j < halfedges.size(); j++) {
  3572. final HE_Halfedge hej = halfedges.get(j);
  3573. if ((i != j) && (hep.getVertex() == hej.getVertex())) {
  3574. hei.setNext(hej);
  3575. }
  3576. }
  3577. hei.setFace(newFace);
  3578. hei.getVertex().setHalfedge(hei);
  3579. }
  3580. removeFaces(sel.getFacesAsArray());
  3581. cleanUnusedElementsByFace();
  3582. return newFace;
  3583. }
  3584. /**
  3585. * Fuse all planar faces. Can lead to concave faces.
  3586. *
  3587. */
  3588. public void fuseCoplanarFaces() {
  3589. fuseCoplanarFaces(0);
  3590. }
  3591. /**
  3592. * Fuse all planar faces. Can lead to concave faces.
  3593. *
  3594. */
  3595. public void fuseCoplanarFaces(final double a) {
  3596. final ArrayList<HE_Face> faces = this.getFacesAsArrayList();
  3597. for (int i = 0; i < faces.size(); i++) {
  3598. final HE_Face f = faces.get(i);
  3599. if (contains(f)) {
  3600. fuseCoplanarFace(f, a);
  3601. }
  3602. }
  3603. }
  3604. /**
  3605. * Remove all redundant vertices in straight edges.
  3606. *
  3607. */
  3608. public void removeColinearVertices() {
  3609. final Iterator<HE_Vertex> vItr = vItr();
  3610. HE_Vertex v;
  3611. HE_Halfedge he;
  3612. while (vItr.hasNext()) {
  3613. v = vItr.next();
  3614. if (v.getVertexOrder() == 2) {
  3615. he = v.getHalfedge();
  3616. if (he.getHalfedgeTangent().isParallel(
  3617. he.getNextInVertex().getHalfedgeTangent())) {
  3618. he.getPrevInFace().setNext(he.getNextInFace());
  3619. he.getPair().getPrevInFace()
  3620. .setNext(he.getPair().getNextInFace());
  3621. he.getPair().getNextInFace()
  3622. .setVertex(he.getNextInFace().getVertex());
  3623. if (he.getFace() != null) {
  3624. if (he.getFace().getHalfedge() == he) {
  3625. he.getFace().setHalfedge(he.getNextInFace());
  3626. }
  3627. }
  3628. if (he.getPair().getFace() != null) {
  3629. if (he.getPair().getFace().getHalfedge() == he
  3630. .getPair()) {
  3631. he.getPair().getFace()
  3632. .setHalfedge(he.getPair().getNextInFace());
  3633. }
  3634. }
  3635. vItr.remove();
  3636. remove(he);
  3637. remove(he.getPair());
  3638. remove(he.getEdge());
  3639. }
  3640. }
  3641. }
  3642. }
  3643. public void resetLabels() {
  3644. resetVertexLabels();
  3645. resetFaceLabels();
  3646. resetEdgeLabels();
  3647. }
  3648. public void resetVertexLabels() {
  3649. final Iterator<HE_Vertex> vItr = vItr();
  3650. while (vItr.hasNext()) {
  3651. vItr.next().setLabel(-1);
  3652. }
  3653. }
  3654. public void resetFaceLabels() {
  3655. final Iterator<HE_Face> fItr = fItr();
  3656. while (fItr.hasNext()) {
  3657. fItr.next().setLabel(-1);
  3658. }
  3659. }
  3660. public void resetEdgeLabels() {
  3661. final Iterator<HE_Edge> eItr = eItr();
  3662. while (eItr.hasNext()) {
  3663. eItr.next().setLabel(-1);
  3664. }
  3665. }
  3666. /**
  3667. * Label all faces of a selection.
  3668. *
  3669. * @param sel selection
  3670. * @param label label to use
  3671. */
  3672. public void labelFaceSelection(final HE_Selection sel, final int label) {
  3673. final Iterator<HE_Face> fItr = sel.fItr();
  3674. while (fItr.hasNext()) {
  3675. fItr.next().label = label;
  3676. }
  3677. }
  3678. /**
  3679. * Update selection to include all face swith given label
  3680. *
  3681. * @param sel selection to update
  3682. * @param label label to search
  3683. */
  3684. public void updateFaceSelection(final HE_Selection sel, final int label) {
  3685. final Iterator<HE_Face> fItr = fItr();
  3686. HE_Face f;
  3687. sel.clear();
  3688. while (fItr.hasNext()) {
  3689. f = fItr.next();
  3690. if (f.label == label) {
  3691. sel.add(f);
  3692. }
  3693. }
  3694. }
  3695. public void labelEdgeSelection(final HE_Selection sel, final int label) {
  3696. final Iterator<HE_Edge> eItr = sel.eItr();
  3697. while (eItr.hasNext()) {
  3698. eItr.next().label = label;
  3699. }
  3700. }
  3701. public void updateEdgeSelection(final HE_Selection sel, final int label) {
  3702. final Iterator<HE_Edge> eItr = eItr();
  3703. HE_Edge e;
  3704. sel.clear();
  3705. while (eItr.hasNext()) {
  3706. e = eItr.next();
  3707. if (e.label == label) {
  3708. sel.add(e);
  3709. }
  3710. }
  3711. }
  3712. public void labelVertexSelection(final HE_Selection sel, final int label) {
  3713. final Iterator<HE_Vertex> vItr = sel.vItr();
  3714. while (vItr.hasNext()) {
  3715. vItr.next().label = label;
  3716. }
  3717. }
  3718. public void updateVertexSelection(final HE_Selection sel, final int label) {
  3719. final Iterator<HE_Vertex> vItr = vItr();
  3720. HE_Vertex v;
  3721. sel.clear();
  3722. while (vItr.hasNext()) {
  3723. v = vItr.next();
  3724. if (v.label == label) {
  3725. sel.add(v);
  3726. }
  3727. }
  3728. }
  3729. /**
  3730. * Return a KD-tree containing all face centers
  3731. *
  3732. * @return WB_KDTree
  3733. */
  3734. public WB_KDTree<Integer> getFaceTree() {
  3735. final WB_KDTree<Integer> tree = new WB_KDTree<Integer>();
  3736. HE_Face f;
  3737. final Iterator<HE_Face> fItr = fItr();
  3738. while (fItr.hasNext()) {
  3739. f = fItr.next();
  3740. tree.put(f.getFaceCenter(), f.key());
  3741. }
  3742. return tree;
  3743. }
  3744. /**
  3745. * Return a KD-tree containing all vertices
  3746. *
  3747. * @return WB_KDTree
  3748. */
  3749. public WB_KDTree<Integer> getVertexTree() {
  3750. final WB_KDTree<Integer> tree = new WB_KDTree<Integer>();
  3751. HE_Vertex v;
  3752. final Iterator<HE_Vertex> vItr = vItr();
  3753. while (vItr.hasNext()) {
  3754. v = vItr.next();
  3755. tree.put(v, v.key());
  3756. }
  3757. return tree;
  3758. }
  3759. /**
  3760. * Return the closest vertex on the mesh.
  3761. *
  3762. * @param p query point
  3763. * @param vertexTree KD-tree from mesh (from vertexTree())
  3764. * @return HE_Vertex closest vertex
  3765. */
  3766. public HE_Vertex getClosestVertex(final WB_Point p,
  3767. final WB_KDTree<Integer> vertexTree) {
  3768. final WB_KDNeighbor<Integer>[] closestVertex = vertexTree
  3769. .getNearestNeighbors(p, 1);
  3770. if (closestVertex.length == 0) {
  3771. return null;
  3772. }
  3773. return getVertexByKey(closestVertex[0].value());
  3774. }
  3775. /**
  3776. * Return the closest point on the mesh.
  3777. *
  3778. * @param p query point
  3779. * @param vertexTree KD-tree from mesh (from vertexTree())
  3780. * @return WB_Point closest point
  3781. */
  3782. public WB_Point getClosestPoint(final WB_Point p,
  3783. final WB_KDTree<Integer> vertexTree) {
  3784. final WB_KDNeighbor<Integer>[] closestVertex = vertexTree
  3785. .getNearestNeighbors(p, 1);
  3786. final HE_Vertex v = getVertexByKey(closestVertex[0].value());
  3787. if (v == null) {
  3788. return null;
  3789. }
  3790. final ArrayList<HE_Face> faces = v.getFaceStar();
  3791. double d;
  3792. double dmin = Double.POSITIVE_INFINITY;
  3793. WB_Point result = new WB_Point();
  3794. for (int i = 0; i < faces.size(); i++) {
  3795. final WB_ExplicitPolygon poly = faces.get(i).toPolygon();
  3796. final WB_Point tmp = WB_ClosestPoint.closestPoint(p, poly);
  3797. d = WB_Distance.sqDistance(tmp, p);
  3798. if (d < dmin) {
  3799. dmin = d;
  3800. result = tmp;
  3801. }
  3802. }
  3803. return result;
  3804. }
  3805. /**
  3806. * Split the closest face in the query point.
  3807. *
  3808. * @param p query point
  3809. * @param vertexTree KD-tree from mesh (from vertexTree())
  3810. */
  3811. public void addPointInClosestFace(final WB_Point p,
  3812. final WB_KDTree<Integer> vertexTree) {
  3813. final WB_KDNeighbor<Integer>[] closestVertex = vertexTree
  3814. .getNearestNeighbors(p, 1);
  3815. final HE_Vertex v = getVertexByKey(closestVertex[0].value());
  3816. final ArrayList<HE_Face> faces = v.getFaceStar();
  3817. double d;
  3818. double dmin = Double.POSITIVE_INFINITY;
  3819. HE_Face face = new HE_Face();
  3820. for (int i = 0; i < faces.size(); i++) {
  3821. final WB_ExplicitPolygon poly = faces.get(i).toPolygon();
  3822. final WB_Point tmp = WB_ClosestPoint.closestPoint(p, poly);
  3823. d = WB_Distance.sqDistance(tmp, p);
  3824. if (d < dmin) {
  3825. dmin = d;
  3826. face = faces.get(i);
  3827. ;
  3828. }
  3829. }
  3830. final HE_Vertex nv = triSplitFace(face, p).vItr().next();
  3831. vertexTree.put(nv, nv.key());
  3832. }
  3833. /**
  3834. * Get all faces shared between two vertices
  3835. * @param v1
  3836. * @param v2
  3837. *
  3838. * @return shared faces as ArrayList<HE_Face>
  3839. */
  3840. public ArrayList<HE_Face> getSharedFaces(final HE_Vertex v1,
  3841. final HE_Vertex v2) {
  3842. final ArrayList<HE_Face> result = v1.getFaceStar();
  3843. final ArrayList<HE_Face> compare = v2.getFaceStar();
  3844. final Iterator<HE_Face> it = result.iterator();
  3845. while (it.hasNext()) {
  3846. if (!compare.contains(it.next())) {
  3847. it.remove();
  3848. }
  3849. }
  3850. return result;
  3851. }
  3852. public ArrayList<WB_ExplicitPolygon> getBoundaryAsPolygons() {
  3853. final ArrayList<WB_ExplicitPolygon> polygons = new ArrayList<WB_ExplicitPolygon>();
  3854. final ArrayList<HE_Halfedge> halfedges = getBoundaryHalfedges();
  3855. final ArrayList<HE_Halfedge> loop = new ArrayList<HE_Halfedge>();
  3856. final ArrayList<WB_Point> points = new ArrayList<WB_Point>();
  3857. while (halfedges.size() > 0) {
  3858. points.clear();
  3859. loop.clear();
  3860. HE_Halfedge he = halfedges.get(0);
  3861. do {
  3862. loop.add(he);
  3863. points.add(he.getVertex());
  3864. he = he.getNextInFace();
  3865. if (loop.contains(he)) {
  3866. break;
  3867. }
  3868. } while (he != halfedges.get(0));
  3869. polygons.add(new WB_ExplicitPolygon(points));
  3870. halfedges.removeAll(loop);
  3871. }
  3872. return polygons;
  3873. }
  3874. public ArrayList<HE_Halfedge> getBoundaryLoopHalfedges() {
  3875. final ArrayList<HE_Halfedge> hes = new ArrayList<HE_Halfedge>();
  3876. final ArrayList<HE_Halfedge> halfedges = getBoundaryHalfedges();
  3877. final ArrayList<HE_Halfedge> loop = new ArrayList<HE_Halfedge>();
  3878. while (halfedges.size() > 0) {
  3879. loop.clear();
  3880. HE_Halfedge he = halfedges.get(0);
  3881. hes.add(he);
  3882. do {
  3883. loop.add(he);
  3884. he = he.getNextInFace();
  3885. if (loop.contains(he)) {
  3886. break;
  3887. }
  3888. } while (he != halfedges.get(0));
  3889. halfedges.removeAll(loop);
  3890. }
  3891. return hes;
  3892. }
  3893. /**
  3894. * Try to identify and correct corner and edge welds. Can occur when combining meshes joined at a single vertex or edge.
  3895. * Needs two passes to complete.
  3896. */
  3897. public void resolvePinchPoints() {
  3898. Iterator<HE_Vertex> vItr = vItr();
  3899. Iterator<HE_Halfedge> heItr;
  3900. HE_Vertex v;
  3901. HE_Halfedge he;
  3902. boolean pinchFound;
  3903. final FastList<HE_Halfedge> vHalfedges = new FastList<HE_Halfedge>();
  3904. do {
  3905. vItr = vItr();
  3906. pinchFound = false;
  3907. while (vItr.hasNext()) {
  3908. v = vItr.next();
  3909. heItr = heItr();
  3910. vHalfedges.clear();
  3911. while (heItr.hasNext()) {
  3912. he = heItr.next();
  3913. if (he.getVertex() == v) {
  3914. vHalfedges.add(he);
  3915. }
  3916. }
  3917. final ArrayList<HE_Halfedge> vStar = v.getHalfedgeStar();
  3918. if (vStar.size() != vHalfedges.size()) {
  3919. pinchFound = true;
  3920. final HE_Vertex vc = new HE_Vertex(v);
  3921. add(vc);
  3922. for (int i = 0; i < vStar.size(); i++) {
  3923. vStar.get(i).setVertex(vc);
  3924. }
  3925. vc.setHalfedge(vStar.get(0));
  3926. for (int i = 0; i < vHalfedges.size(); i++) {
  3927. he = vHalfedges.get(i);
  3928. if (he.getVertex() == v) {
  3929. v.setHalfedge(he);
  3930. break;
  3931. }
  3932. }
  3933. }
  3934. }
  3935. } while (pinchFound);
  3936. }
  3937. public double getArea() {
  3938. final Iterator<HE_Face> fItr = fItr();
  3939. double A = 0.0;
  3940. while (fItr.hasNext()) {
  3941. A += fItr.next().getFaceArea();
  3942. }
  3943. return A;
  3944. }
  3945. }