Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
311d25a8cf | ||
|
|
6fa0e7becb | ||
|
|
e425761d8e | ||
|
|
a4cc9ee54b | ||
|
|
2a7f9cf48f | ||
|
|
99740dafcb | ||
|
|
9157350a11 | ||
|
|
f6cf8d23d3 |
Vendored
-4
@@ -140,8 +140,4 @@
|
||||
"Verts"
|
||||
],
|
||||
"javascript.format.semicolons": "insert",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
},
|
||||
"python.formatting.provider": "none",
|
||||
}
|
||||
@@ -99,7 +99,7 @@ node test/manifold_test.js
|
||||
### Python
|
||||
|
||||
The CMake script will build the python binding `manifold3d` automatically. To
|
||||
use the extension, please add `$BUILD_DIR/bindings/python` to your `PYTHONPATH`, where
|
||||
use the extension, please add `$BUILD_DIR/tools` to your `PYTHONPATH`, where
|
||||
`$BUILD_DIR` is the build directory for CMake. Examples using the python binding
|
||||
can be found in `bindings/python/examples`. To see exported samples, run:
|
||||
```
|
||||
|
||||
@@ -106,30 +106,6 @@ ManifoldCrossSection *manifold_cross_section_intersection(
|
||||
return to_c(new (mem) CrossSection(cs));
|
||||
}
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_hull(void *mem,
|
||||
ManifoldCrossSection *cs) {
|
||||
auto hulled = from_c(cs)->Hull();
|
||||
return to_c(new (mem) CrossSection(hulled));
|
||||
}
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_batch_hull(
|
||||
void *mem, ManifoldCrossSectionVec *css) {
|
||||
auto hulled = CrossSection::Hull(*from_c(css));
|
||||
return to_c(new (mem) CrossSection(hulled));
|
||||
}
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_hull_simple_polygon(
|
||||
void *mem, ManifoldSimplePolygon *ps) {
|
||||
auto hulled = CrossSection::Hull(*from_c(ps));
|
||||
return to_c(new (mem) CrossSection(hulled));
|
||||
}
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_hull_polygons(
|
||||
void *mem, ManifoldPolygons *ps) {
|
||||
auto hulled = CrossSection::Hull(*from_c(ps));
|
||||
return to_c(new (mem) CrossSection(hulled));
|
||||
}
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_translate(void *mem,
|
||||
ManifoldCrossSection *cs,
|
||||
float x, float y) {
|
||||
|
||||
@@ -8,7 +8,6 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
// Polygons
|
||||
|
||||
ManifoldSimplePolygon *manifold_simple_polygon(void *mem, ManifoldVec2 *ps,
|
||||
size_t length);
|
||||
ManifoldPolygons *manifold_polygons(void *mem, ManifoldSimplePolygon **ps,
|
||||
@@ -25,7 +24,6 @@ ManifoldVec2 manifold_polygons_get_point(ManifoldPolygons *ps, int simple_idx,
|
||||
int pt_idx);
|
||||
|
||||
// Mesh Construction
|
||||
|
||||
ManifoldMeshGL *manifold_meshgl(void *mem, float *vert_props, size_t n_verts,
|
||||
size_t n_props, uint32_t *tri_verts,
|
||||
size_t n_tris);
|
||||
@@ -96,14 +94,7 @@ ManifoldManifold *manifold_trim_by_plane(void *mem, ManifoldManifold *m,
|
||||
float normal_x, float normal_y,
|
||||
float normal_z, float offset);
|
||||
|
||||
// Convex Hulls
|
||||
|
||||
ManifoldManifold *manifold_hull(void *mem, ManifoldManifold *m);
|
||||
ManifoldManifold *manifold_batch_hull(void *mem, ManifoldManifoldVec *ms);
|
||||
ManifoldManifold *manifold_hull_pts(void *mem, ManifoldVec3 *ps, size_t length);
|
||||
|
||||
// Manifold Transformations
|
||||
|
||||
ManifoldManifold *manifold_translate(void *mem, ManifoldManifold *m, float x,
|
||||
float y, float z);
|
||||
ManifoldManifold *manifold_rotate(void *mem, ManifoldManifold *m, float x,
|
||||
@@ -121,7 +112,6 @@ ManifoldManifold *manifold_warp(void *mem, ManifoldManifold *m,
|
||||
ManifoldManifold *manifold_refine(void *mem, ManifoldManifold *m, int refine);
|
||||
|
||||
// Manifold Shapes / Constructors
|
||||
|
||||
ManifoldManifold *manifold_empty(void *mem);
|
||||
ManifoldManifold *manifold_copy(void *mem, ManifoldManifold *m);
|
||||
ManifoldManifold *manifold_tetrahedron(void *mem);
|
||||
@@ -147,7 +137,6 @@ ManifoldManifoldVec *manifold_decompose(void *mem, ManifoldManifold *m);
|
||||
ManifoldManifold *manifold_as_original(void *mem, ManifoldManifold *m);
|
||||
|
||||
// Manifold Info
|
||||
|
||||
int manifold_is_empty(ManifoldManifold *m);
|
||||
ManifoldError manifold_status(ManifoldManifold *m);
|
||||
int manifold_num_vert(ManifoldManifold *m);
|
||||
@@ -215,17 +204,6 @@ ManifoldCrossSection *manifold_cross_section_difference(
|
||||
ManifoldCrossSection *manifold_cross_section_intersection(
|
||||
void *mem, ManifoldCrossSection *a, ManifoldCrossSection *b);
|
||||
|
||||
// CrossSection Convex Hulls
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_hull(void *mem,
|
||||
ManifoldCrossSection *cs);
|
||||
ManifoldCrossSection *manifold_cross_section_batch_hull(
|
||||
void *mem, ManifoldCrossSectionVec *css);
|
||||
ManifoldCrossSection *manifold_cross_section_hull_simple_polygon(
|
||||
void *mem, ManifoldSimplePolygon *ps);
|
||||
ManifoldCrossSection *manifold_cross_section_hull_polygons(
|
||||
void *mem, ManifoldPolygons *ps);
|
||||
|
||||
// CrossSection Transformation
|
||||
|
||||
ManifoldCrossSection *manifold_cross_section_translate(void *mem,
|
||||
@@ -290,7 +268,6 @@ ManifoldCrossSection *manifold_rect_as_cross_section(void *mem,
|
||||
ManifoldRect *r);
|
||||
|
||||
// Bounding Box
|
||||
|
||||
ManifoldBox *manifold_box(void *mem, float x1, float y1, float z1, float x2,
|
||||
float y2, float z2);
|
||||
ManifoldVec3 manifold_box_min(ManifoldBox *b);
|
||||
@@ -315,13 +292,11 @@ int manifold_box_does_overlap_box(ManifoldBox *a, ManifoldBox *b);
|
||||
int manifold_box_is_finite(ManifoldBox *b);
|
||||
|
||||
// Static Quality Globals
|
||||
|
||||
void manifold_set_min_circular_angle(float degrees);
|
||||
void manifold_set_min_circular_edge_length(float length);
|
||||
void manifold_set_circular_segments(int number);
|
||||
|
||||
// Manifold Mesh Extraction
|
||||
|
||||
int manifold_meshgl_num_prop(ManifoldMeshGL *m);
|
||||
int manifold_meshgl_num_vert(ManifoldMeshGL *m);
|
||||
int manifold_meshgl_num_tri(ManifoldMeshGL *m);
|
||||
@@ -344,7 +319,6 @@ uint32_t *manifold_meshgl_face_id(void *mem, ManifoldMeshGL *m);
|
||||
float *manifold_meshgl_halfedge_tangent(void *mem, ManifoldMeshGL *m);
|
||||
|
||||
// memory size
|
||||
|
||||
size_t manifold_manifold_size();
|
||||
size_t manifold_manifold_vec_size();
|
||||
size_t manifold_cross_section_size();
|
||||
@@ -358,7 +332,6 @@ size_t manifold_rect_size();
|
||||
size_t manifold_curvature_size();
|
||||
|
||||
// destruction
|
||||
|
||||
void manifold_destruct_manifold(ManifoldManifold *m);
|
||||
void manifold_destruct_manifold_vec(ManifoldManifoldVec *ms);
|
||||
void manifold_destruct_cross_section(ManifoldCrossSection *m);
|
||||
@@ -370,7 +343,6 @@ void manifold_destruct_box(ManifoldBox *b);
|
||||
void manifold_destruct_rect(ManifoldRect *b);
|
||||
|
||||
// pointer free + destruction
|
||||
|
||||
void manifold_delete_manifold(ManifoldManifold *m);
|
||||
void manifold_delete_manifold_vec(ManifoldManifoldVec *ms);
|
||||
void manifold_delete_cross_section(ManifoldCrossSection *cs);
|
||||
@@ -382,7 +354,6 @@ void manifold_delete_box(ManifoldBox *b);
|
||||
void manifold_delete_rect(ManifoldRect *b);
|
||||
|
||||
// MeshIO / Export
|
||||
|
||||
#ifdef MANIFOLD_EXPORT
|
||||
ManifoldMaterial *manifold_material(void *mem);
|
||||
void manifold_material_set_roughness(ManifoldMaterial *mat, float roughness);
|
||||
|
||||
@@ -190,26 +190,6 @@ ManifoldManifold *manifold_trim_by_plane(void *mem, ManifoldManifold *m,
|
||||
return to_c(new (mem) Manifold(trimmed));
|
||||
}
|
||||
|
||||
ManifoldManifold *manifold_hull(void *mem, ManifoldManifold *m) {
|
||||
auto hulled = from_c(m)->Hull();
|
||||
return to_c(new (mem) Manifold(hulled));
|
||||
}
|
||||
|
||||
ManifoldManifold *manifold_batch_hull(void *mem, ManifoldManifoldVec *ms) {
|
||||
auto hulled = Manifold::Hull(*from_c(ms));
|
||||
return to_c(new (mem) Manifold(hulled));
|
||||
}
|
||||
|
||||
ManifoldManifold *manifold_hull_pts(void *mem, ManifoldVec3 *ps,
|
||||
size_t length) {
|
||||
std::vector<glm::vec3> vec(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
vec[i] = {ps[i].x, ps[i].y, ps[i].z};
|
||||
}
|
||||
auto hulled = Manifold::Hull(vec);
|
||||
return to_c(new (mem) Manifold(hulled));
|
||||
}
|
||||
|
||||
ManifoldManifold *manifold_translate(void *mem, ManifoldManifold *m, float x,
|
||||
float y, float z) {
|
||||
auto v = glm::vec3(x, y, z);
|
||||
|
||||
@@ -36,13 +36,10 @@ if __name__ == "__main__":
|
||||
mesh = model.to_mesh()
|
||||
if export_models:
|
||||
if mesh.vert_properties.shape[1] > 3:
|
||||
vertices = mesh.vert_properties[:, :3]
|
||||
colors = (mesh.vert_properties[:, 3:] * 255).astype(np.uint8)
|
||||
vertices = np.hsplit(mesh.vert_properties, 3)[0]
|
||||
else:
|
||||
vertices = mesh.vert_properties
|
||||
colors = None
|
||||
meshOut = trimesh.Trimesh(vertices=vertices, faces=mesh.tri_verts,
|
||||
vertex_colors=colors)
|
||||
meshOut = trimesh.Trimesh(vertices=vertices, faces=mesh.tri_verts)
|
||||
trimesh.exchange.export.export_mesh(meshOut, f'{f}.glb', 'glb')
|
||||
print(f'Exported model to {f}.glb')
|
||||
t1 = time()
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
from manifold3d import Manifold
|
||||
import numpy as np
|
||||
|
||||
|
||||
def fractal(holes, hole, w, position, depth, maxDepth):
|
||||
w /= 3
|
||||
holes.append(hole.scale([w, w, 1.0]).translate(
|
||||
[position[0], position[1], 0.0]))
|
||||
if depth == maxDepth:
|
||||
return
|
||||
offsets = np.array([
|
||||
[-w, -w],
|
||||
[-w, 0.0],
|
||||
[-w, w],
|
||||
[0.0, w],
|
||||
[w, w],
|
||||
[w, 0.0],
|
||||
[w, -w],
|
||||
[0.0, -w],
|
||||
])
|
||||
for offset in offsets:
|
||||
fractal(holes, hole, w, position + offset, depth + 1, maxDepth)
|
||||
|
||||
|
||||
def posColors(pos, _):
|
||||
return [1 - p / 2 for p in pos] + [1.0]
|
||||
|
||||
|
||||
def run(n=1):
|
||||
result = Manifold.cube([1, 1, 1], True)
|
||||
holes = []
|
||||
fractal(holes, result, 1.0, np.array([0.0, 0.0]), 1, n)
|
||||
|
||||
hole = Manifold.compose(holes)
|
||||
|
||||
result -= hole
|
||||
result -= hole.rotate([90, 0, 0])
|
||||
result -= hole.rotate([0, 90, 0])
|
||||
|
||||
return result.trim_by_plane([1, 1, 1], 0).set_properties(4, posColors).scale(100)
|
||||
@@ -96,24 +96,6 @@ PYBIND11_MODULE(manifold3d, m) {
|
||||
.def(py::self + py::self, "Boolean union.")
|
||||
.def(py::self - py::self, "Boolean difference.")
|
||||
.def(py::self ^ py::self, "Boolean intersection.")
|
||||
.def(
|
||||
"hull", [](Manifold &self) { return self.Hull(); },
|
||||
"Compute the convex hull of all points in this manifold.")
|
||||
.def_static(
|
||||
"batch_hull",
|
||||
[](std::vector<Manifold> &ms) { return Manifold::Hull(ms); },
|
||||
"Compute the convex hull enveloping a set of manifolds.")
|
||||
.def_static(
|
||||
"hull_points",
|
||||
[](std::vector<Float3> &pts) {
|
||||
std::vector<glm::vec3> vec(pts.size());
|
||||
for (int i = 0; i < pts.size(); i++) {
|
||||
vec[i] = {std::get<0>(pts[i]), std::get<1>(pts[i]),
|
||||
std::get<2>(pts[i])};
|
||||
}
|
||||
return Manifold::Hull(vec);
|
||||
},
|
||||
"Compute the convex hull enveloping a set of 3d points.")
|
||||
.def(
|
||||
"transform",
|
||||
[](Manifold &self, py::array_t<float> &mat) {
|
||||
@@ -254,36 +236,6 @@ PYBIND11_MODULE(manifold3d, m) {
|
||||
"the user to choose their function with discretion."
|
||||
"\n\n"
|
||||
":param warpFunc: A function that modifies a given vertex position.")
|
||||
.def(
|
||||
"set_properties",
|
||||
[](Manifold &self, int newNumProp,
|
||||
const std::function<py::array_t<float>(
|
||||
Float3, const py::array_t<float> &)> &f) {
|
||||
const int oldNumProp = self.NumProp();
|
||||
return self.SetProperties(newNumProp, [newNumProp, oldNumProp, &f](
|
||||
float *newProps,
|
||||
glm::vec3 v,
|
||||
const float *oldProps) {
|
||||
auto array = f(std::make_tuple(v.x, v.y, v.z),
|
||||
py::array(oldNumProp, oldProps));
|
||||
if (array.ndim() != 1 || array.shape(0) != newNumProp)
|
||||
throw std::runtime_error("Invalid vector shape, expected (" +
|
||||
std::to_string(newNumProp) + ")");
|
||||
auto array_view = array.unchecked<1>();
|
||||
for (int i = 0; i < newNumProp; i++) newProps[i] = array_view(i);
|
||||
});
|
||||
},
|
||||
py::arg("new_num_prop"), py::arg("f"),
|
||||
"Create a new copy of this manifold with updated vertex properties "
|
||||
"by supplying a function that takes the existing position and "
|
||||
"properties as input. You may specify any number of output "
|
||||
"properties, allowing creation and removal of channels. Note: "
|
||||
"undefined behavior will result if you read past the number of input "
|
||||
"properties or write past the number of output properties."
|
||||
"\n\n"
|
||||
":param numProp: The new number of properties per vertex."
|
||||
":param propFunc: A function that modifies the properties of a given "
|
||||
"vertex.")
|
||||
.def(
|
||||
"refine", [](Manifold &self, int n) { return self.Refine(n); },
|
||||
py::arg("n"),
|
||||
@@ -458,13 +410,6 @@ PYBIND11_MODULE(manifold3d, m) {
|
||||
.def_static(
|
||||
"from_mesh", [](const MeshGL &mesh) { return Manifold(mesh); },
|
||||
py::arg("mesh"))
|
||||
.def_static(
|
||||
"compose",
|
||||
[](const std::vector<Manifold> &list) {
|
||||
return Manifold::Compose(list);
|
||||
},
|
||||
"combine several manifolds into one without checking for "
|
||||
"intersections.")
|
||||
.def_static(
|
||||
"tetrahedron", []() { return Manifold::Tetrahedron(); },
|
||||
"Constructs a tetrahedron centered at the origin with one vertex at "
|
||||
@@ -841,23 +786,6 @@ PYBIND11_MODULE(manifold3d, m) {
|
||||
.def(py::self + py::self, "Boolean union.")
|
||||
.def(py::self - py::self, "Boolean difference.")
|
||||
.def(py::self ^ py::self, "Boolean intersection.")
|
||||
.def(
|
||||
"hull", [](CrossSection &self) { return self.Hull(); },
|
||||
"Compute the convex hull of this cross-section.")
|
||||
.def_static(
|
||||
"batch_hull",
|
||||
[](std::vector<CrossSection> &cs) { return CrossSection::Hull(cs); },
|
||||
"Compute the convex hull enveloping a set of cross-sections.")
|
||||
.def_static(
|
||||
"hull_points",
|
||||
[](std::vector<Float2> &pts) {
|
||||
std::vector<glm::vec2> poly(pts.size());
|
||||
for (int i = 0; i < pts.size(); i++) {
|
||||
poly[i] = {std::get<0>(pts[i]), std::get<1>(pts[i])};
|
||||
}
|
||||
return CrossSection::Hull(poly);
|
||||
},
|
||||
"Compute the convex hull enveloping a set of 2d points.")
|
||||
.def("decompose", &CrossSection::Decompose,
|
||||
"This operation returns a vector of CrossSections that are "
|
||||
"topologically disconnected, each containing one outline contour "
|
||||
|
||||
@@ -125,10 +125,6 @@ EMSCRIPTEN_BINDINGS(whatever) {
|
||||
function("_crossSectionUnionN", &cross_js::UnionN);
|
||||
function("_crossSectionDifferenceN", &cross_js::DifferenceN);
|
||||
function("_crossSectionIntersectionN", &cross_js::IntersectionN);
|
||||
function("_crossSectionCollectVertices", &cross_js::CollectVertices);
|
||||
function("_crossSectionHullPoints",
|
||||
select_overload<CrossSection(std::vector<glm::vec2>)>(
|
||||
&CrossSection::Hull));
|
||||
|
||||
class_<Manifold>("Manifold")
|
||||
.constructor(&man_js::FromMeshJS)
|
||||
@@ -138,7 +134,6 @@ EMSCRIPTEN_BINDINGS(whatever) {
|
||||
.function("_Split", &man_js::Split)
|
||||
.function("_SplitByPlane", &man_js::SplitByPlane)
|
||||
.function("_TrimByPlane", &Manifold::TrimByPlane)
|
||||
.function("hull", select_overload<Manifold() const>(&Manifold::Hull))
|
||||
.function("_GetMeshJS", &js::GetMeshJS)
|
||||
.function("refine", &Manifold::Refine)
|
||||
.function("_Warp", &man_js::Warp)
|
||||
@@ -181,10 +176,6 @@ EMSCRIPTEN_BINDINGS(whatever) {
|
||||
function("_manifoldUnionN", &man_js::UnionN);
|
||||
function("_manifoldDifferenceN", &man_js::DifferenceN);
|
||||
function("_manifoldIntersectionN", &man_js::IntersectionN);
|
||||
function("_manifoldCollectVertices", &man_js::CollectVertices);
|
||||
function("_manifoldHullPoints",
|
||||
select_overload<Manifold(const std::vector<glm::vec3>&)>(
|
||||
&Manifold::Hull));
|
||||
|
||||
// Quality Globals
|
||||
function("setMinCircularAngle", &Quality::SetMinCircularAngle);
|
||||
|
||||
@@ -472,36 +472,6 @@ Module.setup = function() {
|
||||
Module.CrossSection.difference = crossSectionBatchbool('DifferenceN');
|
||||
Module.CrossSection.intersection = crossSectionBatchbool('IntersectionN');
|
||||
|
||||
function pushVec2(vec, ps) {
|
||||
toVec(vec, ps, p => {
|
||||
if (p instanceof Array) return {x: p[0], y: p[1]};
|
||||
return p;
|
||||
})
|
||||
}
|
||||
|
||||
Module.CrossSection.hull = function(...args) {
|
||||
if (args.length == 1) args = args[0];
|
||||
let pts = new Module.Vector_vec2();
|
||||
for (const cs of args) {
|
||||
if (cs instanceof CrossSectionCtor) {
|
||||
Module._crossSectionCollectVertices(pts, cs);
|
||||
} else if (
|
||||
cs instanceof Array && cs.length == 2 && typeof cs[0] == 'number') {
|
||||
pts.push_back({x: cs[0], y: cs[1]});
|
||||
} else if (cs.x) {
|
||||
pts.push_back(cs);
|
||||
} else {
|
||||
const wrap =
|
||||
((cs[0].length == 2 && typeof cs[0][0] == 'number') || cs[0].x);
|
||||
const polys = wrap ? [cs] : cs;
|
||||
for (const poly of polys) pushVec2(pts, poly);
|
||||
}
|
||||
}
|
||||
const result = Module._crossSectionHullPoints(pts);
|
||||
pts.delete();
|
||||
return result;
|
||||
};
|
||||
|
||||
Module.CrossSection.prototype = Object.create(CrossSectionCtor.prototype);
|
||||
|
||||
// Because the constructor and prototype are being replaced, instanceof will
|
||||
@@ -626,33 +596,6 @@ Module.setup = function() {
|
||||
return out;
|
||||
};
|
||||
|
||||
function pushVec3(vec, ps) {
|
||||
toVec(vec, ps, p => {
|
||||
if (p instanceof Array) return {x: p[0], y: p[1], z: p[2]};
|
||||
return p;
|
||||
})
|
||||
}
|
||||
|
||||
Module.Manifold.hull = function(...args) {
|
||||
if (args.length == 1) args = args[0];
|
||||
let pts = new Module.Vector_vec3();
|
||||
for (const m of args) {
|
||||
if (m instanceof ManifoldCtor) {
|
||||
Module._manifoldCollectVertices(pts, m);
|
||||
} else if (
|
||||
m instanceof Array && m.length == 3 && typeof m[0] == 'number') {
|
||||
pts.push_back({x: m[0], y: m[1], z: m[2]});
|
||||
} else if (m.x) {
|
||||
pts.push_back(m);
|
||||
} else {
|
||||
pushVec3(pts, m);
|
||||
}
|
||||
}
|
||||
const result = Module._manifoldHullPoints(pts);
|
||||
pts.delete();
|
||||
return result;
|
||||
};
|
||||
|
||||
Module.Manifold.prototype = Object.create(ManifoldCtor.prototype);
|
||||
|
||||
// Because the constructor and prototype are being replaced, instanceof will
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
declare module '@jscadui/3mf-export';
|
||||
@@ -130,14 +130,18 @@ model-viewer {
|
||||
|
||||
.header .margin {
|
||||
font-size: 16px;
|
||||
margin: 1em 0.5em;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
#file {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
width: 250px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -146,10 +150,6 @@ model-viewer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uparrow {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
@@ -174,7 +174,6 @@ model-viewer {
|
||||
position: absolute;
|
||||
width: 36px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
background-size: 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
@@ -194,6 +193,7 @@ model-viewer {
|
||||
|
||||
.trash {
|
||||
background-image: url(/icons/trash.png);
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.icon:hover {
|
||||
@@ -212,15 +212,6 @@ model-viewer {
|
||||
background-color: rgb(255, 177, 177);
|
||||
}
|
||||
|
||||
#file-margin {
|
||||
position: relative;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#save {
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
@@ -229,31 +220,5 @@ model-viewer {
|
||||
|
||||
.col {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
#file-margin {
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: .2em 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header .margin {
|
||||
margin: 0.2em 16px;
|
||||
}
|
||||
|
||||
#button-container {
|
||||
flex-direction: row;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
#button-container .margin {
|
||||
width: calc(50% - 16px);
|
||||
margin: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,31 +26,20 @@ let editor = undefined;
|
||||
|
||||
// File UI ------------------------------------------------------------
|
||||
const fileButton = document.querySelector('#file');
|
||||
const currentFileElement = document.querySelector('#current');
|
||||
const fileArrow = document.querySelector('#file .uparrow');
|
||||
const fileDropdown = document.querySelector('#fileDropdown');
|
||||
const saveContainer = document.querySelector('#save');
|
||||
const saveDropdown = document.querySelector('#saveDropdown');
|
||||
const saveArrow = document.querySelector('#save .uparrow');
|
||||
const currentElement = document.querySelector('#current');
|
||||
const arrow = document.querySelector('.uparrow');
|
||||
const dropdown = document.querySelector('.dropdown');
|
||||
|
||||
const hideDropdown = function() {
|
||||
fileDropdown.classList.remove('show');
|
||||
saveDropdown.classList.remove('show');
|
||||
fileArrow.classList.remove('down');
|
||||
saveArrow.classList.remove('down');
|
||||
dropdown.classList.remove('show');
|
||||
arrow.classList.remove('down');
|
||||
};
|
||||
const toggleFileDropdown = function(event) {
|
||||
const toggleDropdown = function(event) {
|
||||
event.stopPropagation();
|
||||
fileDropdown.classList.toggle('show');
|
||||
fileArrow.classList.toggle('down');
|
||||
dropdown.classList.toggle('show');
|
||||
arrow.classList.toggle('down');
|
||||
};
|
||||
const toggleSaveDropdown = function(event) {
|
||||
event.stopPropagation();
|
||||
saveDropdown.classList.toggle('show');
|
||||
saveArrow.classList.toggle('down');
|
||||
};
|
||||
fileButton.onclick = toggleFileDropdown;
|
||||
saveArrow.parentElement.onclick = toggleSaveDropdown;
|
||||
fileButton.onclick = toggleDropdown;
|
||||
document.body.onclick = hideDropdown;
|
||||
|
||||
const prefix = 'ManifoldCAD';
|
||||
@@ -73,7 +62,7 @@ function nthKey(n) {
|
||||
|
||||
function saveCurrent() {
|
||||
if (editor) {
|
||||
const currentName = currentFileElement.textContent;
|
||||
const currentName = currentElement.textContent;
|
||||
if (!exampleFunctions.get(currentName)) {
|
||||
setScript(currentName, editor.getValue());
|
||||
}
|
||||
@@ -88,7 +77,7 @@ let isExample = true;
|
||||
function switchTo(scriptName) {
|
||||
if (editor) {
|
||||
switching = true;
|
||||
currentFileElement.textContent = scriptName;
|
||||
currentElement.textContent = scriptName;
|
||||
setScript('currentName', scriptName);
|
||||
const code =
|
||||
exampleFunctions.get(scriptName) ?? getScript(scriptName) ?? '';
|
||||
@@ -159,8 +148,8 @@ function addEdit(button) {
|
||||
if (!input) return;
|
||||
const newName = uniqueName(input);
|
||||
label.textContent = newName;
|
||||
if (currentFileElement.textContent == oldName) {
|
||||
currentFileElement.textContent = newName;
|
||||
if (currentElement.textContent == oldName) {
|
||||
currentElement.textContent = newName;
|
||||
}
|
||||
removeScript(oldName);
|
||||
setScript(newName, code);
|
||||
@@ -193,7 +182,7 @@ function addEdit(button) {
|
||||
}, {once: true});
|
||||
} else if (performance.now() - lastClick > 500) {
|
||||
removeScript(label.textContent);
|
||||
if (currentFileElement.textContent == label.textContent) {
|
||||
if (currentElement.textContent == label.textContent) {
|
||||
switchTo('Intro');
|
||||
}
|
||||
const container = button.parentElement;
|
||||
@@ -280,10 +269,10 @@ require(['vs/editor/editor.main'], async function() {
|
||||
|
||||
for (const [name] of exampleFunctions) {
|
||||
const button = createDropdownItem(name);
|
||||
fileDropdown.appendChild(button.parentElement);
|
||||
dropdown.appendChild(button.parentElement);
|
||||
}
|
||||
|
||||
let currentName = currentFileElement.textContent;
|
||||
let currentName = currentElement.textContent;
|
||||
|
||||
for (let i = 0; i < window.localStorage.length; i++) {
|
||||
const key = nthKey(i);
|
||||
@@ -358,10 +347,7 @@ function finishRun() {
|
||||
}
|
||||
|
||||
const mv = document.querySelector('model-viewer');
|
||||
const output = {
|
||||
glbURL: null,
|
||||
threeMFURL: null
|
||||
};
|
||||
let objectURL = null;
|
||||
let manifoldWorker = null;
|
||||
|
||||
function createWorker() {
|
||||
@@ -384,16 +370,10 @@ function createWorker() {
|
||||
finishRun();
|
||||
runButton.disabled = true;
|
||||
|
||||
if (output.threeMFURL != null) {
|
||||
URL.revokeObjectURL(output.threeMFURL);
|
||||
output.threeMFURL = null;
|
||||
}
|
||||
URL.revokeObjectURL(output.glbURL);
|
||||
output.glbURL = e.data.glbURL;
|
||||
output.threeMFURL = e.data.threeMFURL;
|
||||
threemfButton.disabled = output.threeMFURL == null;
|
||||
mv.src = output.glbURL;
|
||||
if (output.glbURL == null) {
|
||||
URL.revokeObjectURL(objectURL);
|
||||
objectURL = e.data.objectURL;
|
||||
mv.src = objectURL;
|
||||
if (objectURL == null) {
|
||||
mv.showPoster();
|
||||
poster.textContent = 'Error';
|
||||
createWorker();
|
||||
@@ -431,24 +411,10 @@ runButton.onclick = function() {
|
||||
}
|
||||
};
|
||||
|
||||
function clickSave(saveButton, filename, outputName) {
|
||||
const container = saveButton.parentElement;
|
||||
return () => {
|
||||
const oldSave = saveContainer.firstElementChild;
|
||||
if (oldSave !== container) {
|
||||
saveDropdown.insertBefore(oldSave, saveDropdown.firstElementChild);
|
||||
saveContainer.insertBefore(container, saveDropdown);
|
||||
container.appendChild(saveArrow.parentElement);
|
||||
}
|
||||
const link = document.createElement('a');
|
||||
link.download = filename;
|
||||
link.href = output[outputName];
|
||||
link.click();
|
||||
};
|
||||
}
|
||||
|
||||
const glbButton = document.querySelector('#glb');
|
||||
glbButton.onclick = clickSave(glbButton, 'manifold.glb', 'glbURL');
|
||||
|
||||
const threemfButton = document.querySelector('#threemf');
|
||||
threemfButton.onclick = clickSave(threemfButton, 'manifold.3mf', 'threeMFURL');
|
||||
const downloadButton = document.querySelector('#download');
|
||||
downloadButton.onclick = function() {
|
||||
const link = document.createElement('a');
|
||||
link.download = 'manifold.glb';
|
||||
link.href = objectURL;
|
||||
link.click();
|
||||
};
|
||||
|
||||
@@ -40,27 +40,15 @@
|
||||
<div class="page">
|
||||
<div class="container header" style="background-color: #A288B3;">
|
||||
<p style="flex: 2;"><a target="_blank" href="https://github.com/elalish/manifold">Manifold</a>CAD </p>
|
||||
<div class="margin" id="file-margin" >
|
||||
<button type="button" id="file" class="blue item"><b class="uparrow"></b> <span
|
||||
<div class="margin" style="position: relative;">
|
||||
<button type="button" id="file" class="blue"><b class="uparrow"></b> <span
|
||||
id="current">Intro</span></button>
|
||||
<div class="dropdown" id="fileDropdown">
|
||||
<div class="dropdown">
|
||||
<button type="button" class="green item" id="new">New</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container" id="button-container">
|
||||
<button type="button" id="compile" class="margin green" disabled><span>Run</span></button>
|
||||
<div id="save" class="margin" style="position: relative; ">
|
||||
<div class="item">
|
||||
<button type="button" id="glb" class="blue item">Save GLB</button>
|
||||
<button type="button" class="icon"><b class="uparrow" style="right: 2px;"></b></button>
|
||||
</div>
|
||||
<div class="dropdown" id="saveDropdown">
|
||||
<div class="item">
|
||||
<button type="button" id="threemf" class="blue item">Save 3MF</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="compile" class="margin green" disabled><span>Run</span></button>
|
||||
<button type="button" id="download" class="blue margin">Save GLB</button>
|
||||
</div>
|
||||
<div class="container" style="flex: 2;">
|
||||
<div id="editor" class="col"></div>
|
||||
@@ -86,4 +74,4 @@
|
||||
<script type="module" src="editor.js"></script>
|
||||
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.1.1/model-viewer.min.js"></script>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Generated
+4
-16
@@ -11,8 +11,6 @@
|
||||
"@gltf-transform/core": "^3.2.1",
|
||||
"@gltf-transform/extensions": "^3.2.1",
|
||||
"@gltf-transform/functions": "^3.2.1",
|
||||
"@jscadui/3mf-export": "^0.3.0",
|
||||
"fflate": "^0.8.0",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"simple-dropzone": "0.8.3",
|
||||
"three": "0.151.2"
|
||||
@@ -413,11 +411,6 @@
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jscadui/3mf-export": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@jscadui/3mf-export/-/3mf-export-0.3.0.tgz",
|
||||
"integrity": "sha512-5NfknQSTO2+rt7m7PGDvIST8V2RNNWBGvQPEmVY2DTMCEZ6y4zyIltxwVbnQ6NRCEeWZseSb3FpmflU1AWE9vw=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -588,12 +581,6 @@
|
||||
"vitest": ">=0.30.1 <1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/ui/node_modules/fflate": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
|
||||
"integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.31.1.tgz",
|
||||
@@ -1013,9 +1000,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.0.tgz",
|
||||
"integrity": "sha512-FAdS4qMuFjsJj6XHbBaZeXOgaypXp8iw/Tpyuq/w3XA41jjLHT8NPA+n7czH/DDhdncq0nAyDZmPeWXh2qmdIg=="
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
|
||||
"integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
"@gltf-transform/core": "^3.2.1",
|
||||
"@gltf-transform/extensions": "^3.2.1",
|
||||
"@gltf-transform/functions": "^3.2.1",
|
||||
"@jscadui/3mf-export": "^0.3.0",
|
||||
"fflate": "^0.8.0",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"simple-dropzone": "0.8.3",
|
||||
"three": "0.151.2"
|
||||
|
||||
@@ -39,7 +39,7 @@ function initialized(worker) {
|
||||
});
|
||||
}
|
||||
|
||||
let glbURL = null;
|
||||
let objectURL = null;
|
||||
|
||||
async function runExample(name) {
|
||||
const worker = new ManifoldWorker();
|
||||
@@ -55,12 +55,12 @@ async function runExample(name) {
|
||||
|
||||
worker.onmessage = async function(e) {
|
||||
try {
|
||||
URL.revokeObjectURL(glbURL);
|
||||
glbURL = e.data.glbURL;
|
||||
if (glbURL == null) {
|
||||
reject('no glbURL)');
|
||||
URL.revokeObjectURL(objectURL);
|
||||
objectURL = e.data.objectURL;
|
||||
if (objectURL == null) {
|
||||
reject('no objectURL');
|
||||
}
|
||||
const docIn = await io.read(glbURL);
|
||||
const docIn = await io.read(objectURL);
|
||||
const nodes = docIn.getRoot().listNodes();
|
||||
for (const node of nodes) {
|
||||
const mesh = node.getMesh();
|
||||
|
||||
@@ -14,14 +14,11 @@
|
||||
|
||||
import {Document, Material, Node, WebIO} from '@gltf-transform/core';
|
||||
import {KHRMaterialsUnlit, KHRONOS_EXTENSIONS} from '@gltf-transform/extensions';
|
||||
import {fileForContentTypes, to3dmodel} from '@jscadui/3mf-export';
|
||||
import {strToU8, Zippable, zipSync} from 'fflate'
|
||||
import * as glMatrix from 'gl-matrix';
|
||||
|
||||
import Module from './built/manifold';
|
||||
//@ts-ignore
|
||||
import {setupIO, writeMesh} from './gltf-io';
|
||||
|
||||
import type {GLTFMaterial, Quat} from './public/editor';
|
||||
import type {CrossSection, Manifold, ManifoldToplevel, Mesh, Vec3} from './public/manifold';
|
||||
|
||||
@@ -45,23 +42,23 @@ io.registerExtensions(KHRONOS_EXTENSIONS);
|
||||
// manifold static methods (that return a new manifold)
|
||||
const manifoldStaticFunctions = [
|
||||
'cube', 'cylinder', 'sphere', 'tetrahedron', 'extrude', 'revolve', 'compose',
|
||||
'union', 'difference', 'intersection', 'levelSet', 'smooth', 'ofMesh', 'hull'
|
||||
'union', 'difference', 'intersection', 'levelSet', 'smooth', 'ofMesh'
|
||||
];
|
||||
// manifold member functions (that return a new manifold)
|
||||
const manifoldMemberFunctions = [
|
||||
'add', 'subtract', 'intersect', 'decompose', 'warp', 'transform', 'translate',
|
||||
'rotate', 'scale', 'mirror', 'refine', 'setProperties', 'asOriginal',
|
||||
'trimByPlane', 'split', 'splitByPlane', 'hull'
|
||||
'trimByPlane', 'split', 'splitByPlane'
|
||||
];
|
||||
// CrossSection static methods (that return a new cross-section)
|
||||
const crossSectionStaticFunctions = [
|
||||
'square', 'circle', 'union', 'difference', 'intersection', 'compose',
|
||||
'ofPolygons', 'hull'
|
||||
'ofPolygons'
|
||||
];
|
||||
// CrossSection member functions (that return a new cross-section)
|
||||
const crossSectionMemberFunctions = [
|
||||
'add', 'subtract', 'intersect', 'rectClip', 'decompose', 'transform',
|
||||
'translate', 'rotate', 'scale', 'mirror', 'simplify', 'offset', 'hull'
|
||||
'translate', 'rotate', 'scale', 'mirror', 'simplify', 'offset'
|
||||
];
|
||||
// top level functions that construct a new manifold/mesh
|
||||
const toplevelConstructors = ['show', 'only', 'setMaterial'];
|
||||
@@ -460,28 +457,8 @@ async function exportGLB(manifold?: Manifold) {
|
||||
wrapper.addChild(node);
|
||||
}
|
||||
|
||||
const results: {glbURL?: string, threeMFURL?: string} = {};
|
||||
if (manifold != null) {
|
||||
const mesh = manifold.getMesh();
|
||||
let vertices = new Float32Array(mesh.numVert * 3);
|
||||
for (let i = 0; i < mesh.numVert; ++i) {
|
||||
for (let j = 0; j < 3; ++j)
|
||||
vertices[i * 3 + j] = mesh.vertProperties[i * mesh.numProp + j];
|
||||
}
|
||||
const model =
|
||||
to3dmodel({simple: [{vertices, indices: mesh.triVerts, id: '1'}]});
|
||||
const files: Zippable = {};
|
||||
files['3D/3dmodel.model'] = strToU8(model);
|
||||
files[fileForContentTypes.name] = strToU8(fileForContentTypes.content);
|
||||
const zipFile = zipSync(files);
|
||||
results.threeMFURL = URL.createObjectURL(new Blob(
|
||||
[zipFile],
|
||||
{type: 'application/vnd.ms-package.3dmanufacturing-3dmodel+xml'}));
|
||||
}
|
||||
|
||||
const glb = await io.writeBinary(doc);
|
||||
|
||||
const blob = new Blob([glb], {type: 'application/octet-stream'});
|
||||
results.glbURL = URL.createObjectURL(blob);
|
||||
self.postMessage(results);
|
||||
self.postMessage({objectURL: URL.createObjectURL(blob)});
|
||||
}
|
||||
|
||||
@@ -159,11 +159,6 @@ CrossSection Offset(CrossSection& cross_section, double delta, int join_type,
|
||||
: CrossSection::JoinType::Miter;
|
||||
return cross_section.Offset(delta, jt, miter_limit, arc_tolerance);
|
||||
}
|
||||
|
||||
void CollectVertices(std::vector<glm::vec2>& verts, const CrossSection& cs) {
|
||||
auto polys = cs.ToPolygons();
|
||||
for (auto poly : polys) verts.insert(verts.end(), poly.begin(), poly.end());
|
||||
}
|
||||
} // namespace cross_js
|
||||
|
||||
namespace man_js {
|
||||
@@ -224,9 +219,4 @@ std::vector<Manifold> SplitByPlane(Manifold& m, glm::vec3 normal,
|
||||
auto [a, b] = m.SplitByPlane(normal, originOffset);
|
||||
return {a, b};
|
||||
}
|
||||
|
||||
void CollectVertices(std::vector<glm::vec3>& verts, const Manifold& manifold) {
|
||||
Mesh mesh = manifold.GetMesh();
|
||||
verts.insert(verts.end(), mesh.vertPos.begin(), mesh.vertPos.end());
|
||||
}
|
||||
} // namespace man_js
|
||||
|
||||
+5
-28
@@ -111,7 +111,6 @@ export class CrossSection {
|
||||
* @param v The vector to add to every vertex.
|
||||
*/
|
||||
translate(v: Vec2): CrossSection;
|
||||
translate(x: number, y?: number): CrossSection;
|
||||
|
||||
/**
|
||||
* Applies a (Z-axis) rotation to the CrossSection, in degrees. This operation
|
||||
@@ -174,6 +173,11 @@ export class CrossSection {
|
||||
delta: number, joinType?: JoinType, miterLimit?: number,
|
||||
circularSegments?: number): CrossSection;
|
||||
|
||||
/**
|
||||
* Compute the convex hull of the contours in this CrossSection.
|
||||
*/
|
||||
hull(): CrossSection;
|
||||
|
||||
/**
|
||||
* Remove vertices from the contours in this CrossSection that are less than
|
||||
* the specified distance epsilon from an imaginary line that passes through
|
||||
@@ -242,18 +246,6 @@ export class CrossSection {
|
||||
*/
|
||||
static intersection(polygons: (CrossSection|Polygons)[]): CrossSection;
|
||||
|
||||
// Convex Hulls
|
||||
|
||||
/**
|
||||
* Compute the convex hull of the contours in this CrossSection.
|
||||
*/
|
||||
hull(): CrossSection;
|
||||
|
||||
/**
|
||||
* Compute the convex hull of all points in a list of polygons/cross-sections.
|
||||
*/
|
||||
static hull(polygons: (CrossSection|Polygons)[]): CrossSection;
|
||||
|
||||
// Topological Operations
|
||||
|
||||
/**
|
||||
@@ -515,7 +507,6 @@ export class Manifold {
|
||||
* @param v The vector to add to every vertex.
|
||||
*/
|
||||
translate(v: Vec3): Manifold;
|
||||
translate(x: number, y?: number, z?: number): Manifold;
|
||||
|
||||
/**
|
||||
* Applies an Euler angle rotation to the manifold, first about the X axis,
|
||||
@@ -528,7 +519,6 @@ export class Manifold {
|
||||
* @param v [X, Y, Z] rotation in degrees.
|
||||
*/
|
||||
rotate(v: Vec3): Manifold;
|
||||
rotate(x: number, y?: number, z?: number): Manifold;
|
||||
|
||||
/**
|
||||
* Scale this Manifold in space. This operation can be chained. Transforms are
|
||||
@@ -685,19 +675,6 @@ export class Manifold {
|
||||
*/
|
||||
trimByPlane(normal: Vec3, originOffset: number): Manifold;
|
||||
|
||||
// Convex Hulls
|
||||
|
||||
/**
|
||||
* Compute the convex hull of all points in this Manifold.
|
||||
*/
|
||||
hull(): Manifold;
|
||||
|
||||
/**
|
||||
* Compute the convex hull of all points contained within a set of Manifolds
|
||||
* and point vectors.
|
||||
*/
|
||||
static hull(points: (Manifold|Vec3)[]): Manifold;
|
||||
|
||||
// Topological Operations
|
||||
|
||||
/**
|
||||
|
||||
@@ -287,8 +287,7 @@ SparseIndices Collider::Collisions(const VecDH<T>& queriesIn) const {
|
||||
{thrust::pair<int*, int*>(nullptr, nullptr), counts.ptrD(),
|
||||
nodeBBox_.ptrD(), internalChildren_.ptrD()}));
|
||||
// compute start index for each query and total count
|
||||
exclusive_scan(policy, counts.begin(), counts.end(), counts.begin(), 0,
|
||||
std::plus<int>());
|
||||
exclusive_scan(policy, counts.begin(), counts.end(), counts.begin());
|
||||
SparseIndices queryTri(counts.back());
|
||||
// actually recording collisions
|
||||
for_each_n(policy, zip(queriesIn.cbegin(), countAt(0)), queriesIn.size(),
|
||||
|
||||
@@ -612,12 +612,6 @@ CrossSection CrossSection::Offset(double delta, JoinType jointype,
|
||||
return CrossSection(ps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the convex hull enveloping a set of cross-sections.
|
||||
*
|
||||
* @param crossSections A vector of cross-sections over which to compute a
|
||||
* convex hull.
|
||||
*/
|
||||
CrossSection CrossSection::Hull(
|
||||
const std::vector<CrossSection>& crossSections) {
|
||||
int n = 0;
|
||||
@@ -635,31 +629,14 @@ CrossSection CrossSection::Hull(
|
||||
return CrossSection(C2::PathsD{HullImpl(pts)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the convex hull of this cross-section.
|
||||
*/
|
||||
CrossSection CrossSection::Hull() const {
|
||||
return Hull(std::vector<CrossSection>{*this});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the convex hull of a set of points. If the given points are fewer
|
||||
* than 3, an empty CrossSection will be returned.
|
||||
*
|
||||
* @param pts A vector of 2-dimensional points over which to compute a convex
|
||||
* hull.
|
||||
*/
|
||||
CrossSection CrossSection::Hull(SimplePolygon pts) {
|
||||
return CrossSection(C2::PathsD{HullImpl(pts)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the convex hull of a set of points/polygons. If the given points are
|
||||
* fewer than 3, an empty CrossSection will be returned.
|
||||
*
|
||||
* @param pts A vector of vectors of 2-dimensional points over which to compute
|
||||
* a convex hull.
|
||||
*/
|
||||
CrossSection CrossSection::Hull(const Polygons polys) {
|
||||
SimplePolygon pts;
|
||||
for (auto poly : polys) {
|
||||
|
||||
@@ -222,12 +222,9 @@ void Manifold::Impl::SimplifyTopology() {
|
||||
precision_};
|
||||
for_each_n(policy, countAt(0), nbEdges,
|
||||
[=] __host__ __device__(int i) { bflagsPtr[i] = se(i); });
|
||||
std::vector<int> visited(halfedge_.size(), -1);
|
||||
int tag = 0;
|
||||
for (int i = 0; i < nbEdges; ++i) {
|
||||
if (bflags[i]) {
|
||||
tag++;
|
||||
RecursiveEdgeSwap(i, visited, tag);
|
||||
RecursiveEdgeSwap(i);
|
||||
numFlagged++;
|
||||
}
|
||||
}
|
||||
@@ -486,17 +483,13 @@ void Manifold::Impl::CollapseEdge(const int edge) {
|
||||
RemoveIfFolded(start);
|
||||
}
|
||||
|
||||
void Manifold::Impl::RecursiveEdgeSwap(const int edge,
|
||||
std::vector<int>& visited, int& tag) {
|
||||
void Manifold::Impl::RecursiveEdgeSwap(const int edge) {
|
||||
VecDH<TriRef>& triRef = meshRelation_.triRef;
|
||||
|
||||
if (edge < 0) return;
|
||||
const int pair = halfedge_[edge].pairedHalfedge;
|
||||
if (pair < 0) return;
|
||||
|
||||
// avoid infinite recursion
|
||||
if (visited[edge] == tag && visited[pair] == tag) return;
|
||||
|
||||
const glm::ivec3 tri0edge = TriOf(edge);
|
||||
const glm::ivec3 tri1edge = TriOf(pair);
|
||||
const glm::ivec3 perm0 = TriOf(edge % 3);
|
||||
@@ -575,15 +568,12 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge,
|
||||
SwapEdge();
|
||||
const glm::vec2 e23 = v[3] - v[2];
|
||||
if (glm::dot(e23, e23) < precision_ * precision_) {
|
||||
tag++;
|
||||
CollapseEdge(tri0edge[2]);
|
||||
} else {
|
||||
visited[edge] = tag;
|
||||
visited[pair] = tag;
|
||||
RecursiveEdgeSwap(tri0edge[0], visited, tag);
|
||||
RecursiveEdgeSwap(tri0edge[1], visited, tag);
|
||||
RecursiveEdgeSwap(tri1edge[0], visited, tag);
|
||||
RecursiveEdgeSwap(tri1edge[1], visited, tag);
|
||||
RecursiveEdgeSwap(tri0edge[0]);
|
||||
RecursiveEdgeSwap(tri0edge[1]);
|
||||
RecursiveEdgeSwap(tri1edge[0]);
|
||||
RecursiveEdgeSwap(tri1edge[1]);
|
||||
}
|
||||
return;
|
||||
} else if (CCW(v[0], v[3], v[2], precision_) <= 0 ||
|
||||
@@ -592,10 +582,8 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge,
|
||||
}
|
||||
// Normal path
|
||||
SwapEdge();
|
||||
visited[edge] = tag;
|
||||
visited[pair] = tag;
|
||||
RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge, visited, tag);
|
||||
RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge, visited, tag);
|
||||
RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge);
|
||||
RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge);
|
||||
}
|
||||
|
||||
void Manifold::Impl::SplitPinchedVerts() {
|
||||
|
||||
@@ -121,7 +121,7 @@ struct Manifold::Impl {
|
||||
void SimplifyTopology();
|
||||
void DedupeEdge(int edge);
|
||||
void CollapseEdge(int edge);
|
||||
void RecursiveEdgeSwap(int edge, std::vector<int>& visited, int& tag);
|
||||
void RecursiveEdgeSwap(int edge);
|
||||
void RemoveIfFolded(int edge);
|
||||
void PairUp(int edge0, int edge1);
|
||||
void UpdateVert(int vert, int startEdge, int endEdge);
|
||||
|
||||
+18
-42
@@ -15,14 +15,8 @@
|
||||
#include "polygon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#if MANIFOLD_PAR == 'T'
|
||||
#include <execution>
|
||||
#endif
|
||||
#include <list>
|
||||
#include <map>
|
||||
#if __has_include(<memory_resource>)
|
||||
#include <memory_resource>
|
||||
#endif
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
@@ -309,25 +303,14 @@ class Monotones {
|
||||
|
||||
private:
|
||||
struct VertAdj;
|
||||
struct EdgePair;
|
||||
enum VertType { Start, WestSide, EastSide, Merge, End, Skip };
|
||||
#if __has_include(<memory_resource>)
|
||||
typedef std::pmr::list<VertAdj>::iterator VertItr;
|
||||
typedef std::pmr::list<EdgePair>::iterator PairItr;
|
||||
|
||||
std::pmr::monotonic_buffer_resource mbr;
|
||||
std::pmr::polymorphic_allocator<int> pa{&mbr};
|
||||
std::pmr::list<VertAdj> monotones_{pa}; // sweep-line list of verts
|
||||
std::pmr::list<EdgePair> activePairs_{pa}; // west to east monotone edges
|
||||
std::pmr::list<EdgePair> inactivePairs_{pa}; // completed monotones
|
||||
#else
|
||||
typedef std::list<VertAdj>::iterator VertItr;
|
||||
struct EdgePair;
|
||||
typedef std::list<EdgePair>::iterator PairItr;
|
||||
enum VertType { Start, WestSide, EastSide, Merge, End, Skip };
|
||||
|
||||
std::list<VertAdj> monotones_; // sweep-line list of verts
|
||||
std::list<EdgePair> activePairs_; // west to east monotone edges
|
||||
std::list<VertAdj> monotones_; // sweep-line list of verts
|
||||
std::list<EdgePair> activePairs_; // west to east list of monotone edge pairs
|
||||
std::list<EdgePair> inactivePairs_; // completed monotones
|
||||
#endif
|
||||
float precision_; // a triangle of this height or less is degenerate
|
||||
|
||||
/**
|
||||
@@ -409,7 +392,7 @@ class Monotones {
|
||||
class Triangulator {
|
||||
public:
|
||||
Triangulator(VertItr vert, float precision) : precision_(precision) {
|
||||
reflex_chain_.push_back(vert);
|
||||
reflex_chain_.push(vert);
|
||||
other_side_ = vert;
|
||||
}
|
||||
int NumTriangles() const { return triangles_output_; }
|
||||
@@ -424,14 +407,14 @@ class Monotones {
|
||||
*/
|
||||
void ProcessVert(const VertItr vi, bool onRight, bool last,
|
||||
std::vector<glm::ivec3> &triangles) {
|
||||
VertItr v_top = reflex_chain_.back();
|
||||
VertItr v_top = reflex_chain_.top();
|
||||
if (reflex_chain_.size() < 2) {
|
||||
reflex_chain_.push_back(vi);
|
||||
reflex_chain_.push(vi);
|
||||
onRight_ = onRight;
|
||||
return;
|
||||
}
|
||||
reflex_chain_.pop_back();
|
||||
VertItr vj = reflex_chain_.back();
|
||||
reflex_chain_.pop();
|
||||
VertItr vj = reflex_chain_.top();
|
||||
if (onRight_ == onRight && !last) {
|
||||
// This only creates enough triangles to ensure the reflex chain is
|
||||
// still reflex.
|
||||
@@ -440,13 +423,13 @@ class Monotones {
|
||||
while (ccw == (onRight_ ? 1 : -1) || ccw == 0) {
|
||||
AddTriangle(triangles, vi, vj, v_top);
|
||||
v_top = vj;
|
||||
reflex_chain_.pop_back();
|
||||
reflex_chain_.pop();
|
||||
if (reflex_chain_.empty()) break;
|
||||
vj = reflex_chain_.back();
|
||||
vj = reflex_chain_.top();
|
||||
ccw = CCW(vi->pos, vj->pos, v_top->pos, precision_);
|
||||
}
|
||||
reflex_chain_.push_back(v_top);
|
||||
reflex_chain_.push_back(vi);
|
||||
reflex_chain_.push(v_top);
|
||||
reflex_chain_.push(vi);
|
||||
} else {
|
||||
// This branch empties the reflex chain and switches sides. It must be
|
||||
// used for the last point, as it will output all the triangles
|
||||
@@ -455,19 +438,19 @@ class Monotones {
|
||||
onRight_ = !onRight_;
|
||||
VertItr v_last = v_top;
|
||||
while (!reflex_chain_.empty()) {
|
||||
vj = reflex_chain_.back();
|
||||
vj = reflex_chain_.top();
|
||||
AddTriangle(triangles, vi, v_last, vj);
|
||||
v_last = vj;
|
||||
reflex_chain_.pop_back();
|
||||
reflex_chain_.pop();
|
||||
}
|
||||
reflex_chain_.push_back(v_top);
|
||||
reflex_chain_.push_back(vi);
|
||||
reflex_chain_.push(v_top);
|
||||
reflex_chain_.push(vi);
|
||||
other_side_ = v_top;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<VertItr> reflex_chain_;
|
||||
std::stack<VertItr> reflex_chain_;
|
||||
VertItr other_side_; // The end vertex across from the reflex chain
|
||||
bool onRight_; // The side the reflex chain is on
|
||||
int triangles_output_ = 0;
|
||||
@@ -801,11 +784,7 @@ class Monotones {
|
||||
starts.push_back(v);
|
||||
}
|
||||
}
|
||||
#if MANIFOLD_PAR == 'T' && !(__APPLE__)
|
||||
std::sort(std::execution::par_unseq, starts.begin(), starts.end(), cmp);
|
||||
#else
|
||||
std::sort(starts.begin(), starts.end(), cmp);
|
||||
#endif
|
||||
|
||||
std::vector<VertItr> skipped;
|
||||
VertItr insertAt = monotones_.begin();
|
||||
@@ -1074,9 +1053,6 @@ std::vector<glm::ivec3> TriangulateIdx(const PolygonsIdx &polys,
|
||||
Monotones monotones(polys, precision);
|
||||
monotones.Triangulate(triangles);
|
||||
#ifdef MANIFOLD_DEBUG
|
||||
std::cout << "in triangulator: "
|
||||
<< (PolygonParams().intermediateChecks ? "true" : "false")
|
||||
<< std::endl;
|
||||
if (params.intermediateChecks) {
|
||||
CheckTopology(triangles, polys);
|
||||
if (!params.processOverlaps) {
|
||||
|
||||
+18
-83
@@ -30,9 +30,6 @@
|
||||
#define MANIFOLD_PAR_NS omp
|
||||
#elif MANIFOLD_PAR == 'T'
|
||||
#include <thrust/system/tbb/execution_policy.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <execution>
|
||||
#define MANIFOLD_PAR_NS tbb
|
||||
#else
|
||||
#define MANIFOLD_PAR_NS cpp
|
||||
@@ -139,70 +136,6 @@ inline ExecutionPolicy autoPolicy(int size) {
|
||||
thrust::NAME(thrust::cpp::par, args...); \
|
||||
}
|
||||
|
||||
#if MANIFOLD_PAR == 'T' && !(__APPLE__)
|
||||
// sometimes stl variant is faster
|
||||
#define STL_DYNAMIC_BACKEND(NAME, RET) \
|
||||
template <typename Ret = RET, typename... Args> \
|
||||
Ret NAME(ExecutionPolicy policy, Args... args) { \
|
||||
switch (policy) { \
|
||||
case ExecutionPolicy::ParUnseq: \
|
||||
case ExecutionPolicy::Par: \
|
||||
return std::NAME(std::execution::par_unseq, args...); \
|
||||
case ExecutionPolicy::Seq: \
|
||||
break; \
|
||||
} \
|
||||
return std::NAME(args...); \
|
||||
}
|
||||
#define STL_DYNAMIC_BACKEND_VOID(NAME) \
|
||||
template <typename... Args> \
|
||||
void NAME(ExecutionPolicy policy, Args... args) { \
|
||||
switch (policy) { \
|
||||
case ExecutionPolicy::ParUnseq: \
|
||||
case ExecutionPolicy::Par: \
|
||||
std::NAME(std::execution::par_unseq, args...); \
|
||||
break; \
|
||||
case ExecutionPolicy::Seq: \
|
||||
std::NAME(args...); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void exclusive_scan(ExecutionPolicy policy, Args... args) {
|
||||
// https://github.com/llvm/llvm-project/issues/59810
|
||||
std::exclusive_scan(args...);
|
||||
}
|
||||
template <typename DerivedPolicy, typename InputIterator1,
|
||||
typename InputIterator2, typename OutputIterator, typename Predicate>
|
||||
OutputIterator copy_if(ExecutionPolicy policy, InputIterator1 first,
|
||||
InputIterator1 last, InputIterator2 stencil,
|
||||
OutputIterator result, Predicate pred) {
|
||||
if (policy == ExecutionPolicy::Seq)
|
||||
return thrust::copy_if(thrust::cpp::par, first, last, stencil, result,
|
||||
pred);
|
||||
else
|
||||
// note: this is not a typo, see
|
||||
// https://github.com/NVIDIA/thrust/issues/1977
|
||||
return thrust::copy_if(first, last, stencil, result, pred);
|
||||
}
|
||||
template <typename DerivedPolicy, typename InputIterator1,
|
||||
typename OutputIterator, typename Predicate>
|
||||
OutputIterator copy_if(ExecutionPolicy policy, InputIterator1 first,
|
||||
InputIterator1 last, OutputIterator result,
|
||||
Predicate pred) {
|
||||
if (policy == ExecutionPolicy::Seq)
|
||||
return std::copy_if(first, last, result, pred);
|
||||
else
|
||||
return std::copy_if(std::execution::par_unseq, first, last, result, pred);
|
||||
}
|
||||
#else
|
||||
#define STL_DYNAMIC_BACKEND(NAME, RET) THRUST_DYNAMIC_BACKEND(NAME, RET)
|
||||
#define STL_DYNAMIC_BACKEND_VOID(NAME) THRUST_DYNAMIC_BACKEND_VOID(NAME)
|
||||
|
||||
THRUST_DYNAMIC_BACKEND_VOID(exclusive_scan)
|
||||
THRUST_DYNAMIC_BACKEND(copy_if, void)
|
||||
#endif
|
||||
|
||||
THRUST_DYNAMIC_BACKEND_HOST_VOID(for_each)
|
||||
THRUST_DYNAMIC_BACKEND_HOST_VOID(for_each_n)
|
||||
|
||||
@@ -210,34 +143,36 @@ THRUST_DYNAMIC_BACKEND_VOID(gather)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(scatter)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(for_each)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(for_each_n)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(sort)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(stable_sort)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(fill)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(sequence)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(sort_by_key)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(stable_sort_by_key)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(copy)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(transform)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(inclusive_scan)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(exclusive_scan)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(uninitialized_fill)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(uninitialized_copy)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(stable_sort)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(fill)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(copy)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(inclusive_scan)
|
||||
THRUST_DYNAMIC_BACKEND_VOID(copy_n)
|
||||
STL_DYNAMIC_BACKEND_VOID(sort)
|
||||
|
||||
// void implies that the user have to specify the return type in the template
|
||||
// argument, as we are unable to deduce it
|
||||
THRUST_DYNAMIC_BACKEND(transform_reduce, void)
|
||||
THRUST_DYNAMIC_BACKEND(gather_if, void)
|
||||
THRUST_DYNAMIC_BACKEND(reduce_by_key, void)
|
||||
THRUST_DYNAMIC_BACKEND(lower_bound, void)
|
||||
THRUST_DYNAMIC_BACKEND(remove, void)
|
||||
THRUST_DYNAMIC_BACKEND(find, void)
|
||||
THRUST_DYNAMIC_BACKEND(find_if, void)
|
||||
THRUST_DYNAMIC_BACKEND(all_of, bool)
|
||||
THRUST_DYNAMIC_BACKEND(is_sorted, bool)
|
||||
THRUST_DYNAMIC_BACKEND(reduce, void)
|
||||
THRUST_DYNAMIC_BACKEND(count_if, int)
|
||||
THRUST_DYNAMIC_BACKEND(binary_search, bool)
|
||||
STL_DYNAMIC_BACKEND(remove_if, void)
|
||||
STL_DYNAMIC_BACKEND(unique, void)
|
||||
// void implies that the user have to specify the return type in the template
|
||||
// argument, as we are unable to deduce it
|
||||
THRUST_DYNAMIC_BACKEND(remove, void)
|
||||
THRUST_DYNAMIC_BACKEND(copy_if, void)
|
||||
THRUST_DYNAMIC_BACKEND(remove_if, void)
|
||||
THRUST_DYNAMIC_BACKEND(unique, void)
|
||||
THRUST_DYNAMIC_BACKEND(find, void)
|
||||
THRUST_DYNAMIC_BACKEND(find_if, void)
|
||||
THRUST_DYNAMIC_BACKEND(reduce_by_key, void)
|
||||
THRUST_DYNAMIC_BACKEND(transform_reduce, void)
|
||||
THRUST_DYNAMIC_BACKEND(lower_bound, void)
|
||||
THRUST_DYNAMIC_BACKEND(gather_if, void)
|
||||
|
||||
} // namespace manifold
|
||||
|
||||
@@ -106,7 +106,7 @@ inline HOST_DEVICE int CCW(glm::vec2 p0, glm::vec2 p1, glm::vec2 p2,
|
||||
glm::vec2 v2 = p2 - p0;
|
||||
float area = v1.x * v2.y - v1.y * v2.x;
|
||||
float base2 = glm::max(glm::dot(v1, v1), glm::dot(v2, v2));
|
||||
if (area * area * 4 <= base2 * tol * tol)
|
||||
if (area * area <= base2 * tol * tol)
|
||||
return 0;
|
||||
else
|
||||
return area > 0 ? 1 : -1;
|
||||
|
||||
@@ -26,8 +26,6 @@ using namespace manifold;
|
||||
* The very simplest Boolean operation test.
|
||||
*/
|
||||
TEST(Boolean, Tetra) {
|
||||
std::cout << (PolygonParams().intermediateChecks ? "true" : "false")
|
||||
<< std::endl;
|
||||
Manifold tetra = Manifold::Tetrahedron();
|
||||
MeshGL tetraGL = WithPositionColors(tetra);
|
||||
tetra = Manifold(tetraGL);
|
||||
@@ -39,8 +37,6 @@ TEST(Boolean, Tetra) {
|
||||
ExpectMeshes(result, {{8, 12, 3, 11}});
|
||||
|
||||
RelatedGL(result, {tetraGL});
|
||||
std::cout << (PolygonParams().intermediateChecks ? "true" : "false")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
TEST(Boolean, MeshGLRoundTrip) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -301,23 +301,6 @@ TEST(Polygon, ColinearY) {
|
||||
TestPoly(polys, 16);
|
||||
}
|
||||
|
||||
TEST(Polygon, NearlyColinearY) {
|
||||
Polygons polys;
|
||||
polys.push_back({
|
||||
{3.5, 0}, //
|
||||
{3.0, 0.5}, //
|
||||
{3.0, 0.0144}, //
|
||||
{2.0, 0.4}, //
|
||||
{1.8, 0.1}, //
|
||||
{1.6, 0.0155}, //
|
||||
{1.5, 0.0147}, //
|
||||
{1.4, 0.0144}, //
|
||||
{1.0, 0.1}, //
|
||||
{0, 0}, //
|
||||
});
|
||||
TestPoly(polys, 8, 0.001);
|
||||
}
|
||||
|
||||
TEST(Polygon, Concave) {
|
||||
Polygons polys;
|
||||
polys.push_back({
|
||||
|
||||
@@ -255,16 +255,3 @@ TEST(Samples, Sponge4) {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MANIFOLD_EXPORT
|
||||
TEST(Samples, SelfIntersect) {
|
||||
manifold::PolygonParams().processOverlaps = true;
|
||||
std::string file = __FILE__;
|
||||
std::string dir = file.substr(0, file.rfind('/'));
|
||||
Manifold m1 = ImportMesh(dir + "/models/self_intersectA.glb");
|
||||
Manifold m2 = ImportMesh(dir + "/models/self_intersectB.glb");
|
||||
Manifold res = m1 + m2;
|
||||
res.GetMeshGL(); // test crash
|
||||
manifold::PolygonParams().processOverlaps = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,7 +65,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
manifold::PolygonParams().intermediateChecks = true;
|
||||
|
||||
manifold::PolygonParams().processOverlaps = false;
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
Reference in New Issue
Block a user