Box surface Normal pointing inwards... huh?

rhino5

#1

When I test the surface normals on a new Box Brep I noticed that the “bottom” surface has its Normal pointing upwards (inwards that is). How can that be?

Fig. 1. My solid Box, with two identical (length) Normals on top of each other, one Normal starting from the uppermost surfaceand the other one starting from the bottom surface going up through the Box :

How can this be? I test the normal at the middle of the surface, like so :

        InBrep.Surfaces(4).GetSurfaceSize(u, v)
        DA.SetData(OUT_BFN_4, InBrep.Surfaces(4).NormalAt(u/2, v/2))

(The component shown is my own “test component”)


Edit: With “Analyse direction” turned on :

// Rolf


#2

Hi Rolf

I think this might have something to do with this property of BrepFace

http://developer.rhino3d.com/api/RhinoCommonWin/html/P_Rhino_Geometry_BrepFace_OrientationIsReversed.htm

In a brep face, surface orientation and face orientation may be different.

Regards


#3

Hm. What is a Face as opposed to a Surface?

I saw this “BrepFace” for the first time today, and I have no idea what it is. Is there anywhere I can read up on what it is? What’s the difference?

// Rolf


#4

This Brep property gives you the brep’s faces

http://developer.rhino3d.com/api/RhinoCommonWin/html/P_Rhino_Geometry_Brep_Faces.htm

Breps are pretty complex objects … for a humble scripter like me, at least … :confused:


(David Rutten) #5

A Surface is a fairly simple object, basically just a rectangle that can be stretched and bend into some other shape. Some types of surfaces supported in Rhino are PlaneSurface (a literal rectangle with interior), Revolution (one curve swept (partially) in a circle, SumSurface (one curve swept along another curve), and NurbsSurface.

When a surface becomes part of a Brep, it needs additional information and it is wrapped up into a BrepFace. BrepFaces add additional functionality such as trimming edges, some topological stuff, and also a normal-inversion-flag.

The normal direction of a surface is implied by the direction of U and V in any given point. It’s the right-hand-rule; if your index finger points along U, and your middle finger points along V, your thumb is the normal direction. In order to flip the normal direction of a surface, either U or V must be reversed, or U and V must be swapped with each other. This can be difficult depending on the surface type, and always requires the creation a new surface.

Since faces in a brep often need to be flipped to keep the normal direction consistent across edges, we have a single boolean on BrepFace which allows us to invert the normal of the underlying surface without having to reconstruct the surface itself.

Personally I’d have preferred for this boolean to exist on Surface rather than BrepFace, because in the current system it is very easy to lose that information, and this is causing lots of problems in Grasshopper in particular.


#6

This explanation is excellent and should be added to the following documentation pages, at least:

BTW, I did test the BrepFace orientation as well for the “bottom” surface (see code below). This surface seems to have it’s Normal pointing inwards (up) although the Rhino Analyze Direction command indicates that the Normal is OK.
And no surprise, I never encounter OrientationIsReversed = True, but still its Normal points inward(up) when I display using VectorDisplay (see pictures above). All other 5 surfaces are OK except for the “bottom” srf.

        srf = InBrep.Surfaces(4)
        srf.GetSurfaceSize(u, v)
        If InBrep.Faces(4).OrientationIsReversed Then
            DA.SetData(4, srf.NormalAt(u/2, v/2).Reverse())
        Else
            DA.SetData(4, srf.NormalAt(u/2, v/2))
        End If

Any clues as to why this is so?

// Rolf


#7

Rolf,

I think the problem comes from assuming that the underlying surface has the same index as the face.
I mean: Brep.Faces and Brep.Surfaces are independent arrays.

Using BrepFace.SurfaceIndex, things seem to work

import Rhino
import scriptcontext
import System

def main():
  gob = Rhino.Input.Custom.GetObject()
  gob.AcceptNothing( True )
  gob.SetCommandPrompt( 'Brep ?' )
  gob.Get()
  res = gob.Result()
  if res == Rhino.Input.GetResult.Object:
    obref = gob.Object( 0 )
    brep = obref.Brep()
    for face in brep.Faces:
##########################################
      sux = face.SurfaceIndex
##########################################
      surf = brep.Surfaces[ sux ]
      vec = surf.NormalAt( surf.Domain( 0 ).Mid, surf.Domain( 1 ).Mid )
      pnt = surf.PointAt( surf.Domain( 0 ).Mid, surf.Domain( 1 ).Mid )
      colr = System.Drawing.Color.White
      if face.OrientationIsReversed:
        vec.Reverse()
        colr = System.Drawing.Color.Red
      gid = scriptcontext.doc.Objects.AddLine(
          Rhino.Geometry.Line( pnt, vec * 100 ) )
      rob = Rhino.DocObjects.ObjRef( gid ).Object()
      att = rob.Attributes
      decor = Rhino.DocObjects.ObjectDecoration.EndArrowhead
      att.ObjectDecoration = decor
      att.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
      att.ObjectColor = colr
      Rhino.RhinoDoc.ActiveDoc.Objects.ModifyAttributes( rob, att, True )
    scriptcontext.doc.Views.Redraw()
 
main()

#8

Ah thanks, you saved my day! Why didn’t I think of that?

More coffee. :coffee: :coffee: :coffee: :coffee::coffee:

// Rolf