From 908b968c5da9dbeb1cfd34c51ca89a35513b9286 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Mon, 18 Aug 2025 12:10:56 -0700 Subject: [PATCH 1/5] add logging --- src/surface_parameterization_quantity.cpp | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/surface_parameterization_quantity.cpp b/src/surface_parameterization_quantity.cpp index fc7b8a44..643fddad 100644 --- a/src/surface_parameterization_quantity.cpp +++ b/src/surface_parameterization_quantity.cpp @@ -102,6 +102,8 @@ void SurfaceParameterizationQuantity::buildCustomUI() { } CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std::string structureName) { + + std::cout << "createCurveNetworkFromSeams: " << structureName << std::endl; // set the name to default if (structureName == "") { @@ -115,6 +117,9 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: parent.edgeIsReal.ensureHostBufferPopulated(); parent.vertexPositions.ensureHostBufferPopulated(); + + std::cout << "populated" << std::endl; + // helper to canonicalize edge direction auto canonicalizeEdge = [](std::pair& inds, std::pair& coords) { @@ -133,6 +138,9 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: // loop over all edges for(size_t iT = 0; iT < parent.nFacesTriangulation(); iT++) { for(size_t k = 0; k < 3; k++) { + + std::cout << " processing edge " << iT << " " << k << std::endl; + if(parent.edgeIsReal.data[3*iT][k] == 0.) continue; // skip internal tesselation edges // gather data for the edge @@ -144,6 +152,9 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: std::pair eC (coords.data[iC_tail], coords.data[iC_tip]); canonicalizeEdge(eInd, eC); // make sure ordering is consistent + std::cout << " iV_tail: " << iV_tail << " iV_tip: " << iV_tip << std::endl; + std::cout << " iC_tail: " << iC_tail << " iC_tip: " << iC_tip << std::endl; + // increment the count if(edgeCount.find(eInd) == edgeCount.end()) { edgeCount[eInd] = 1; @@ -151,6 +162,8 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: edgeCount[eInd] ++; } + std::cout << " incremented" << std::endl; + // check for a collision against a previously seen copy of this edge if(edgeCoords.find(eInd) == edgeCoords.end()) { edgeCoords[eInd] = eC; @@ -160,16 +173,23 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: seamEdges.emplace(eInd); } } + + std::cout << " placed" << std::endl; + } } // add all edges that appeared any number of times other than 2 // (boundaries and nonmanifold edges are always seams) + std::cout << "placing seam edges" << std::endl; for(auto& entry : edgeCount) { if(entry.second != 2) { + std::cout << " emplacing " << entry.second << std::endl; seamEdges.emplace(entry.first); } } + + std::cout << "done placing seam edges" << std::endl; // densely enumerate the nodes of the seam curves std::vector> seamEdgeInds; @@ -178,24 +198,31 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: for(const std::pair& edge: seamEdges) { int32_t vA = edge.first; int32_t vB = edge.second; + + + std::cout << " processing edge " << vA << " " << vB << std::endl; // get unique vertices for the edges + std::cout << " part 1" << std::endl; if(vertexIndToDense.find(vA) == vertexIndToDense.end()) { vertexIndToDense[vA] = seamEdgeNodes.size(); seamEdgeNodes.push_back(parent.vertexPositions.data[vA]); } + std::cout << " part 2" << std::endl; int32_t nA = vertexIndToDense[vA]; if(vertexIndToDense.find(vB) == vertexIndToDense.end()) { vertexIndToDense[vB] = seamEdgeNodes.size(); seamEdgeNodes.push_back(parent.vertexPositions.data[vB]); } int32_t nB = vertexIndToDense[vB]; + std::cout << " part 3" << std::endl; // add the edge seamEdgeInds.push_back({nA, nB}); } // add the curve network + std::cout << " adding!" << std::endl; return registerCurveNetwork(structureName, seamEdgeNodes, seamEdgeInds); } From 5a5a005a99713e807430404633cd3aadc1b980cd Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Mon, 18 Aug 2025 12:23:32 -0700 Subject: [PATCH 2/5] more logs --- src/surface_parameterization_quantity.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/surface_parameterization_quantity.cpp b/src/surface_parameterization_quantity.cpp index 643fddad..09bdcf2c 100644 --- a/src/surface_parameterization_quantity.cpp +++ b/src/surface_parameterization_quantity.cpp @@ -142,23 +142,29 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: std::cout << " processing edge " << iT << " " << k << std::endl; if(parent.edgeIsReal.data[3*iT][k] == 0.) continue; // skip internal tesselation edges + + std::cout << " is real passed" << std::endl; // gather data for the edge int32_t iV_tail = parent.triangleVertexInds.data[3*iT + (k+0)%3]; int32_t iV_tip = parent.triangleVertexInds.data[3*iT + (k+1)%3]; int32_t iC_tail = parent.triangleCornerInds.data[3*iT + (k+0)%3]; int32_t iC_tip = parent.triangleCornerInds.data[3*iT + (k+1)%3]; + std::cout << " iV_tail: " << iV_tail << " iV_tip: " << iV_tip << std::endl; + std::cout << " iC_tail: " << iC_tail << " iC_tip: " << iC_tip << std::endl; std::pair eInd (iV_tail, iV_tip); std::pair eC (coords.data[iC_tail], coords.data[iC_tip]); + std::cout << " eC: " << eC.first << " -- " << eC.second << std::endl; canonicalizeEdge(eInd, eC); // make sure ordering is consistent + std::cout << " canonicalized "<< std::endl; - std::cout << " iV_tail: " << iV_tail << " iV_tip: " << iV_tip << std::endl; - std::cout << " iC_tail: " << iC_tail << " iC_tip: " << iC_tip << std::endl; // increment the count if(edgeCount.find(eInd) == edgeCount.end()) { + std::cout << " new!"<< std::endl; edgeCount[eInd] = 1; } else { + std::cout << " increment!"<< std::endl; edgeCount[eInd] ++; } From d5a6f6e5940032ddd4ddfe175ba055c92b3e86f9 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Mon, 18 Aug 2025 12:35:48 -0700 Subject: [PATCH 3/5] more debugging --- src/surface_parameterization_quantity.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/surface_parameterization_quantity.cpp b/src/surface_parameterization_quantity.cpp index 09bdcf2c..d8f02af5 100644 --- a/src/surface_parameterization_quantity.cpp +++ b/src/surface_parameterization_quantity.cpp @@ -153,6 +153,7 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: std::cout << " iV_tail: " << iV_tail << " iV_tip: " << iV_tip << std::endl; std::cout << " iC_tail: " << iC_tail << " iC_tip: " << iC_tip << std::endl; std::pair eInd (iV_tail, iV_tip); + std::cout << " coords.data.size() = " << coords.data.size() << std::endl; std::pair eC (coords.data[iC_tail], coords.data[iC_tip]); std::cout << " eC: " << eC.first << " -- " << eC.second << std::endl; canonicalizeEdge(eInd, eC); // make sure ordering is consistent From 0ff58b7b482739fdcd89c56f9393d267d89e7938 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Mon, 18 Aug 2025 13:17:35 -0700 Subject: [PATCH 4/5] add buffer view getter, fix curve networks for vertices, cleanup --- include/polyscope/render/managed_buffer.h | 6 +++ .../surface_parameterization_quantity.h | 3 ++ src/render/managed_buffer.cpp | 8 ++++ src/surface_parameterization_quantity.cpp | 46 +++++-------------- test/src/curve_network_test.cpp | 8 ++++ test/src/surface_mesh_test.cpp | 4 ++ 6 files changed, 41 insertions(+), 34 deletions(-) diff --git a/include/polyscope/render/managed_buffer.h b/include/polyscope/render/managed_buffer.h index ccaefb87..594b6b3d 100644 --- a/include/polyscope/render/managed_buffer.h +++ b/include/polyscope/render/managed_buffer.h @@ -178,6 +178,12 @@ class ManagedBuffer : public virtual WeakReferrable { // same view will be returned repeatedly at no additional cost. std::shared_ptr getIndexedRenderAttributeBuffer(ManagedBuffer& indices); + // Get a copy of the data viewed through an index, such that view[i] = data[indices[i]]. + // + // This follows the same logic as above, but rather than returning a render buffer it simply returns a host-side + // copy (which is not cached). + std::vector getIndexedView(ManagedBuffer& indices); + // ======================================================================== // == Direct access to the GPU (device-side) render texture buffer // ======================================================================== diff --git a/include/polyscope/surface_parameterization_quantity.h b/include/polyscope/surface_parameterization_quantity.h index 8e90c47d..957bac4a 100644 --- a/include/polyscope/surface_parameterization_quantity.h +++ b/include/polyscope/surface_parameterization_quantity.h @@ -48,6 +48,7 @@ class SurfaceParameterizationQuantity : public SurfaceMeshQuantity, void createProgram(); size_t nFaces(); // works around an incomplete def of the parent mesh virtual void fillCoordBuffers(render::ShaderProgram& p) = 0; + virtual std::vector getCornerCoords() = 0; }; @@ -66,6 +67,7 @@ class SurfaceCornerParameterizationQuantity : public SurfaceParameterizationQuan protected: virtual void fillCoordBuffers(render::ShaderProgram& p) override; + virtual std::vector getCornerCoords() override; }; @@ -84,6 +86,7 @@ class SurfaceVertexParameterizationQuantity : public SurfaceParameterizationQuan protected: virtual void fillCoordBuffers(render::ShaderProgram& p) override; + virtual std::vector getCornerCoords() override; }; diff --git a/src/render/managed_buffer.cpp b/src/render/managed_buffer.cpp index b8287ff7..35317b12 100644 --- a/src/render/managed_buffer.cpp +++ b/src/render/managed_buffer.cpp @@ -392,6 +392,14 @@ ManagedBuffer::getIndexedRenderAttributeBuffer(ManagedBuffer& indic return newBuffer; } +template +std::vector ManagedBuffer::getIndexedView(ManagedBuffer& indices) { + checkDeviceBufferTypeIs(DeviceBufferType::Attribute); + ensureHostBufferPopulated(); + indices.ensureHostBufferPopulated(); + return gather(data, indices.data); +} + template void ManagedBuffer::updateIndexedViews() { checkDeviceBufferTypeIs(DeviceBufferType::Attribute); diff --git a/src/surface_parameterization_quantity.cpp b/src/surface_parameterization_quantity.cpp index d8f02af5..071df350 100644 --- a/src/surface_parameterization_quantity.cpp +++ b/src/surface_parameterization_quantity.cpp @@ -102,8 +102,6 @@ void SurfaceParameterizationQuantity::buildCustomUI() { } CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std::string structureName) { - - std::cout << "createCurveNetworkFromSeams: " << structureName << std::endl; // set the name to default if (structureName == "") { @@ -111,14 +109,13 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: } // Populate data on the host - coords.ensureHostBufferPopulated(); parent.triangleCornerInds.ensureHostBufferPopulated(); parent.triangleVertexInds.ensureHostBufferPopulated(); parent.edgeIsReal.ensureHostBufferPopulated(); parent.vertexPositions.ensureHostBufferPopulated(); - - std::cout << "populated" << std::endl; + // expand out the coords buffer based on how the quantity is indexed + std::vector cornerCoords = getCornerCoords(); // helper to canonicalize edge direction auto canonicalizeEdge = [](std::pair& inds, std::pair& coords) @@ -139,38 +136,24 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: for(size_t iT = 0; iT < parent.nFacesTriangulation(); iT++) { for(size_t k = 0; k < 3; k++) { - std::cout << " processing edge " << iT << " " << k << std::endl; - if(parent.edgeIsReal.data[3*iT][k] == 0.) continue; // skip internal tesselation edges - - std::cout << " is real passed" << std::endl; // gather data for the edge int32_t iV_tail = parent.triangleVertexInds.data[3*iT + (k+0)%3]; int32_t iV_tip = parent.triangleVertexInds.data[3*iT + (k+1)%3]; int32_t iC_tail = parent.triangleCornerInds.data[3*iT + (k+0)%3]; int32_t iC_tip = parent.triangleCornerInds.data[3*iT + (k+1)%3]; - std::cout << " iV_tail: " << iV_tail << " iV_tip: " << iV_tip << std::endl; - std::cout << " iC_tail: " << iC_tail << " iC_tip: " << iC_tip << std::endl; std::pair eInd (iV_tail, iV_tip); - std::cout << " coords.data.size() = " << coords.data.size() << std::endl; - std::pair eC (coords.data[iC_tail], coords.data[iC_tip]); - std::cout << " eC: " << eC.first << " -- " << eC.second << std::endl; + std::pair eC (cornerCoords[iC_tail], cornerCoords[iC_tip]); canonicalizeEdge(eInd, eC); // make sure ordering is consistent - std::cout << " canonicalized "<< std::endl; - // increment the count if(edgeCount.find(eInd) == edgeCount.end()) { - std::cout << " new!"<< std::endl; edgeCount[eInd] = 1; } else { - std::cout << " increment!"<< std::endl; edgeCount[eInd] ++; } - std::cout << " incremented" << std::endl; - // check for a collision against a previously seen copy of this edge if(edgeCoords.find(eInd) == edgeCoords.end()) { edgeCoords[eInd] = eC; @@ -181,22 +164,16 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: } } - std::cout << " placed" << std::endl; - } } // add all edges that appeared any number of times other than 2 // (boundaries and nonmanifold edges are always seams) - std::cout << "placing seam edges" << std::endl; for(auto& entry : edgeCount) { if(entry.second != 2) { - std::cout << " emplacing " << entry.second << std::endl; seamEdges.emplace(entry.first); } } - - std::cout << "done placing seam edges" << std::endl; // densely enumerate the nodes of the seam curves std::vector> seamEdgeInds; @@ -206,31 +183,23 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: int32_t vA = edge.first; int32_t vB = edge.second; - - std::cout << " processing edge " << vA << " " << vB << std::endl; - // get unique vertices for the edges - std::cout << " part 1" << std::endl; if(vertexIndToDense.find(vA) == vertexIndToDense.end()) { vertexIndToDense[vA] = seamEdgeNodes.size(); seamEdgeNodes.push_back(parent.vertexPositions.data[vA]); } - std::cout << " part 2" << std::endl; int32_t nA = vertexIndToDense[vA]; if(vertexIndToDense.find(vB) == vertexIndToDense.end()) { vertexIndToDense[vB] = seamEdgeNodes.size(); seamEdgeNodes.push_back(parent.vertexPositions.data[vB]); } int32_t nB = vertexIndToDense[vB]; - std::cout << " part 3" << std::endl; // add the edge seamEdgeInds.push_back({nA, nB}); } // add the curve network - std::cout << " adding!" << std::endl; - return registerCurveNetwork(structureName, seamEdgeNodes, seamEdgeInds); } @@ -261,6 +230,11 @@ void SurfaceCornerParameterizationQuantity::fillCoordBuffers(render::ShaderProgr p.setAttribute("a_value2", coords.getIndexedRenderAttributeBuffer(parent.triangleCornerInds)); } + +std::vector SurfaceCornerParameterizationQuantity::getCornerCoords() { + return coords.getIndexedView(parent.triangleCornerInds); +} + void SurfaceCornerParameterizationQuantity::buildCornerInfoGUI(size_t cInd) { glm::vec2 coord = coords.getValue(cInd); @@ -288,6 +262,10 @@ void SurfaceVertexParameterizationQuantity::fillCoordBuffers(render::ShaderProgr p.setAttribute("a_value2", coords.getIndexedRenderAttributeBuffer(parent.triangleVertexInds)); } +std::vector SurfaceVertexParameterizationQuantity::getCornerCoords() { + return coords.getIndexedView(parent.triangleVertexInds); +} + void SurfaceVertexParameterizationQuantity::buildVertexInfoGUI(size_t vInd) { glm::vec2 coord = coords.getValue(vInd); diff --git a/test/src/curve_network_test.cpp b/test/src/curve_network_test.cpp index 8b7fd794..3225a9cf 100644 --- a/test/src/curve_network_test.cpp +++ b/test/src/curve_network_test.cpp @@ -18,6 +18,14 @@ TEST_F(PolyscopeTest, ShowCurveNetwork) { EXPECT_FALSE(polyscope::hasCurveNetwork("test1")); } +TEST_F(PolyscopeTest, EmptyCurveNetwork) { + std::vector points; + std::vector> edges; + polyscope::registerCurveNetwork("empty", points, edges); + polyscope::show(3); + polyscope::removeAllStructures(); +} + TEST_F(PolyscopeTest, CurveNetworkAppearance) { auto psCurve = registerCurveNetwork(); diff --git a/test/src/surface_mesh_test.cpp b/test/src/surface_mesh_test.cpp index dc593f11..16b2ca21 100644 --- a/test/src/surface_mesh_test.cpp +++ b/test/src/surface_mesh_test.cpp @@ -497,6 +497,10 @@ TEST_F(PolyscopeTest, SurfaceMeshVertexParam) { q1->setStyle(polyscope::ParamVizStyle::LOCAL_RAD); polyscope::show(3); + // create the curve network + q1->createCurveNetworkFromSeams(); + polyscope::show(3); + polyscope::removeAllStructures(); } From 337b2071e2fa1201ebd1397bbffeb7cb7f4933f8 Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Mon, 18 Aug 2025 13:19:39 -0700 Subject: [PATCH 5/5] formatting --- src/surface_parameterization_quantity.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/surface_parameterization_quantity.cpp b/src/surface_parameterization_quantity.cpp index 071df350..11945be6 100644 --- a/src/surface_parameterization_quantity.cpp +++ b/src/surface_parameterization_quantity.cpp @@ -135,7 +135,6 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: // loop over all edges for(size_t iT = 0; iT < parent.nFacesTriangulation(); iT++) { for(size_t k = 0; k < 3; k++) { - if(parent.edgeIsReal.data[3*iT][k] == 0.) continue; // skip internal tesselation edges // gather data for the edge @@ -163,7 +162,6 @@ CurveNetwork* SurfaceParameterizationQuantity::createCurveNetworkFromSeams(std:: seamEdges.emplace(eInd); } } - } }