Bug: Project Loose Changes Crv Structure

Project Loose is altering the structure of the output curves. Here are 4 examples (file: projectLooseBug.3dm):


1) The projection of a polycrv with two segments (deg3/8 and deg1/2) is exploded and deg 1/2 curve is rebuilt to deg3/4.

//parent  

  Geometry: 
    Valid curve.
    Closed polycurve with 2 curve segments.
      Segment 1:
        Open NURBS curve
          start = (-0.580,0.275,0.000)
          end = (-0.584,1.204,0.000)
          degree = 3
          control points: non-rational, count=8
          knots: uniform (delta=1.000), domain = 1.000 to 6.000
          clamped at start and end
      Segment 2:
        Line
          start = (-0.584,1.204,0.000)
          end = (-0.580,0.275,0.000)
          domain = 6.000 to 6.929
          line length = 0.929

//children
  Geometry:  
    Valid curve.
    Open NURBS curve
      start = (-0.580,0.275,8.817)
      end = (-0.584,1.204,8.814)
      degree = 3
      control points: non-rational, count=8
      knots: uniform (delta=1.000), domain = 1.000 to 6.000
      clamped at start and end

  Geometry: 
    Valid curve.
    Open NURBS curve (SubD friendly)
      start = (-0.584,1.204,8.814)
      end = (-0.580,0.275,8.817)
      degree = 3
      control points: non-rational, count=4
      knots: uniform (delta=0.929), domain = 6.000 to 6.929
      clamped at start and end
 

2) The projection of a polycrv with two segments (deg3/8 and deg3/5) is exploded, degree and point counts are unchanged.

//parent
  
  Geometry:
    Valid curve.
    Closed polycurve with 2 curve segments.
      Segment 1:
        Open NURBS curve
          start = (1.257,1.204,0.000)
          end = (1.257,0.275,0.000)
          degree = 3
          control points: non-rational, count=5
          knots: uniform (delta=0.500), domain = 0.000 to 1.000
          clamped at start and end
      Segment 2:
        Open NURBS curve
          start = (1.257,0.275,0.000)
          end = (1.257,1.204,0.000)
          degree = 3
          control points: non-rational, count=8
          knots: uniform (delta=1.000), domain = 1.000 to 6.000
          clamped at start and end

//children
     
  Geometry:
    Valid curve.
    Open NURBS curve
      start = (1.257,1.204,6.382)
      end = (1.257,0.275,6.382)
      degree = 3
      control points: non-rational, count=5
      knots: uniform (delta=0.500), domain = 0.000 to 1.000
      clamped at start and end

  Geometry:
    Valid curve.
    Open NURBS curve
      start = (1.257,0.275,6.382)
      end = (1.257,1.204,6.382)
      degree = 3
      control points: non-rational, count=8
      knots: uniform (delta=1.000), domain = 1.000 to 6.000
      clamped at start and end

3) The projection of a polycrv with two segments (deg3/8 and deg3/5) with continuity closer to G1 than G0 results in a single non-uniform deg3/12 curve that is not smooth(?!?) and will explode into two curves(?!?).

//parent 
  
  Geometry:
    Valid curve.
    Closed polycurve with 2 curve segments.
      Segment 1:
        Open NURBS curve
          start = (-0.617,-0.241,0.000)
          end = (-0.617,-1.170,0.000)
          degree = 3
          control points: non-rational, count=5
          knots: uniform (delta=0.500), domain = 0.000 to 1.000
          clamped at start and end
      Segment 2:
        Open NURBS curve
          start = (-0.617,-1.170,0.000)
          end = (-0.617,-0.241,0.000)
          degree = 3
          control points: non-rational, count=8
          knots: uniform (delta=1.000), domain = 1.000 to 6.000
          clamped at start and end

//child

  Geometry:
    Valid curve.
    Closed NURBS curve
      start = (-0.617,-0.241,5.064)
      end = (-0.617,-0.241,5.064)
      degree = 3
      control points: non-rational, count=12 (1 duplicate)
      knots: non-uniform, domain = 0.000 to 6.000
      clamped at start and end
      Curve is not smooth.  If you explode it, it will become two or more curves.

4) The projection of a polycrv with two segments (deg3/8 and deg3/5) that are G1 results in a single deg3/12 curve that is non-uniform and non-periodic.

