Problem with creation of a ON_BezierSurface by lofting

Hi,

I’m trying to create an interpolation surface for an airfoil by using the method
ON_BezierSurface::Loft(int count, const ON_BezierCurve* const* curve_list);

I start out with a set of ON_BezierCurves, lofted from points themselves
pointers to which I store in a std::vector<ON_BezierCurve*>.
The compiler doesn’t complain about feeding ‘CurveList.data()’ to the method.
I decided to do it like this, because there is no documentation about how
ON_ClassArray<> works, and the implementation of
bool Loft( const ON_ClassArray<ON_BezierCurve>& curve_list );
creates a list of pointers anyway and calls the method I try to use.

When trying to render, everything looks fine for the original curves,
but the result for the surface shows a strange shape, that is reproducably
related to the input. It looks sort of like a foil that has been smashed against
a brick wall at high velocity.

The same input data used as control vertices of a NURBS produces a great
looking result, but it’s not an interpolation, which is required.

My system is Debian GNU Linux 10.10 and opennurbs-7.6.21127.19001,
compiler gcc (Debian 8.3.0-6) 8.3.0, used with ‘-Wall’.
If this is not clear enough, I can post the relevant parts of the code.

Kind Regards, Armin

P.S. I needed to fix some minor issues, to get opennurbs to compile,
but I don’t think this is related to the problem.
I’d like to share those fixes.

Hi @armin1l

ON_ClassArray is fully documented. See opennurbs_array.y for details.

Here is a simple example:

ON_ClassArray<ON_BezierCurve> curve_list;

for (int i = 0; i < curve_count; i++)
{
  ON_BezierCurve curve = YourCurveCreationFunction(i);
  if (curve.IsValid())
    curve_list.Append(curve);
}

if (curve_list.Count() > 2)
{
  ON_BezierSurface surface;
  if (surface.Loft(curve_list) && surface.IsValid())
  {
    // TODO...
  }
}

– Dale

Hello Dale,

thank you for the fast response.
I studied opennurbs_array.h a bit now and set up the lofting the way you tell me.
The result is basically the same. I made a screenshot:
https://imgur.com/a/dO8hoxZ - maybe it rings a bell for someone.
In magenta the NURBS and in yellow the lofted bezier surface from the same data.
Both my old code and the modified one show the curves and loft surface successfully
lofted and valid (see second preformated text).
Since the problem may come from evaluation of the surface too, here I add the code
that renders the yellow stuff:

  1             //___ render Bezier surface in straigt space
  2             bool good;
  3             int i, j;
  4             double u, v, du, dv, data[4];
  5             int strd = TheLoft->Dimension();
  6             int uResolution {m_uResolution / 4}, vResolution {m_vResolution / 4};
  7 
  8             ON_Interval uIvl = TheLoft->Domain(0);
  9             ON_Interval vIvl = TheLoft->Domain(1);
 10             du = (uIvl.m_t[1] - uIvl.m_t[0]) / double(uResolution);
 11             dv = (vIvl.m_t[1] - vIvl.m_t[0]) / double(vResolution);
 12 
 13             glColor3ub(255, 255, 0);
 14             for (i = 0; i <= uResolution; i++) {
 15                 u = i * du + uIvl.m_t[0];
 16                 glBegin(GL_LINE_STRIP);
 17                 for (j = 0; j <= vResolution; j++) {
 18                     v = j * dv + vIvl.Min();
 19                     ON_3dPoint p = TheLoft->PointAt(u, v);
 20                     glVertex3d(p.x, p.y, p.z);
 21                 }   
 22                 glEnd();
 23             }   
 24             for (j = 0; j <= vResolution; j++) {
 25                 v = j * dv + vIvl.m_t[0]; 
 26                 glBegin(GL_LINE_STRIP);
 27                 for (i = 0; i <= uResolution; i++) {
 28                     u = i * du + uIvl.m_t[0]; 
 29                     good = TheLoft->Evaluate(u, v,  // parameters
 30                                              0,     // number of derivatives
 31                                              strd,  // array stride
 32                                              data); // array of length stride*(ndir+1)*(ndir+2)/2
 33                     if (!good) {             
 34                         printf("evaluation at (%lf, %lf) failed\n", u, v);
 35                     } else {
 36                         glVertex3d(data[0], data[1], data[2]);
 37                     }   
 38                 }
 39             }   

