manifold.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Copyright 2021 The Manifold Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #pragma once
  15. #include <functional>
  16. #include <memory>
  17. #include "manifold/common.h"
  18. #include "manifold/vec_view.h"
  19. namespace manifold {
  20. /**
  21. * @ingroup Debug
  22. *
  23. * Allows modification of the assertions checked in MANIFOLD_DEBUG mode.
  24. *
  25. * @return ExecutionParams&
  26. */
  27. ExecutionParams& ManifoldParams();
  28. class CsgNode;
  29. class CsgLeafNode;
  30. /** @addtogroup Core
  31. * @brief The central classes of the library
  32. * @{
  33. */
  34. /**
  35. * @brief Mesh input/output suitable for pushing directly into graphics
  36. * libraries.
  37. *
  38. * This may not be manifold since the verts are duplicated along property
  39. * boundaries that do not match. The additional merge vectors store this missing
  40. * information, allowing the manifold to be reconstructed. MeshGL is an alias
  41. * for the standard single-precision version. Use MeshGL64 to output the full
  42. * double precision that Manifold uses internally.
  43. */
  44. template <typename Precision, typename I = uint32_t>
  45. struct MeshGLP {
  46. /// Number of property vertices
  47. I NumVert() const { return vertProperties.size() / numProp; };
  48. /// Number of triangles
  49. I NumTri() const { return triVerts.size() / 3; };
  50. /// Number of properties per vertex, always >= 3.
  51. I numProp = 3;
  52. /// Flat, GL-style interleaved list of all vertex properties: propVal =
  53. /// vertProperties[vert * numProp + propIdx]. The first three properties are
  54. /// always the position x, y, z.
  55. std::vector<Precision> vertProperties;
  56. /// The vertex indices of the three triangle corners in CCW (from the outside)
  57. /// order, for each triangle.
  58. std::vector<I> triVerts;
  59. /// Optional: A list of only the vertex indicies that need to be merged to
  60. /// reconstruct the manifold.
  61. std::vector<I> mergeFromVert;
  62. /// Optional: The same length as mergeFromVert, and the corresponding value
  63. /// contains the vertex to merge with. It will have an identical position, but
  64. /// the other properties may differ.
  65. std::vector<I> mergeToVert;
  66. /// Optional: Indicates runs of triangles that correspond to a particular
  67. /// input mesh instance. The runs encompass all of triVerts and are sorted
  68. /// by runOriginalID. Run i begins at triVerts[runIndex[i]] and ends at
  69. /// triVerts[runIndex[i+1]]. All runIndex values are divisible by 3. Returned
  70. /// runIndex will always be 1 longer than runOriginalID, but same length is
  71. /// also allowed as input: triVerts.size() will be automatically appended in
  72. /// this case.
  73. std::vector<I> runIndex;
  74. /// Optional: The OriginalID of the mesh this triangle run came from. This ID
  75. /// is ideal for reapplying materials to the output mesh. Multiple runs may
  76. /// have the same ID, e.g. representing different copies of the same input
  77. /// mesh. If you create an input MeshGL that you want to be able to reference
  78. /// as one or more originals, be sure to set unique values from ReserveIDs().
  79. std::vector<uint32_t> runOriginalID;
  80. /// Optional: For each run, a 3x4 transform is stored representing how the
  81. /// corresponding original mesh was transformed to create this triangle run.
  82. /// This matrix is stored in column-major order and the length of the overall
  83. /// vector is 12 * runOriginalID.size().
  84. std::vector<Precision> runTransform;
  85. /// Optional: Length NumTri, contains the source face ID this
  86. /// triangle comes from. When auto-generated, this ID will be a triangle index
  87. /// into the original mesh. This index/ID is purely for external use (e.g.
  88. /// recreating polygonal faces) and will not affect Manifold's algorithms.
  89. std::vector<I> faceID;
  90. /// Optional: The X-Y-Z-W weighted tangent vectors for smooth Refine(). If
  91. /// non-empty, must be exactly four times as long as Mesh.triVerts. Indexed
  92. /// as 4 * (3 * tri + i) + j, i < 3, j < 4, representing the tangent value
  93. /// Mesh.triVerts[tri][i] along the CCW edge. If empty, mesh is faceted.
  94. std::vector<Precision> halfedgeTangent;
  95. /// Tolerance for mesh simplification. When creating a Manifold, the tolerance
  96. /// used will be the maximum of this and a baseline tolerance from the size of
  97. /// the bounding box. Any edge shorter than tolerance may be collapsed.
  98. /// Tolerance may be enlarged when floating point error accumulates.
  99. Precision tolerance = 0;
  100. MeshGLP() = default;
  101. /**
  102. * Updates the mergeFromVert and mergeToVert vectors in order to create a
  103. * manifold solid. If the MeshGL is already manifold, no change will occur and
  104. * the function will return false. Otherwise, this will merge verts along open
  105. * edges within tolerance (the maximum of the MeshGL tolerance and the
  106. * baseline bounding-box tolerance), keeping any from the existing merge
  107. * vectors, and return true.
  108. *
  109. * There is no guarantee the result will be manifold - this is a best-effort
  110. * helper function designed primarily to aid in the case where a manifold
  111. * multi-material MeshGL was produced, but its merge vectors were lost due to
  112. * a round-trip through a file format. Constructing a Manifold from the result
  113. * will report an error status if it is not manifold.
  114. */
  115. bool Merge();
  116. /**
  117. * Returns the x, y, z position of the ith vertex.
  118. *
  119. * @param v vertex index.
  120. */
  121. la::vec<Precision, 3> GetVertPos(size_t v) const {
  122. size_t offset = v * numProp;
  123. return la::vec<Precision, 3>(vertProperties[offset],
  124. vertProperties[offset + 1],
  125. vertProperties[offset + 2]);
  126. }
  127. /**
  128. * Returns the three vertex indices of the ith triangle.
  129. *
  130. * @param t triangle index.
  131. */
  132. la::vec<I, 3> GetTriVerts(size_t t) const {
  133. size_t offset = 3 * t;
  134. return la::vec<I, 3>(triVerts[offset], triVerts[offset + 1],
  135. triVerts[offset + 2]);
  136. }
  137. /**
  138. * Returns the x, y, z, w tangent of the ith halfedge.
  139. *
  140. * @param h halfedge index (3 * triangle_index + [0|1|2]).
  141. */
  142. la::vec<Precision, 4> GetTangent(size_t h) const {
  143. size_t offset = 4 * h;
  144. return la::vec<Precision, 4>(
  145. halfedgeTangent[offset], halfedgeTangent[offset + 1],
  146. halfedgeTangent[offset + 2], halfedgeTangent[offset + 3]);
  147. }
  148. };
  149. /**
  150. * @brief Single-precision - ideal for most uses, especially graphics.
  151. */
  152. using MeshGL = MeshGLP<float>;
  153. /**
  154. * @brief Double-precision, 64-bit indices - best for huge meshes.
  155. */
  156. using MeshGL64 = MeshGLP<double, uint64_t>;
  157. /**
  158. * @brief This library's internal representation of an oriented, 2-manifold,
  159. * triangle mesh - a simple boundary-representation of a solid object. Use this
  160. * class to store and operate on solids, and use MeshGL for input and output.
  161. *
  162. * In addition to storing geometric data, a Manifold can also store an arbitrary
  163. * number of vertex properties. These could be anything, e.g. normals, UV
  164. * coordinates, colors, etc, but this library is completely agnostic. All
  165. * properties are merely float values indexed by channel number. It is up to the
  166. * user to associate channel numbers with meaning.
  167. *
  168. * Manifold allows vertex properties to be shared for efficient storage, or to
  169. * have multiple property verts associated with a single geometric vertex,
  170. * allowing sudden property changes, e.g. at Boolean intersections, without
  171. * sacrificing manifoldness.
  172. *
  173. * Manifolds also keep track of their relationships to their inputs, via
  174. * OriginalIDs and the faceIDs and transforms accessible through MeshGL. This
  175. * allows object-level properties to be re-associated with the output after many
  176. * operations, particularly useful for materials. Since separate object's
  177. * properties are not mixed, there is no requirement that channels have
  178. * consistent meaning between different inputs.
  179. */
  180. class Manifold {
  181. public:
  182. /** @name Basics
  183. * Copy / move / assignment
  184. */
  185. ///@{
  186. Manifold();
  187. ~Manifold();
  188. Manifold(const Manifold& other);
  189. Manifold& operator=(const Manifold& other);
  190. Manifold(Manifold&&) noexcept;
  191. Manifold& operator=(Manifold&&) noexcept;
  192. ///@}
  193. /** @name Input & Output
  194. * Create and retrieve arbitrary manifolds
  195. */
  196. ///@{
  197. Manifold(const MeshGL&);
  198. Manifold(const MeshGL64&);
  199. MeshGL GetMeshGL(int normalIdx = -1) const;
  200. MeshGL64 GetMeshGL64(int normalIdx = -1) const;
  201. ///@}
  202. /** @name Constructors
  203. * Topological ops, primitives, and SDF
  204. */
  205. ///@{
  206. std::vector<Manifold> Decompose() const;
  207. static Manifold Compose(const std::vector<Manifold>&);
  208. static Manifold Tetrahedron();
  209. static Manifold Cube(vec3 size = vec3(1.0), bool center = false);
  210. static Manifold Cylinder(double height, double radiusLow,
  211. double radiusHigh = -1.0, int circularSegments = 0,
  212. bool center = false);
  213. static Manifold Sphere(double radius, int circularSegments = 0);
  214. static Manifold LevelSet(std::function<double(vec3)> sdf, Box bounds,
  215. double edgeLength, double level = 0,
  216. double tolerance = -1, bool canParallel = true);
  217. ///@}
  218. /** @name Polygons
  219. * 3D to 2D and 2D to 3D
  220. */
  221. ///@{
  222. Polygons Slice(double height = 0) const;
  223. Polygons Project() const;
  224. static Manifold Extrude(const Polygons& crossSection, double height,
  225. int nDivisions = 0, double twistDegrees = 0.0,
  226. vec2 scaleTop = vec2(1.0));
  227. static Manifold Revolve(const Polygons& crossSection,
  228. int circularSegments = 0,
  229. double revolveDegrees = 360.0f);
  230. ///@}
  231. enum class Error {
  232. NoError,
  233. NonFiniteVertex,
  234. NotManifold,
  235. VertexOutOfBounds,
  236. PropertiesWrongLength,
  237. MissingPositionProperties,
  238. MergeVectorsDifferentLengths,
  239. MergeIndexOutOfBounds,
  240. TransformWrongLength,
  241. RunIndexWrongLength,
  242. FaceIDWrongLength,
  243. InvalidConstruction,
  244. };
  245. /** @name Information
  246. * Details of the manifold
  247. */
  248. ///@{
  249. Error Status() const;
  250. bool IsEmpty() const;
  251. size_t NumVert() const;
  252. size_t NumEdge() const;
  253. size_t NumTri() const;
  254. size_t NumProp() const;
  255. size_t NumPropVert() const;
  256. Box BoundingBox() const;
  257. int Genus() const;
  258. double GetTolerance() const;
  259. ///@}
  260. /** @name Measurement
  261. */
  262. ///@{
  263. double SurfaceArea() const;
  264. double Volume() const;
  265. double MinGap(const Manifold& other, double searchLength) const;
  266. ///@}
  267. /** @name Mesh ID
  268. * Details of the manifold's relation to its input meshes, for the purposes
  269. * of reapplying mesh properties.
  270. */
  271. ///@{
  272. int OriginalID() const;
  273. Manifold AsOriginal() const;
  274. static uint32_t ReserveIDs(uint32_t);
  275. ///@}
  276. /** @name Transformations
  277. */
  278. ///@{
  279. Manifold Translate(vec3) const;
  280. Manifold Scale(vec3) const;
  281. Manifold Rotate(double xDegrees, double yDegrees = 0.0,
  282. double zDegrees = 0.0) const;
  283. Manifold Mirror(vec3) const;
  284. Manifold Transform(const mat3x4&) const;
  285. Manifold Warp(std::function<void(vec3&)>) const;
  286. Manifold WarpBatch(std::function<void(VecView<vec3>)>) const;
  287. Manifold SetTolerance(double) const;
  288. ///@}
  289. /** @name Boolean
  290. * Combine two manifolds
  291. */
  292. ///@{
  293. Manifold Boolean(const Manifold& second, OpType op) const;
  294. static Manifold BatchBoolean(const std::vector<Manifold>& manifolds,
  295. OpType op);
  296. // Boolean operation shorthand
  297. Manifold operator+(const Manifold&) const; // Add (Union)
  298. Manifold& operator+=(const Manifold&);
  299. Manifold operator-(const Manifold&) const; // Subtract (Difference)
  300. Manifold& operator-=(const Manifold&);
  301. Manifold operator^(const Manifold&) const; // Intersect
  302. Manifold& operator^=(const Manifold&);
  303. std::pair<Manifold, Manifold> Split(const Manifold&) const;
  304. std::pair<Manifold, Manifold> SplitByPlane(vec3 normal,
  305. double originOffset) const;
  306. Manifold TrimByPlane(vec3 normal, double originOffset) const;
  307. ///@}
  308. /** @name Properties
  309. * Create and modify vertex properties.
  310. */
  311. ///@{
  312. Manifold SetProperties(
  313. int numProp,
  314. std::function<void(double*, vec3, const double*)> propFunc) const;
  315. Manifold CalculateCurvature(int gaussianIdx, int meanIdx) const;
  316. Manifold CalculateNormals(int normalIdx, double minSharpAngle = 60) const;
  317. ///@}
  318. /** @name Smoothing
  319. * Smooth meshes by calculating tangent vectors and refining to a higher
  320. * triangle count.
  321. */
  322. ///@{
  323. Manifold Refine(int) const;
  324. Manifold RefineToLength(double) const;
  325. Manifold RefineToTolerance(double) const;
  326. Manifold SmoothByNormals(int normalIdx) const;
  327. Manifold SmoothOut(double minSharpAngle = 60, double minSmoothness = 0) const;
  328. static Manifold Smooth(const MeshGL&,
  329. const std::vector<Smoothness>& sharpenedEdges = {});
  330. static Manifold Smooth(const MeshGL64&,
  331. const std::vector<Smoothness>& sharpenedEdges = {});
  332. ///@}
  333. /** @name Convex Hull
  334. */
  335. ///@{
  336. Manifold Hull() const;
  337. static Manifold Hull(const std::vector<Manifold>& manifolds);
  338. static Manifold Hull(const std::vector<vec3>& pts);
  339. ///@}
  340. /** @name Testing Hooks
  341. * These are just for internal testing.
  342. */
  343. ///@{
  344. bool MatchesTriNormals() const;
  345. size_t NumDegenerateTris() const;
  346. size_t NumOverlaps(const Manifold& second) const;
  347. double GetEpsilon() const;
  348. ///@}
  349. struct Impl;
  350. private:
  351. Manifold(std::shared_ptr<CsgNode> pNode_);
  352. Manifold(std::shared_ptr<Impl> pImpl_);
  353. static Manifold Invalid();
  354. mutable std::shared_ptr<CsgNode> pNode_;
  355. CsgLeafNode& GetCsgLeafNode() const;
  356. };
  357. /** @} */
  358. /** @addtogroup Debug
  359. * @ingroup Optional
  360. * @brief Debugging features
  361. *
  362. * The features require compiler flags to be enabled. Assertions are enabled
  363. * with the MANIFOLD_DEBUG flag and then controlled with ExecutionParams.
  364. * @{
  365. */
  366. #ifdef MANIFOLD_DEBUG
  367. inline std::string ToString(const Manifold::Error& error) {
  368. switch (error) {
  369. case Manifold::Error::NoError:
  370. return "No Error";
  371. case Manifold::Error::NonFiniteVertex:
  372. return "Non Finite Vertex";
  373. case Manifold::Error::NotManifold:
  374. return "Not Manifold";
  375. case Manifold::Error::VertexOutOfBounds:
  376. return "Vertex Out Of Bounds";
  377. case Manifold::Error::PropertiesWrongLength:
  378. return "Properties Wrong Length";
  379. case Manifold::Error::MissingPositionProperties:
  380. return "Missing Position Properties";
  381. case Manifold::Error::MergeVectorsDifferentLengths:
  382. return "Merge Vectors Different Lengths";
  383. case Manifold::Error::MergeIndexOutOfBounds:
  384. return "Merge Index Out Of Bounds";
  385. case Manifold::Error::TransformWrongLength:
  386. return "Transform Wrong Length";
  387. case Manifold::Error::RunIndexWrongLength:
  388. return "Run Index Wrong Length";
  389. case Manifold::Error::FaceIDWrongLength:
  390. return "Face ID Wrong Length";
  391. case Manifold::Error::InvalidConstruction:
  392. return "Invalid Construction";
  393. default:
  394. return "Unknown Error";
  395. };
  396. }
  397. inline std::ostream& operator<<(std::ostream& stream,
  398. const Manifold::Error& error) {
  399. return stream << ToString(error);
  400. }
  401. #endif
  402. /** @} */
  403. } // namespace manifold