Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make create faces optional #935

Merged
merged 7 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/c/include/manifold/manifoldc.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ ManifoldManifold *manifold_revolve(void *mem, ManifoldPolygons *cs,
int circular_segments);
ManifoldManifold *manifold_compose(void *mem, ManifoldManifoldVec *ms);
ManifoldManifoldVec *manifold_decompose(void *mem, ManifoldManifold *m);

ManifoldManifold *manifold_as_original(void *mem, ManifoldManifold *m);

// Manifold Info
Expand Down
9 changes: 5 additions & 4 deletions bindings/python/manifold3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,8 @@ NB_MODULE(manifold3d, m) {

nb::class_<Manifold>(m, "Manifold")
.def(nb::init<>(), manifold__manifold)
.def(nb::init<const MeshGL &, const std::vector<float> &>(),
nb::arg("mesh"), nb::arg("property_tolerance") = nb::list(),
manifold__manifold__mesh_gl__property_tolerance)
.def(nb::init<const MeshGL &>(), nb::arg("mesh"),
manifold__manifold__mesh_gl)
.def(nb::self + nb::self, manifold__operator_plus__q)
.def(nb::self - nb::self, manifold__operator_minus__q)
.def(nb::self ^ nb::self, manifold__operator_xor__q)
Expand Down Expand Up @@ -348,7 +347,9 @@ NB_MODULE(manifold3d, m) {
"Get the surface area of the manifold\n This is clamped to zero for "
"a given face if they are within the Precision().")
.def("original_id", &Manifold::OriginalID, manifold__original_id)
.def("as_original", &Manifold::AsOriginal, manifold__as_original)
.def("as_original", &Manifold::AsOriginal,
nb::arg("property_tolerance") = nb::list(),
manifold__as_original__property_tolerance)
.def("is_empty", &Manifold::IsEmpty, manifold__is_empty)
.def("decompose", &Manifold::Decompose, manifold__decompose)
.def("split", &Manifold::Split, nb::arg("cutter"),
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ EMSCRIPTEN_BINDINGS(whatever) {
.function("calculateCurvature", &Manifold::CalculateCurvature)
.function("_CalculateNormals", &Manifold::CalculateNormals)
.function("originalID", &Manifold::OriginalID)
.function("asOriginal", &Manifold::AsOriginal);
.function("_AsOriginal", &Manifold::AsOriginal);

// Manifold Static Methods
function("_Cube", &Manifold::Cube);
Expand Down
8 changes: 8 additions & 0 deletions bindings/wasm/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ Module.setup = function() {
return this._CalculateNormals(normalIdx, minSharpAngle);
};

Module.Manifold.prototype.asOriginal = function(propertyTolerance = []) {
const tol = new Module.Vector_f64();
toVec(tol, propertyTolerance);
const result = this._AsOriginal(tol);
tol.delete();
return result
};

Module.Manifold.prototype.setProperties = function(numProp, func) {
const oldNumProp = this.numProp();
const wasmFuncPtr = addFunction(function(newPtr, vec3Ptr, oldPtr) {
Expand Down
6 changes: 3 additions & 3 deletions src/manifold/include/manifold/manifold.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ class Manifold {
Manifold(Manifold&&) noexcept;
Manifold& operator=(Manifold&&) noexcept;

Manifold(const MeshGL&, const std::vector<float>& propertyTolerance = {});
Manifold(const MeshGL&);
Manifold(const Mesh&);
Manifold(const MeshGL64&, const std::vector<double>& propertyTolerance = {});
Manifold(const MeshGL64&);

static Manifold Smooth(const MeshGL&,
const std::vector<Smoothness>& sharpenedEdges = {});
Expand Down Expand Up @@ -249,7 +249,7 @@ class Manifold {
*/
///@{
int OriginalID() const;
Manifold AsOriginal() const;
Manifold AsOriginal(const std::vector<double>& propertyTolerance = {}) const;
static uint32_t ReserveIDs(uint32_t);
///@}

Expand Down
12 changes: 2 additions & 10 deletions src/manifold/src/constructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ Manifold Manifold::Smooth(const MeshGL& meshGL,
"when supplying tangents, the normal constructor should be used "
"rather than Smooth().");

// Don't allow any triangle merging.
std::vector<float> propertyTolerance(meshGL.numProp - 3, -1);
std::shared_ptr<Impl> impl =
std::make_shared<Impl>(meshGL, propertyTolerance);
std::shared_ptr<Impl> impl = std::make_shared<Impl>(meshGL);
impl->CreateTangents(impl->UpdateSharpenedEdges(sharpenedEdges));
return Manifold(impl);
}
Expand Down Expand Up @@ -94,10 +91,7 @@ Manifold Manifold::Smooth(const MeshGL64& meshGL64,
"when supplying tangents, the normal constructor should be used "
"rather than Smooth().");

// Don't allow any triangle merging.
std::vector<double> propertyTolerance(meshGL64.numProp - 3, -1);
std::shared_ptr<Impl> impl =
std::make_shared<Impl>(meshGL64, propertyTolerance);
std::shared_ptr<Impl> impl = std::make_shared<Impl>(meshGL64);
impl->CreateTangents(impl->UpdateSharpenedEdges(sharpenedEdges));
return Manifold(impl);
}
Expand Down Expand Up @@ -278,7 +272,6 @@ Manifold Manifold::Extrude(const Polygons& crossSection, double height,

pImpl_->CreateHalfedges(triVertsDH);
pImpl_->Finish();
pImpl_->meshRelation_.originalID = ReserveIDs(1);
pImpl_->InitializeOriginal();
pImpl_->CreateFaces();
return Manifold(pImpl_);
Expand Down Expand Up @@ -423,7 +416,6 @@ Manifold Manifold::Revolve(const Polygons& crossSection, int circularSegments,

pImpl_->CreateHalfedges(triVertsDH);
pImpl_->Finish();
pImpl_->meshRelation_.originalID = ReserveIDs(1);
pImpl_->InitializeOriginal();
pImpl_->CreateFaces();
return Manifold(pImpl_);
Expand Down
17 changes: 7 additions & 10 deletions src/manifold/src/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,6 @@ Manifold::Impl::Impl(const Mesh& mesh, const MeshRelationD& relation,
CalculateNormals();

InitializeOriginal();
if (!hasFaceIDs) {
CreateFaces(propertyTolerance);
}

SimplifyTopology();
Finish();
Expand Down Expand Up @@ -350,7 +347,6 @@ Manifold::Impl::Impl(Shape shape, const mat4x3 m) {
for (auto& v : vertPos_) v = m * vec4(v, 1.0);
CreateHalfedges(triVerts);
Finish();
meshRelation_.originalID = ReserveIDs(1);
InitializeOriginal();
CreateFaces();
}
Expand Down Expand Up @@ -392,9 +388,8 @@ void Manifold::Impl::RemoveUnreferencedVerts() {
}

void Manifold::Impl::InitializeOriginal() {
const int meshID = meshRelation_.originalID;
// Don't initialize if it's not an original
if (meshID < 0) return;
const int meshID = ReserveIDs(1);
meshRelation_.originalID = meshID;
auto& triRef = meshRelation_.triRef;
triRef.resize(NumTri());
for_each_n(autoPolicy(NumTri(), 1e5), countAt(0), NumTri(),
Expand All @@ -407,9 +402,11 @@ void Manifold::Impl::InitializeOriginal() {

void Manifold::Impl::CreateFaces(const std::vector<double>& propertyTolerance) {
ZoneScoped;
constexpr double kDefaultPropTolerance = 1e-5;
Vec<double> propertyToleranceD =
propertyTolerance.empty() ? Vec<double>(meshRelation_.numProp, kTolerance)
: propertyTolerance;
propertyTolerance.empty()
? Vec<double>(meshRelation_.numProp, kDefaultPropTolerance)
: propertyTolerance;

Vec<std::pair<int, int>> face2face(halfedge_.size(), {-1, -1});
Vec<std::pair<int, int>> vert2vert(halfedge_.size(), {-1, -1});
Expand Down Expand Up @@ -569,7 +566,7 @@ void Manifold::Impl::WarpBatch(std::function<void(VecView<vec3>)> warpFunc) {
faceNormal_.resize(0); // force recalculation of triNormal
CalculateNormals();
SetPrecision();
CreateFaces();
InitializeOriginal();
Finish();
}

Expand Down
19 changes: 4 additions & 15 deletions src/manifold/src/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ struct Manifold::Impl {
Impl(Shape, const mat4x3 = mat4x3(1));

template <typename Precision>
Impl(const MeshGLP<Precision>& meshGL,
std::vector<Precision> propertyTolerance) {
Impl(const MeshGLP<Precision>& meshGL) {
const uint32_t numVert = meshGL.NumVert();
const uint32_t numTri = meshGL.NumTri();

Expand Down Expand Up @@ -133,11 +132,7 @@ struct Manifold::Impl {
}

Vec<TriRef> triRef;
if (meshGL.runOriginalID.empty()) {
// FIXME: This affects Impl::InitializeOriginal, and removing this
// apparently make things fail. Not sure if this is expected.
meshRelation_.originalID = Impl::ReserveIDs(1);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @pca006132 I fixed this as part of the rest of this cleanup.

} else {
if (!meshGL.runOriginalID.empty()) {
std::vector<uint32_t> runIndex = meshGL.runIndex;
const uint32_t runEnd = meshGL.triVerts.size();
if (runIndex.empty()) {
Expand Down Expand Up @@ -194,11 +189,6 @@ struct Manifold::Impl {
}
}

std::vector<double> propertyToleranceD(propertyTolerance.size());
manifold::transform(propertyTolerance.begin(), propertyTolerance.end(),
propertyToleranceD.begin(),
[](Precision v) { return (double)v; });

CreateHalfedges(triVerts);
if (!IsManifold()) {
MarkFailure(Error::NotManifold);
Expand All @@ -216,9 +206,8 @@ struct Manifold::Impl {

CalculateNormals();

InitializeOriginal();
if (meshGL.faceID.empty()) {
CreateFaces(propertyToleranceD);
if (meshGL.runOriginalID.empty()) {
InitializeOriginal();
}

SimplifyTopology();
Expand Down
42 changes: 18 additions & 24 deletions src/manifold/src/manifold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,18 +266,9 @@ CsgLeafNode& Manifold::GetCsgLeafNode() const {
* runs.
*
* @param meshGL The input MeshGL.
* @param propertyTolerance A vector of precision values for each property
* beyond position. If specified, the propertyTolerance vector must have size =
* numProp - 3. This is the amount of interpolation error allowed before two
* neighboring triangles are considered to be on a property boundary edge.
* Property boundary edges will be retained across operations even if the
* triangles are coplanar. Defaults to 1e-5, which works well for most
* properties in the [-1, 1] range.
*/
Manifold::Manifold(const MeshGL& meshGL,
const std::vector<float>& propertyTolerance)
: pNode_(std::make_shared<CsgLeafNode>(
std::make_shared<Impl>(meshGL, propertyTolerance))) {}
Manifold::Manifold(const MeshGL& meshGL)
: pNode_(std::make_shared<CsgLeafNode>(std::make_shared<Impl>(meshGL))) {}

/**
* Convert a MeshGL into a Manifold, retaining its properties and merging only
Expand All @@ -299,10 +290,8 @@ Manifold::Manifold(const MeshGL& meshGL,
* triangles are coplanar. Defaults to 1e-5, which works well for most
* properties in the [-1, 1] range.
*/
Manifold::Manifold(const MeshGL64& meshGL64,
const std::vector<double>& propertyTolerance)
: pNode_(std::make_shared<CsgLeafNode>(
std::make_shared<Impl>(meshGL64, propertyTolerance))) {}
Manifold::Manifold(const MeshGL64& meshGL64)
: pNode_(std::make_shared<CsgLeafNode>(std::make_shared<Impl>(meshGL64))) {}

/**
* Convert a Mesh into a Manifold. Will return an empty Manifold
Expand All @@ -312,7 +301,7 @@ Manifold::Manifold(const MeshGL64& meshGL64,
* @param mesh The input Mesh.
*/
Manifold::Manifold(const Mesh& mesh) {
Impl::MeshRelationD relation = {(int)ReserveIDs(1)};
Impl::MeshRelationD relation;
pNode_ =
std::make_shared<CsgLeafNode>(std::make_shared<Impl>(mesh, relation));
}
Expand Down Expand Up @@ -471,12 +460,20 @@ int Manifold::OriginalID() const {
* collapses those edges. In the process the relation to ancestor meshes is lost
* and this new Manifold is marked an original. Properties are preserved, so if
* they do not match across an edge, that edge will be kept.
*
* @param propertyTolerance A vector of precision values for each property
* beyond position. If specified, the propertyTolerance vector must have size =
* numProp - 3. This is the amount of interpolation error allowed before two
* neighboring triangles are considered to be on a property boundary edge.
* Property boundary edges will be retained across operations even if the
* triangles are coplanar. Defaults to 1e-5, which works well for most
* single-precision properties in the [-1, 1] range.
*/
Manifold Manifold::AsOriginal() const {
Manifold Manifold::AsOriginal(
const std::vector<double>& propertyTolerance) const {
auto newImpl = std::make_shared<Impl>(*GetCsgLeafNode().GetImpl());
newImpl->meshRelation_.originalID = ReserveIDs(1);
newImpl->InitializeOriginal();
newImpl->CreateFaces();
newImpl->CreateFaces(propertyTolerance);
newImpl->SimplifyTopology();
newImpl->Finish();
return Manifold(std::make_shared<CsgLeafNode>(newImpl));
Expand Down Expand Up @@ -645,13 +642,12 @@ Manifold Manifold::SetProperties(
if (triProperties.size() == 0) {
const int numTri = NumTri();
triProperties.resize(numTri);
int idx = 0;
for (int i = 0; i < numTri; ++i) {
for (const int j : {0, 1, 2}) {
triProperties[i][j] = idx++;
triProperties[i][j] = pImpl->halfedge_[3 * i + j].startVert;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bug was causing duplicate propVerts to be created unnecessarily.

}
}
pImpl->meshRelation_.properties = Vec<double>(numProp * idx, 0);
pImpl->meshRelation_.properties = Vec<double>(numProp * NumVert(), 0);
} else {
pImpl->meshRelation_.properties = Vec<double>(numProp * NumPropVert(), 0);
}
Expand All @@ -668,8 +664,6 @@ Manifold Manifold::SetProperties(
}

pImpl->meshRelation_.numProp = numProp;
pImpl->CreateFaces();
pImpl->Finish();
return Manifold(std::make_shared<CsgLeafNode>(pImpl));
}

Expand Down
3 changes: 0 additions & 3 deletions src/manifold/src/properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,6 @@ void Manifold::Impl::CalculateCurvature(int gaussianIdx, int meanIdx) {
oldProperties, halfedge_, vertMeanCurvature,
vertGaussianCurvature, oldNumProp, numProp, gaussianIdx,
meanIdx}));

CreateFaces();
Finish();
}

/**
Expand Down
4 changes: 0 additions & 4 deletions src/manifold/src/quickhull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -830,14 +830,10 @@ void Manifold::Impl::Hull(VecView<vec3> vertPos) {

QuickHull qh(vertPos);
std::tie(halfedge_, vertPos_) = qh.buildMesh();
meshRelation_.originalID = ReserveIDs(1);
CalculateBBox();
SetPrecision(bBox_.Scale() * kTolerance);
SplitPinchedVerts();
CalculateNormals();
InitializeOriginal();
CreateFaces({});
SimplifyTopology();
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @Kushal-Shah-03 I simplified the hull setup - hopefully improves the speed a bit.

Finish();
}

Expand Down
1 change: 0 additions & 1 deletion src/manifold/src/sdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,6 @@ Manifold Manifold::LevelSet(std::function<double(vec3)> sdf, Box bounds,
pImpl_->CreateHalfedges(triVerts);
pImpl_->CleanupTopology();
pImpl_->Finish();
pImpl_->meshRelation_.originalID = ReserveIDs(1);
pImpl_->InitializeOriginal();
return Manifold(pImpl_);
}
Expand Down
2 changes: 0 additions & 2 deletions src/manifold/src/smoothing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,9 +993,7 @@ void Manifold::Impl::Refine(std::function<int(vec3)> edgeDivisions) {
InterpTri({vertPos_, vertBary, &old}));
// Make original since the subdivided faces have been warped into
// being non-coplanar, and hence not being related to the original faces.
meshRelation_.originalID = ReserveIDs(1);
InitializeOriginal();
CreateFaces();
}

halfedgeTangent_.resize(0);
Expand Down
2 changes: 1 addition & 1 deletion test/boolean_complex_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ TEST(BooleanComplex, MeshRelation) {
#endif

EXPECT_TRUE(result.MatchesTriNormals());
EXPECT_LE(result.NumDegenerateTris(), 1);
EXPECT_LE(result.NumDegenerateTris(), 12);
EXPECT_EQ(result.Decompose().size(), 1);
auto prop = result.GetProperties();
EXPECT_NEAR(prop.volume, 226, 1);
Expand Down
4 changes: 2 additions & 2 deletions test/hull_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ TEST(Hull, Cube) {

TEST(Hull, Empty) {
const std::vector<vec3> tooFew{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}};
EXPECT_TRUE(Manifold::Hull(tooFew).IsEmpty());
EXPECT_TRUE(Manifold::Hull(tooFew).AsOriginal().IsEmpty());

const std::vector<vec3> coplanar{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}};
EXPECT_TRUE(Manifold::Hull(coplanar).IsEmpty());
EXPECT_TRUE(Manifold::Hull(coplanar).AsOriginal().IsEmpty());
}

TEST(Hull, MengerSponge) {
Expand Down
5 changes: 3 additions & 2 deletions test/manifold_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ TEST(Manifold, Empty) {
}

TEST(Manifold, ValidInput) {
std::vector<float> propTol = {0.1, 0.2};
MeshGL tetGL = TetGL();
Manifold tet(tetGL, propTol);
Manifold tet(tetGL);
EXPECT_FALSE(tet.IsEmpty());
EXPECT_EQ(tet.Status(), Manifold::Error::NoError);
}
Expand Down Expand Up @@ -521,6 +520,7 @@ TEST(Manifold, MeshGLRoundTrip) {

void CheckCube(const MeshGL& cubeSTL) {
Manifold cube(cubeSTL);
cube = cube.AsOriginal();
EXPECT_EQ(cube.NumTri(), 12);
EXPECT_EQ(cube.NumVert(), 8);
EXPECT_EQ(cube.NumPropVert(), 24);
Expand All @@ -540,6 +540,7 @@ TEST(Manifold, Merge) {
EXPECT_EQ(cubeBad.Status(), Manifold::Error::NotManifold);

EXPECT_TRUE(cubeSTL.Merge());
EXPECT_EQ(cubeSTL.mergeFromVert.size(), 28);
CheckCube(cubeSTL);

EXPECT_FALSE(cubeSTL.Merge());
Expand Down
Loading
Loading