Exploring Brep, Edges and Trim Curves

Hi,

I am relatively new to the OpenNURBS library.

My ultimate goal is to be able to extract the Brep (polygonal cage) and Trim Curves so that I can reproduce them inside of Houdini for futher experimentation.

Before I get ahead of myself, I need to learn about various I/O approach in OpenNURBS.

I see that there are multiple ways to open a *.3dm file in OpenNURBS to look for information.

If I am mostly after Brep and Trim Curves, what is the recommended way to load a *.3dm via OpenNURBS ?

Cheers

Hi @Nicholas_Yue,

Here is a quick example:

const wchar_t* filename = ...;
ONX_Model model;
if (model.Read(filename))
{
  ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
  const ON_ModelComponent* model_component = nullptr;
  for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
  {
    const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component);
    if (nullptr != model_geometry)
    {
      // Test for Brep object
      const ON_Brep* brep = ON_Brep::Cast(model_geometry->Geometry(nullptr));
      if (nullptr != brep)
      {
        // TODO: do something with the Brep...
      }
    }
  }
}

– Dale

Thank you Dale. Your code is very helpful.

Now that I can find the Trim Curves and also which Brep it belongs to, I have further questions.
What coordinate space are the Trim Curves CVs in ? I see a lot of trim curves in the model I loaded as a test (Rhino logo 3dm), more than I expect. Some of the trim curves has only 2 CVs which looks suspicious to me. I don’t have a 1 Brep 1 Trim Curve *.3dm as a learning starting point so I am a little overwhelm with the data at the moment but making progress.

Does OpenNURBS use right or left handed coordinate system ?

#include <opennurbs_public.h>
#include <string>
#include <boost/format.hpp>
#include <iostream>
#include <cstdio>

int main(int argc, char **argv) {
	if (argc != 2) {
		std::cerr << boost::format("Usage: %1% <3dm file>") % argv[0] << std::endl;
		return 1;
	}

	ON::Begin();
	ON_TextLog error_log;
	ONX_Model model;
	std::string filename(argv[1]);

	if (model.Read(filename.c_str()))
	{
		ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
		const ON_ModelComponent* model_component = nullptr;
		for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
		{
			const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component);
			if (nullptr != model_geometry)
			{
				// Test for Brep object
				const ON_Brep* brep = ON_Brep::Cast(model_geometry->Geometry(nullptr));
				if (nullptr != brep)
				{
					// TODO: do something with the Brep...
					std::cout << "BREP" << std::endl;

					// Surface
					{
						unsigned int num_surface = brep->m_S.Count();
						std::cout << "num_surface = " << num_surface << std::endl;
						for (auto s_index=0;s_index<num_surface;s_index++)
						{

							if (brep->m_S[s_index]->HasNurbForm())
							{
								ON_NurbsSurface nurbs_surface;

								if (brep->m_S[s_index]->GetNurbForm(nurbs_surface))
								{
									int order0 = nurbs_surface.m_order[0];
									int order1 = nurbs_surface.m_order[1];
									std::cout << boost::format("order0=%1%, order1=%2%") % order0 % order1 << std::endl;

								}
							}
						}
					}

					// Trim
					{
						unsigned int num_trim = brep->m_T.Count();
						std::cout << "num_trim = " << num_trim << std::endl;
						for (auto t_index=0;t_index<num_trim;t_index++)
						{
							const ON_BrepTrim& trim = brep->m_T[t_index];

							std::cout << "m_type = " <<  trim.m_type << std::endl;

							if (trim.Brep()) {
								std::cout << "HAS BREP" << std::endl;
							}else{
								std::cout << "HAS NO BREP" << std::endl;
							}
							ON_NurbsCurve trim_nurbs_curve;
							if (trim.NurbsCurve(&trim_nurbs_curve)) {
								int num_cv = trim_nurbs_curve.CVCount();
								std::cout << "Able to get trim as NURBS curve : num_cv = " <<  num_cv << std::endl;
								for (auto tcv_index=0;tcv_index<num_cv;tcv_index++)
								{
									if (trim_nurbs_curve.IsRational())
									{
										ON_4dPoint cv;

										trim_nurbs_curve.GetCV(tcv_index,cv);
										std::cout << boost::format("Rational CV [%f,%f,%f,%f]") % cv.x % cv.y% cv.z% cv.w<< std::endl;
									}
									else
									{
										ON_3dPoint cv;
										trim_nurbs_curve.GetCV(tcv_index,cv);
										std::cout << boost::format("Non-rational CV [%f,%f,%f]") % cv.x % cv.y% cv.z << std::endl;

									}
								}
							}
						}

					}
				}
			}
		}
	}
	ON::End();

	return 0;
}

Rhino (and thus OpenNURBS) is using left handed coordinate system.

Hi @Nicholas_Yue,

This is worth studying:

Something to keep in mind is that openNURBS has curve and surface types other than NURBS, albeit you can get the NURB form of these types.

Also, trim curves are 2d, parameter space curves.

– Dale

I have studied the developer links and I think I am still not understanding something fundamental.

I have create 2 3dm file, one without trim and one with a single trim (single circle)

However, the Count() from a non-trim 3dm gives 4 while a print 1 for a single trim.

I was expecting 0 (zero) for the non-trim 3dm, maybe I am looking at the wrong attribute to query.

My code looks like this

ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
const ON_ModelComponent* model_component = nullptr;
for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
{
    const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component);
    if (nullptr != model_geometry)
    {
        // Test for Brep object
        const ON_Brep* brep = ON_Brep::Cast(model_geometry->Geometry(nullptr));
        if (nullptr != brep)
        {
            // TODO: do something with the Brep...
            std::cout << "BREP" << std::endl;

            std::cout << boost::format("m_T Count = %1%") % brep->m_T.Count() << std::endl;
            std::cout << boost::format("m_C2 Count = %1%") % brep->m_C2.Count() << std::endl;
            std::cout << boost::format("m_C3 Count = %1%") % brep->m_C3.Count() << std::endl;
            std::cout << boost::format("m_L Count = %1%") % brep->m_L.Count() << std::endl;

grid_2x2_single_full_circle_trim.3dm (21.6 KB) grid_2x2.3dm (22.0 KB)

Hi @Nicholas_Yue,

All Breps have trim curves, whether or not the Brep has been “trimmed” or not. The diagram I referenced (above) shows this.

In the case of grid_2x2.3dm, ON_Brep::IsSurface() should return true because the Brep has a single face and that face is geometrically the same as the underlying surface.

– Dale