[FWD] How to retrieve the index of the closest polygon in a mesh to a point?
-
Dear community,
we received a support request via mail which we thought might also be interesting to the community. This thread captures the question asked in the mail.
The question is "How to retrieve the index of the closest polygon in a mesh to a point?". The question has been asked for the C++ environment, looking for the right optimization data structure provided by the C++ SDK.
Cheers,
Ferdinand -
Dear user,
the problem with your example code is that you do use a
VoxelizationInterfacewhich is not well suited for this task. The typeDistanceQueryInterface(Documentation) is much better suited for the task. You should also be more cautious with statements like the following, taken from your code,voxelRef = maxon::PolyVoxelization().Create() iferr_ignore("Could not create VoxelizationRef");as stepping over a failure of initialization will lead to crashes. At the end of this posting you will find an example for how to use
DistanceQueryInterfaceas well as some light comments on error handling.I hope this helps and cheers,
Ferdinand/* This function expects a point object (A) to be the first object in the scene, followed by a polygon object (B) as the second object. It will then return the index for closest polygon in B for each vertex in A. */ static maxon::Result<void> Pc13296(BaseDocument* doc) { iferr_scope; // Get the first and second node in the scene. The first one is expected // to be a point node, serving as a point source, and the second one is // expected to be a polygon node, serving as a polygon source. BaseObject* node = doc->GetFirstObject(); if (node == nullptr || !node->IsInstanceOf(Opoint)) { ApplicationOutput("Please provide a point object as the first node in the scene."_s); return maxon::OK; } PointObject* pointNode = static_cast<PointObject*>(node); node = node->GetNext(); if (node == nullptr || !node->IsInstanceOf(Opolygon)) { ApplicationOutput("Please provide a polygon object as the second node in the scene."_s); return maxon::OK; } PolygonObject* polygonNode = static_cast<PolygonObject*> (node); // Get access to the point and polygon data and the global transforms of both nodes. const Vector* points = pointNode->GetPointR(); const CPolygon* polygons = polygonNode->GetPolygonR(); const int pointCount = pointNode->GetPointCount(); const int polygonCount = polygonNode->GetPolygonCount(); Matrix mgPointNode = pointNode->GetMg(); // We invert it right away, as we only will need it in this form. Matrix iMgPolygonNode = ~polygonNode->GetMg(); // When an error is being raised by Cinema we should be cautious with using iferr_ingore, as // then the code will keep running in the current scope. In some cases like manipulating an // array like structure this can be useful. But when an initialization of an entity fails, we // almost never want to keep going, as trying to use that not initialized object then will be // a sure fire way to crash Cinema 4D. Instead we can either use iferr_return to simply leave // the current scope, use iferr_throw to throw a specific error or handle it manually with // iferr(). Below you will find a two examples. // Create a reference to the distance query interface. maxon::DistanceQueryRef distanceQuery = maxon::DistanceCalculator().Create() iferr_return; // Pass true for the second argument to voxelize the input to speed up larger queries. Just as // with any optimization, for smaller data sets this voxelization setup might eat up all the // performance benefits gained latter on. iferr(distanceQuery.Init(polygonNode, false)) { ApplicationOutput("Failed to initialize DistanceQueryInterfacae for @", polygonNode->GetName()); return maxon::OK; } // Go over all vertices and query them for the closest polygon (id) in the other mesh. float distance = 0; Vector p; for (int poindId = 0; poindId < pointCount; poindId++) { // The point in the point mesh converted first to global coordinates and then to local // coordinates in the polygon node. We have to do that because the points in the point // source live in their own coordinate system as well the ones in the polygon source. p = mgPointNode * iMgPolygonNode * points[poindId]; maxon::PrimitiveInformation info; distance = distanceQuery.GetClosestMeshPrimitive(p, info); ApplicationOutput("Closest polygon id for point id @: @", poindId, info.GetRealPolyIndex()); } return maxon::OK; }The output/setup:

-
I was very happy to find this nice example. Thanks Ferdinand!
However looking at the docs and If I have understood this correctly, I should be able to include <distancequery.h> to get access to the DistanceQueryInterface.
My problem is that the <distancequery.h> source file is not found.
All common frameworks are available to my build system.
Any help or hint on what to look for would be much appreciated. I'm sure I have overlooked something trivial.
set(maxon_targetFrameworkDependencies
asset.framework
cinema.framework
cinema_hybrid.framework
crypt.framework
core.framework
corenodes.framework
command.framework
image.framework
math.framework
misc.framework
mesh_misc.framework
python.framework
) -
Hey @dex,
distancequery.his part of themesh_misc.frameworkwhich you alreeady include. Sounds a bit like you have a corrupted build system on your hands or are not using the frameworks you think you are using. Where does the CMake fragment come from you show us? I assume you are using the oldprojectdefintion.txtsourced workflow (in which case you should us show that file). Or are you a beta member and have access to the 2027 SDK (which is natively pure CMake), in which case this would be invalid CMake markup, as some stuff has changed.Have you checked in the IDE of your choice that the
mesh_misc.frameworkshows up as a dependency of the project in which you want to#include "maxon/distancequery.h"? And just for the recoord, this is not a std lib, so you cannot use#include <>but must use#include "". And since this is part of the Maxon API, you also need to specify themaxonfolder.Cheers,
Ferdinand