Bug report: Rhino.Geometry.Curve.ProjectToPlane error with ArcCurve

I’ve got a wrong result when using Rhino.Geometry.Curve.ProjectToPlane on an ArcCurve.

Here is a Rhino file:
bug curve.3dm (41.1 KB)

Here is the script:

import Rhino
import scriptcontext as sc

def getCurrentCPlane():
    viewport = sc.doc.Views.ActiveView.MainViewport
    return viewport.GetConstructionPlane()

def getCurvesRefs():
    crvType = Rhino.DocObjects.ObjectType.Curve
    res = Rhino.Input.RhinoGet.GetMultipleObjects( "Select curves to flatten", False, crvType )
    if res[0] == Rhino.Commands.Result.Success:
        curvesRefs = []
        for objRef in res[1]:
            curvesRefs.append( objRef )
    return curvesRefs

def flattenCurves( curvesRefs ):
    if curvesRefs == None:
        return
    plane = getCurrentCPlane().Plane
    for curveRef in curvesRefs:
        curve = curveRef.Curve()
        curveOnPlane = Rhino.Geometry.Curve.ProjectToPlane( curve, plane )
        sc.doc.ActiveDoc.Objects.Replace( curveRef, curveOnPlane )
    sc.doc.ActiveDoc.Views.Redraw()

curvesRefs = getCurvesRefs()
flattenCurves( curvesRefs )

Steps to reproduce:

  1. open the file, go to front view
  2. run EditPythonScript, copy the script above.
  3. run the script, select the curve and press enter.
  4. the result is unexpected: it’s a circle normal to the plane, whereas it should be an ellipse.

I tested on several curves, it seems that it only happens when the curve is an ArcCurve.

Rhino 8 SR14 2024-12-10 (Rhino 8, 8.14.24345.15001, Git hash:master @ cdb74b46090a23fe242c51b288886f76467a741b)
License type: Commercial, build 2024-12-10
License details: Cloud Zoo

Windows 11 (10.0.22631 SR0.0) or greater (Physical RAM: 31GB)
.NET 7.0.0

Computer platform: LAPTOP  - Plugged in [100% battery remaining]

Hybrid graphics configuration.
  Primary display: AMD Radeon(TM) Graphics (AMD) Memory: 1GB, Driver date: 10-17-2023 (M-D-Y).
    > Integrated accelerated graphics device with 3 adapter port(s)
        - Secondary monitor is laptop's integrated screen or built-in port
        - Windows Main Display attached to adapter port #1
  Primary OpenGL: NVIDIA GeForce RTX 3070 Laptop GPU (NVidia) Memory: 8GB, Driver date: 10-15-2024 (M-D-Y). OpenGL Ver: 4.6.0 NVIDIA 566.03
    > Integrated accelerated graphics device with 4 adapter port(s)
        - Secondary monitor is laptop's integrated screen or built-in port

OpenGL Settings
  Safe mode: Off
  Use accelerated hardware modes: On
  GPU Tessellation is: On
  Redraw scene when viewports are exposed: On
  Graphics level being used: OpenGL 4.6 (primary GPU's maximum)
  
  Anti-alias mode: 4x
  Mip Map Filtering: Linear
  Anisotropic Filtering Mode: High
  
  Vendor Name: NVIDIA Corporation
  Render version: 4.6
  Shading Language: 4.60 NVIDIA
  Driver Date: 10-15-2024
  Driver Version: 32.0.15.6603
  Maximum Texture size: 32768 x 32768
  Z-Buffer depth: 24 bits
  Maximum Viewport size: 32768 x 32768
  Total Video Memory: 8 GB

Rhino plugins that do not ship with Rhino
  C:\Program Files\SimLab\Plugins\SimLab PDF From Rhino\SimLabPDFExporter.rhp	"SimLab PDF Exporter"	

Rhino plugins that ship with Rhino
  C:\Program Files\Rhino 8\Plug-ins\Commands.rhp	"Commands"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\rdk.rhp	"Renderer Development Kit"	
  C:\Program Files\Rhino 8\Plug-ins\RhinoRenderCycles.rhp	"Rhino Render"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\RhinoRender.rhp	"Legacy Rhino Render"	
  C:\Program Files\Rhino 8\Plug-ins\rdk_etoui.rhp	"RDK_EtoUI"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\NamedSnapshots.rhp	"Snapshots"	
  C:\Program Files\Rhino 8\Plug-ins\MeshCommands.rhp	"MeshCommands"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\IronPython\RhinoDLR_Python.rhp	"IronPython"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\RhinoCycles.rhp	"RhinoCycles"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\Toolbars\Toolbars.rhp	"Toolbars"	8.14.24345.15001
  C:\Program Files\Rhino 8\Plug-ins\3dxrhino.rhp	"3Dconnexion 3D Mouse"	
  C:\Program Files\Rhino 8\Plug-ins\Displacement.rhp	"Displacement"	
  C:\Program Files\Rhino 8\Plug-ins\SectionTools.rhp	"SectionTools"

I confirm that if you convert the ArcCurve to NurbsCurve it works as expected.
curve = curve.ToNurbsCurve()

@felix.mariotto - this works too:

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.geometrybase/makedeformable

– Dale

You mean that it’s not a bug, it’s intended ?

A Rhino.Geometry.ArcCurve can only represent an arc. The projection of your arc to that plane is not an arc. Like you do with curve = curve.ToNurbsCurve() you need to convert your curve to something that can be deformed by the transformation.

I understand the logic, but then it’s hardly a projection, it’s just a transformation. Yes this kind of transformation can also be called a projection but I don’t think it should be mixed like this in the API. In a context where the user wants a script that projects any curves on a plane, it is unexpected and feels like a bug. I got the unforeseen case when my curve was not a normal curve but an ArcCurve, then I had to debug to understand what I just understood.

I think Rhino.Geometry.Curve.ProjectToPlane should make deformable by default, and maybe take an optional boolean argument for those (I assume very rare) cases when you don’t want a deformation. Which makes more sense because you could project a NurbsCurve without deformation with the same API.

This way you offer explicit instructions “project (and deform by default)”, and “project and don’t deform” for all curves, instead of “project and deform maybe, it depends on the type of curve”. It’s much more user-friendly this way I think.

Hi @felix.mariotto,

I’ve logged the issue so I can look into this.

https://mcneel.myjetbrains.com/youtrack/issue/RH-85269

Thanks,

– Dale