As you can see, I use 2 methods (PointAt() and Evaluate()), but that doesn’t make a difference in tests. Because your example requires more than 2 curves, I used three.
Before you ask: the NURBS profile does have a pointy tip, but the Bezier lofting uses
only the 3 profiles and should be open at the top and bottom.
The 3 cyan profile curves are what went into the loft and their rendering happened
after the lofting. One of the end curves of the yellow wire wool starts tangential
to the bottom profile.
Here some output, showing what the classes themselves think about their state:

 0  x/y/rad: -400.000,    0.000,  150.000
 0  x/y/rad:    0.000,   20.000,  150.000
 0  x/y/rad:  150.000,   40.000,  150.000
 0  x/y/rad:  200.000,    0.000,  150.000
 0  x/y/rad:  150.000,  -40.000,  150.000
 0  x/y/rad:    0.000,  -70.000,  150.000
 0  x/y/rad: -400.000,    0.000,  150.000
loftSurface: 1. bezier curve: good, is valid: yes
 1  x/y/rad: -400.000,    0.000,  500.000
 1  x/y/rad:    0.000,   40.000,  500.000
 1  x/y/rad:  150.000,   25.000,  500.000
 1  x/y/rad:  200.000,    0.000,  500.000
 1  x/y/rad:  150.000,  -25.000,  500.000
 1  x/y/rad:    0.000,  -40.000,  500.000
 1  x/y/rad: -400.000,    0.000,  500.000
loftSurface: 2. bezier curve: good, is valid: yes
 2  x/y/rad: -300.000,    0.000, 1000.000
 2  x/y/rad:    0.000,   30.000, 1000.000
 2  x/y/rad:  100.000,   20.000, 1000.000
 2  x/y/rad:  150.000,    0.000, 1000.000
 2  x/y/rad:  100.000,  -20.000, 1000.000
 2  x/y/rad:    0.000,  -30.000, 1000.000
 2  x/y/rad: -300.000,    0.000, 1000.000
loftSurface: 3. bezier curve: good, is valid: yes
loftSurface: lofting of bezier surface: good
   is valid: yes
   u-order = 3,  v-order = 7

Originally I used 2 to 4 curves, all resulting in fine NURBS and crooked Bezier surfaces.
Why is lofting between only 2 Bezier curves not good?

Thanks again, Armin

Hi @armin1,

ON_BezierSurface::Loft is not used in core Rhino. So I have no idea if it works or not. But it’s doubtful lofting bezier curves will give you the shape you are looking for, which I assume is something like the attached.

test_loft.3dm (41.0 KB)

ON_Surface::CreateCubicLoft might get you there. But openNURBS does not include methods for interpoating NURBS curves from a list of points.

– Dale

Hi Dale,

thank you for your honest reply and sorry for my late reply.
In the meantime, I implemented lofting of B-spline surfaces as described in ‘The NURBS Book’. The result + an exact transformation to propeller geometry looks like this:
When quenched in water, it's actually cool - Album on Imgur
In addition there is a test surface, that shows my interpolating B-spline surface with input and control points.

I’ve been fighting with DXF-export and porting my application to Windows (again) and all the while it’s Summer!

I have looked for ON_Surface::CreateCubicLoft in the code, and iirc, it’s mentioned twice in comments, but doesn’t appear in the active code.
I couldn’t use my standard CAD application (NX) to open your test file, probably since my license isn’t large enough. I’ll give it a try, should I find something open source or get around to implement import of 3dm files.

Kind Regards, Armin