Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Recent
    • Tags
    • Users
    • Register
    • Login

    [FWD] How to retrieve the index of the closest polygon in a mesh to a point?

    Scheduled Pinned Locked Moved Cinema 4D SDK
    c++r23windowsmacos
    4 Posts 2 Posters 481 Views 1 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ferdinandF Offline
      ferdinand
      last edited by

      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

      MAXON SDK Specialist
      developers.maxon.net

      1 Reply Last reply Reply Quote 0
      • ferdinandF Offline
        ferdinand
        last edited by ferdinand

        Dear user,

        the problem with your example code is that you do use a VoxelizationInterface which is not well suited for this task. The type DistanceQueryInterface(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 DistanceQueryInterface as 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:
        642545d3-3ffa-467e-9123-cf0a328b18f1-image.png

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 1
        • dexD Offline
          dex
          last edited by dex

          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
          )

          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF Offline
            ferdinand @dex
            last edited by ferdinand

            Hey @dex,

            distancequery.h is part of the mesh_misc.framework which 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 old projectdefintion.txt sourced 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.framework shows 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 the maxon folder.

            Cheers,
            Ferdinand

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • First post
              Last post