Calling UnifyNormals freezes GH/Rhino on UnWelded mesh - Why?

grasshopper
rhino5
mesh
unhandled

#1

When I run the command UnifyNormals on a mesh from a GrassHopper component, then Rhino freezes if the mesh is Unwelded - Why?

To me it seems like it should work better if all mesh faces were “detached” (unwelded) because then any rewinding of the edges would not affect adjacent faces… but I could be wrong.

In any case, can anyone explain to me why the command tends to get stuck when the mesh is unwelded?

// Rolf


(Giulio Piacentino) #2

It’s probably a bug.
I reported it here: https://mcneel.myjetbrains.com/youtrack/issue/RH-41091

Giulio


Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#4

Ouch, then I will have to learn how to check and update proper winding… (I must stick to Rhino5 for now.)

Any pointers or links to where I can learn more about related strategies for the task?

// Rolf


(Dale Fugier) #5

Hi @RIL,

Can you show some sample code that triggers the display of this message box?

– Dale


(Giulio Piacentino) #6

Sorry, I was assuming that this was a Grasshopper native component. It’s not. Is the component made by a third-party?

To identify its assembly, right-click on its icon on the toolbar, and choose “Component info”. If you cannot find it on the toolbars, you can Ctrl+Alt+Left Click it and Grasshopper will show in which toolbar to find it.


#7

Yup, below.

Yup. Me. :slight_smile:

Da code. (Search for “#”. No method calls before the crash, not even properties) :

    protected override void SolveInstance(IGH_DataAccess DA)
    {
        base.SolveInstance(DA);

        if ( !DA.GetData((int)InPrt.Mesh, ref m_mesh) )
        {
            return;  // Bah, good enough.
        }

        // Unweld - recommended. 
        if ( DA.GetData((int)InPrt.Unweld, ref m_unweld) && m_unweld )
        {
            if ( DA.GetData((int)InPrt.UnweldAngle, ref m_UnweldAngle) )
            {
                m_mesh.Unweld(m_UnweldAngle, true);
            }
        }

        // Fix insconsistencies in the Mesh face winding and face Normals.
        if ( (DA.GetData((int)InPrt.UnifyFN, ref m_UnifyFN)) && m_UnifyFN )
        {
            bool DoUnify = true;

            // WARN AND ASK:
            if ( m_unweld )
            {
                DoUnify = (DialogResult.Yes == MessageBox.Show("The Mesh is Unwelded which can choke the program. Do you still want to Unify FaceNormals?", "WARNING!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning));
            }
            if ( DoUnify )
            {
                // Rearrange the Mesh Faces and Normals
                m_mesh.UnifyNormals();                         // # <----- Gets stuck here.
                // Ensure valid Vertex Normals after unifying Faces.
                m_mesh.Normals.ComputeNormals();
            }
        }

        // If unifying, it is recommended to run ComputeFaceNormals as well:
        if ( DA.GetData((int)InPrt.ComputeFN, ref m_ComputeFN) && m_ComputeFN )
        {
            // Computes all Face Normals for this Mesh based on the physical shape of the Mesh
            m_mesh.FaceNormals.ComputeFaceNormals();
        }

        // RUN LAST (of all the above commands)!
        if ( DA.GetData((int)InPrt.UnitizeFN, ref m_UnitizeFN) && m_UnitizeFN )
        {
            m_mesh.FaceNormals.UnitizeFaceNormals();
        }

// Rolf


(Tim Hemmelman) #8

Hi Rolf,

As far as I can tell the RhinoUnifyMeshNormals SDK function gets called whether from RhinoCommon calls or the UnifyMeshNormals command in Rhino. I say this because I should be able to see the same weirdness in a Grasshopper mesh that is not yet part of the Rhino doc or a mesh that is already in the doc. Can you send me a model that has one of your grasshopper meshes in it that I can run UnifyMeshNormals and see the odd behavior in the debugger? Thanks.

Tim


#9

I ran the command on this mesh, via a std Mesh component fed into my component. This mesh was remeshed with InstantMeshes 6x6 Triangles.

(removed file)

I uploaded the wrong file, and the right one seems to be a bit big. I’ll send the failing mesh over email to support@mcneel.com, is that ok?

I also tested to open and process the Rhino file in VS debug mode and opening Rhino “freestanding”, but it gets stuck in both cases.

// Rolf


(Tim Hemmelman) #10

You can upload it here http://www.rhino3d.com/upload and put my email, tim at same domain, in the to field.


(Tim Hemmelman) #11

If you already sent it to support that’s fine too.


#12

I just uploaded it. In a hurry, forgot to zip it… sorry.

// Rolf


(Tim Hemmelman) #13

Hi Rolf,

I have not been able to get UniifyMeshNormals to fail. The last mesh you sent had a number of duplicate faces and non-manifold edges but the command still completed pretty much instantly. I did notice that the code that does welding/unwelding does not destroy the mesh topology when it’s finished. That seems like a bug but I was still not able to get UnifyMeshNormals to hang after running the Weld and Unweld commands. The Unweld command calls compact on the mesh and that does a bunch of stuff which might include destroying the topology. I’m going to commit a change that explicitly destroys the topology on the output of RhinoUnWeldMesh. It will be in the next WIP (I’m on holiday next week, but the change will be in there). That may help. If it doesn’t, I may need to get the Grasshopper definition too since I can’t repeat this with the model alone.

Tim


#14

I uploaded the GrassHopper definition.

I tried to make a new vs-project with only relevant components, but newbie as I am on VS…

Anyway, hope you will find out what the problem is.

// Rolf


(Dale Fugier) #15

Hi @RIL,

This command code works on the mesh you posted:

protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
  ObjRef obj_ref;
  var rc = Rhino.Input.RhinoGet.GetOneObject("Select mesh to unify normals", false, ObjectType.Mesh, out obj_ref);
  if (rc != Result.Success)
    return rc;

  var mesh = obj_ref.Mesh();
  if (null == mesh)
    return Result.Failure;

  var new_mesh = mesh.DuplicateMesh();
  var count = new_mesh.UnifyNormals();
  if (0 == count)
  {
    RhinoApp.WriteLine("All face normals are already oriented in the same direction.");
    return Result.Success;
  }

  new_mesh.Normals.ComputeNormals();

  doc.Objects.Replace(obj_ref.ObjectId, new_mesh);
  doc.Views.Redraw();

  RhinoApp.WriteLine("Reversed the orientation of {0} faces.", count);

  return Result.Success;
}

– Dale


#16

OK, I’ll try this code tomorrow.

// Rolf


#17

Now I have tried your code (It took a while to test it since I had to learn how to make a RhinoCommon Plugin command, but thanks for pushing me… :slight_smile: ).

Your code example needs an additional line before the case corresponds to the problem I described, like so:

  // copy etc.
  new_mesh.Unweld(180, true);             //   <-- Add this!
  var count = new_mesh.UnifyNormals();    // # <-- You will be stuck here

In other words, same problem as when executed from a GH component.

I tried processing both the original and the copy, same problem.

// Rolf