//parent
  
  Geometry:
    Valid curve.
    Closed polycurve with 2 curve segments.
      Segment 1:
        Open NURBS curve
          start = (1.177,-0.241,0.000)
          end = (1.177,-1.170,0.000)
          degree = 3
          control points: non-rational, count=5
          knots: uniform (delta=0.500), domain = 0.000 to 1.000
          clamped at start and end
      Segment 2:
        Open NURBS curve
          start = (1.177,-1.170,0.000)
          end = (1.177,-0.241,0.000)
          degree = 3
          control points: non-rational, count=8
          knots: uniform (delta=1.000), domain = 1.000 to 6.000
          clamped at start and end

//child 

  Geometry:
    Valid curve.
    Closed NURBS curve
      start = (1.177,-0.241,6.326)
      end = (1.177,-0.241,6.326)
      degree = 3
      control points: non-rational, count=12 (1 duplicate)
      knots: non-uniform, domain = 0.000 to 6.000
      clamped at start and end

I tried using a scripted function that projects curves along a vector (in this case World Z axis) to a plane. The plane was determined by picking 3 points on your surface plane. This way does not seem to alter the curve structure - just submitted as a comparison/debug help.

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def TestProjectAlong():
    crv_ids=rs.GetObjects("Select curves to project",4,preselect=True)
    if not crv_ids: return
    
    msg1="Pick point for origin"
    msg2="Pick point for X axis and then Y axis"
    pts=rs.GetPoints(True,message1=msg1, message2=msg2, max_points=3)
    if not pts: return
    plane=rs.PlaneFromPoints(pts[0],pts[1],pts[2])
    crvs=[rs.coercecurve(crv_id) for crv_id in crv_ids]
    proj_vec=Rhino.Geometry.Vector3d(0,0,1)
    xform=Rhino.Geometry.Transform.ProjectAlong(plane,proj_vec)
    for crv in crvs: crv.Transform(xform)
    proj_ids=[sc.doc.Objects.AddCurve(crv) for crv in crvs]
    rs.SelectObjects(proj_ids)
TestProjectAlong()

projectLooseBug-test-msh.3dm (4.0 MB)

Thanks - my guess of the moment is this may be related to the maintaining of sub curve structure within a polycurve. I’ll run it by the developer - Projecting edit points does the right thing, at least in my quick test.
RH-70679 Project > Loose changes curves

-Pascal

1 Like

Yeah, that works but then there’s no history. I need to get profiles into place matching a particular projection angle.

That works for 3 of those 4 cases (which are the ones I care about). It does a weird thing with the first case(deg3/8 and deg1/2). It starts off perfect, but after the first edit, the line sub curve teleports from the child to the parent.

That is possible to do via scripting, but I haven’t done it often, so it may take some experimenting…

Voila, it actually wasn’t that hard.

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import Rhino.ApplicationSettings.HistorySettings as hs

def TestProjectAlongWHist():
    crv_ids=rs.GetObjects("Select curves to project",4,preselect=True)
    if not crv_ids: return
    hist=hs.RecordingEnabled
    
    msg1="Pick point for origin"
    msg2="Pick point for X axis and then Y axis"
    pts=rs.GetPoints(True,message1=msg1, message2=msg2, max_points=3)
    if not pts: return
    plane=rs.PlaneFromPoints(pts[0],pts[1],pts[2])
    proj_vec=Rhino.Geometry.Vector3d(0,0,1)
    xform=Rhino.Geometry.Transform.ProjectAlong(plane,proj_vec)
    proj_ids=[sc.doc.Objects.TransformWithHistory(crv_id,xform) for crv_id in crv_ids]
    rs.SelectObjects(proj_ids)
TestProjectAlongWHist()

projectLooseBug-test-msh2.3dm (4.0 MB)

1 Like

Can you make the plane be a part of history? I need it to move along the Z.

No, because it’s not an object and it’s not associated with the surface in the file. The script was just proof-of-concept that projecting to a plane can work correctly. I think the problem is that the code for Project (to a surface) is not the same as project to a theoretical plane, because you can also project to non-planar surfaces.

dear @EricM
a possible workaround:
if you just project to a plane - you can use shear instead.
_shear copy=yes
supports history.
screenshot shows how to find the correct points for shear, in your case cplane = front

Thanks, I get that, but I really need the history for the crv and the plane. I need to edit the profile crv, the projection angle, and the projection distance.

@pascal, projecting the points works for now. I tried using Joincopy as a workaround, but the output polycrv was especially prone to randomly flip the seam location and/or direction with different projection angles. I’m not sure if @mikko is aware of that issue with Joincopy.

I love Joincopy, it’s a huge time saver, I use it dozens of times per day…but I am really bummed out when a seam/dir flips and my lofts go haywire.