csg_collector.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // Begin License:
  2. // Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
  3. // All rights reserved.
  4. //
  5. // This file is part of the Carve CSG Library (http://carve-csg.com/)
  6. //
  7. // This file may be used under the terms of either the GNU General
  8. // Public License version 2 or 3 (at your option) as published by the
  9. // Free Software Foundation and appearing in the files LICENSE.GPL2
  10. // and LICENSE.GPL3 included in the packaging of this file.
  11. //
  12. // This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
  13. // INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
  14. // A PARTICULAR PURPOSE.
  15. // End:
  16. #if defined(HAVE_CONFIG_H)
  17. # include <carve_config.h>
  18. #endif
  19. #include <carve/csg.hpp>
  20. #include <iostream>
  21. #include "csg_collector.hpp"
  22. #include "intersect_debug.hpp"
  23. #if defined(CARVE_DEBUG_WRITE_PLY_DATA)
  24. void writePLY(const std::string &out_file, const carve::mesh::MeshSet<3> *poly, bool ascii);
  25. #endif
  26. namespace carve {
  27. namespace csg {
  28. namespace {
  29. class BaseCollector : public CSG::Collector {
  30. BaseCollector();
  31. BaseCollector(const BaseCollector &);
  32. BaseCollector &operator=(const BaseCollector &);
  33. protected:
  34. struct face_data_t {
  35. carve::mesh::MeshSet<3>::face_t *face;
  36. const carve::mesh::MeshSet<3>::face_t *orig_face;
  37. bool flipped;
  38. face_data_t(carve::mesh::MeshSet<3>::face_t *_face,
  39. const carve::mesh::MeshSet<3>::face_t *_orig_face,
  40. bool _flipped) : face(_face), orig_face(_orig_face), flipped(_flipped) {
  41. };
  42. };
  43. std::list<face_data_t> faces;
  44. const carve::mesh::MeshSet<3> *src_a;
  45. const carve::mesh::MeshSet<3> *src_b;
  46. BaseCollector(const carve::mesh::MeshSet<3> *_src_a,
  47. const carve::mesh::MeshSet<3> *_src_b) : CSG::Collector(), src_a(_src_a), src_b(_src_b) {
  48. }
  49. virtual ~BaseCollector() {
  50. }
  51. void FWD(const carve::mesh::MeshSet<3>::face_t *orig_face,
  52. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  53. carve::geom3d::Vector /* normal */,
  54. bool /* poly_a */,
  55. FaceClass face_class,
  56. CSG::Hooks &hooks) {
  57. std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
  58. new_faces.reserve(1);
  59. new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), false));
  60. hooks.processOutputFace(new_faces, orig_face, false);
  61. for (size_t i = 0; i < new_faces.size(); ++i) {
  62. faces.push_back(face_data_t(new_faces[i], orig_face, false));
  63. }
  64. #if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
  65. std::cerr << "+" << ENUM(face_class) << " ";
  66. for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
  67. std::cerr << std::endl;
  68. #endif
  69. }
  70. void REV(const carve::mesh::MeshSet<3>::face_t *orig_face,
  71. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  72. carve::geom3d::Vector /* normal */,
  73. bool /* poly_a */,
  74. FaceClass face_class,
  75. CSG::Hooks &hooks) {
  76. // normal = -normal;
  77. std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
  78. new_faces.reserve(1);
  79. new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), true));
  80. hooks.processOutputFace(new_faces, orig_face, true);
  81. for (size_t i = 0; i < new_faces.size(); ++i) {
  82. faces.push_back(face_data_t(new_faces[i], orig_face, true));
  83. }
  84. #if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
  85. std::cerr << "-" << ENUM(face_class) << " ";
  86. for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
  87. std::cerr << std::endl;
  88. #endif
  89. }
  90. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  91. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  92. carve::geom3d::Vector normal,
  93. bool poly_a,
  94. FaceClass face_class,
  95. CSG::Hooks &hooks) =0;
  96. virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
  97. std::list<ClassificationInfo> &cinfo = (grp->classification);
  98. if (cinfo.size() == 0) {
  99. std::cerr << "WARNING! group " << grp << " has no classification info!" << std::endl;
  100. return;
  101. }
  102. FaceClass fc = FACE_UNCLASSIFIED;
  103. unsigned fc_closed_bits = 0;
  104. unsigned fc_open_bits = 0;
  105. unsigned fc_bits = 0;
  106. for (std::list<ClassificationInfo>::const_iterator i = grp->classification.begin(), e = grp->classification.end(); i != e; ++i) {
  107. if ((*i).intersected_mesh == NULL) {
  108. // classifier only returns global info
  109. fc_closed_bits = class_to_class_bit((*i).classification);
  110. break;
  111. }
  112. if ((*i).classification == FACE_UNCLASSIFIED) continue;
  113. if ((*i).intersectedMeshIsClosed()) {
  114. fc_closed_bits |= class_to_class_bit((*i).classification);
  115. } else {
  116. fc_open_bits |= class_to_class_bit((*i).classification);
  117. }
  118. }
  119. if (fc_closed_bits) {
  120. fc_bits = fc_closed_bits;
  121. } else {
  122. fc_bits = fc_open_bits;
  123. }
  124. fc = class_bit_to_class(fc_bits);
  125. // handle the complex cases where a group is classified differently with respect to two or more closed manifolds.
  126. if (fc == FACE_UNCLASSIFIED) {
  127. unsigned inout_bits = fc_bits & FACE_NOT_ON_BIT;
  128. unsigned on_bits = fc_bits & FACE_ON_BIT;
  129. // both in and out. indicates an invalid manifold embedding.
  130. if (inout_bits == (FACE_IN_BIT | FACE_OUT_BIT)) goto out;
  131. // on, both orientations. could be caused by two manifolds touching at a face.
  132. if (on_bits == (FACE_ON_ORIENT_IN_BIT | FACE_ON_ORIENT_OUT_BIT)) goto out;
  133. // in or out, but also on (with orientation). the on classification takes precedence.
  134. fc = class_bit_to_class(on_bits);
  135. }
  136. out:
  137. if (fc == FACE_UNCLASSIFIED) {
  138. std::cerr << "group " << grp << " is unclassified!" << std::endl;
  139. #if defined(CARVE_DEBUG_WRITE_PLY_DATA)
  140. static int uc_count = 0;
  141. std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
  142. for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
  143. carve::mesh::MeshSet<3>::face_t *temp = f->orig_face->create(f->vertices.begin(), f->vertices.end(), false);
  144. faces.push_back(temp);
  145. }
  146. carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(faces);
  147. std::ostringstream filename;
  148. filename << "classifier_fail_" << ++uc_count << ".ply";
  149. std::string out(filename.str().c_str());
  150. ::writePLY(out, p, false);
  151. delete p;
  152. #endif
  153. return;
  154. }
  155. bool is_poly_a = grp->src == src_a;
  156. for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
  157. collect(f->orig_face, f->vertices, f->orig_face->plane.N, is_poly_a, fc, hooks);
  158. }
  159. }
  160. virtual carve::mesh::MeshSet<3> *done(CSG::Hooks &hooks) {
  161. std::vector<carve::mesh::MeshSet<3>::face_t *> f;
  162. f.reserve(faces.size());
  163. for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
  164. f.push_back((*i).face);
  165. }
  166. carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(f);
  167. if (hooks.hasHook(carve::csg::CSG::Hooks::RESULT_FACE_HOOK)) {
  168. for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
  169. hooks.resultFace((*i).face, (*i).orig_face, (*i).flipped);
  170. }
  171. }
  172. return p;
  173. }
  174. };
  175. class AllCollector : public BaseCollector {
  176. public:
  177. AllCollector(const carve::mesh::MeshSet<3> *_src_a,
  178. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  179. }
  180. virtual ~AllCollector() {
  181. }
  182. virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
  183. for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
  184. FWD(f->orig_face, f->vertices, f->orig_face->plane.N, f->orig_face->mesh->meshset == src_a, FACE_OUT, hooks);
  185. }
  186. }
  187. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  188. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  189. carve::geom3d::Vector normal,
  190. bool poly_a,
  191. FaceClass face_class,
  192. CSG::Hooks &hooks) {
  193. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  194. }
  195. };
  196. class UnionCollector : public BaseCollector {
  197. public:
  198. UnionCollector(const carve::mesh::MeshSet<3> *_src_a,
  199. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  200. }
  201. virtual ~UnionCollector() {
  202. }
  203. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  204. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  205. carve::geom3d::Vector normal,
  206. bool poly_a,
  207. FaceClass face_class,
  208. CSG::Hooks &hooks) {
  209. if (face_class == FACE_OUT || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
  210. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  211. }
  212. }
  213. };
  214. class IntersectionCollector : public BaseCollector {
  215. public:
  216. IntersectionCollector(const carve::mesh::MeshSet<3> *_src_a,
  217. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  218. }
  219. virtual ~IntersectionCollector() {
  220. }
  221. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  222. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  223. carve::geom3d::Vector normal,
  224. bool poly_a,
  225. FaceClass face_class,
  226. CSG::Hooks &hooks) {
  227. if (face_class == FACE_IN || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
  228. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  229. }
  230. }
  231. };
  232. class SymmetricDifferenceCollector : public BaseCollector {
  233. public:
  234. SymmetricDifferenceCollector(const carve::mesh::MeshSet<3> *_src_a,
  235. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  236. }
  237. virtual ~SymmetricDifferenceCollector() {
  238. }
  239. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  240. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  241. carve::geom3d::Vector normal,
  242. bool poly_a,
  243. FaceClass face_class,
  244. CSG::Hooks &hooks) {
  245. if (face_class == FACE_OUT) {
  246. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  247. } else if (face_class == FACE_IN) {
  248. REV(orig_face, vertices, normal, poly_a, face_class, hooks);
  249. }
  250. }
  251. };
  252. class AMinusBCollector : public BaseCollector {
  253. public:
  254. AMinusBCollector(const carve::mesh::MeshSet<3> *_src_a,
  255. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  256. }
  257. virtual ~AMinusBCollector() {
  258. }
  259. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  260. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  261. carve::geom3d::Vector normal,
  262. bool poly_a,
  263. FaceClass face_class,
  264. CSG::Hooks &hooks) {
  265. if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && poly_a) {
  266. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  267. } else if (face_class == FACE_IN && !poly_a) {
  268. REV(orig_face, vertices, normal, poly_a, face_class, hooks);
  269. }
  270. }
  271. };
  272. class BMinusACollector : public BaseCollector {
  273. public:
  274. BMinusACollector(const carve::mesh::MeshSet<3> *_src_a,
  275. const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
  276. }
  277. virtual ~BMinusACollector() {
  278. }
  279. virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
  280. const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
  281. carve::geom3d::Vector normal,
  282. bool poly_a,
  283. FaceClass face_class,
  284. CSG::Hooks &hooks) {
  285. if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && !poly_a) {
  286. FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
  287. } else if (face_class == FACE_IN && poly_a) {
  288. REV(orig_face, vertices, normal, poly_a, face_class, hooks);
  289. }
  290. }
  291. };
  292. }
  293. CSG::Collector *makeCollector(CSG::OP op,
  294. const carve::mesh::MeshSet<3> *poly_a,
  295. const carve::mesh::MeshSet<3> *poly_b) {
  296. switch (op) {
  297. case CSG::UNION: return new UnionCollector(poly_a, poly_b);
  298. case CSG::INTERSECTION: return new IntersectionCollector(poly_a, poly_b);
  299. case CSG::A_MINUS_B: return new AMinusBCollector(poly_a, poly_b);
  300. case CSG::B_MINUS_A: return new BMinusACollector(poly_a, poly_b);
  301. case CSG::SYMMETRIC_DIFFERENCE: return new SymmetricDifferenceCollector(poly_a, poly_b);
  302. case CSG::ALL: return new AllCollector(poly_a, poly_b);
  303. }
  304. return NULL;
  305. }
  306. }
  307. }