Not sure how to debug Mac GH Python error

A bunch of issues related to debugging and integration of Python in GH.

Trying to do the Exploded Box Python example (pg 31) from Essential Mathematics for Computational Design. I’m not sure how to debug this since it doesn’t tell me what line the error is at. Not sure what “balloon” is (if not red comment icon…) Not sure if error is due to a dif between Rhino 5 and 6, Rhino WIn and Mac, or other.

My code:

“”“Provides a scripting component.
Inputs:
box: The geometry being exploded
dis: The distance to explode
Output:
a: The a output variable”""

author = “kmochel”

import rhinoscriptsyntax as rs
import Rhino

#get the brep center
area = Rhino.Geometry.AreaMassProperties.Compute(box)
box_center = area.Centroid

#get a list of faces
faces = box.Faces

#declare variables
exploded_faces =

#loop through all faces
for i, face in enumerate(faces):

#get a duplicate of the face
extracted_face = faces.ExtractFace(i)

#get the center of each face
area = Rhino.Geometry.AreaMassProperties.Compute(extracted_face)
center = area.Centroid

#calculate move direction (from box centroid to face center)
dir = center - box_center
dir.Unitize()
dir *= dis

#move the extracted face
move = Rhino.Geometry.Transform.Translation(dir)
extracted_face.Transform(move)

#add to exploded_faces list
exploded_faces.append(extracted_face)

#assign exploded list of faces output
A = exploded_faces

This is the components in GH:

Hi @kalmdown,

Long story short, the Mac version of the GHPython component sucks as a text editor/IDE, and we shouldn’t expect any improvements before the “next version of Rhino” (according a recent discussion). In terms of running code, it mostly works just fine though.

In order to get clearer, more detailed debugging information, you can plug a panel into the out output of the GHPython component. This will then show you on which line of code your errors occur.

I doubt that! It seems to be a value error, since it tells you that it expected a curve, but got a GUID.
First of all, you must understand that the rhinoscriptsyntax mostly refers to geometry by GUID, a type of id, and the API (i.e. Rhino) deals with “code” objects. I can’t handle GUIDs unless you convert them first.
Generally speaking it is not a good idea to mix both, since you then have to deal with these kinds of conversion errors.
The rhinoscriptsyntax is a Python wrapper for the Rhino API, and is usually better for beginners, since it’s easier to understand (nearer to Rhino commands). The downside is that it’s less flexible and usually slower.
The Rhino API is for more advanced users, since you have to be familiar with some coding concepts, like object-oriented programming and other stuff, to comprehend how everything works structurally.

Your code seems to be API oriented, so I stuck with that. Here’s a simplified, working version:

"""Explodes a box geometry and offsets its faces along their normal vectors.
    Inputs:
        box: A box geometry
        dist: An offset distance
    Output:
        a: The exploded, offset box faces"""

__author__ = "p1r4t3b0y"
__version__ = 0.2

import Rhino

# Get the box center
box_center = box.Center
# Convert the box to a brep 
bbrep = Rhino.Geometry.Box.ToBrep(box)
# Get a list of faces
faces = bbrep.Faces

exploded_faces = [] # empty faces list

for i in xrange(faces.Count):
    face = faces[i] # current face
    # Reparameterise the current face
    face.SetDomain(0, Rhino.Geometry.Interval(0,1))
    face.SetDomain(1, Rhino.Geometry.Interval(0,1))
    # Get the center of the current face
    face_center = face.PointAt(0.5, 0.5)
    # Calculate the translation vector
    vec = face_center - box_center
    vec.Unitize()
    vec *= dist
    # Convert the face to a brep
    fbrep = face.ToBrep()
    # Move the face brep
    fbrep.Translate(vec)
    # Store the moved brep
    exploded_faces.append(fbrep)

# Output
a = exploded_faces

Note that it was this line of code that threw the error:

area = Rhino.Geometry.AreaMassProperties.Compute(box)

Simply because it expects a brep, mesh, or curve geometry and can’t handle boxes (cf. documentation). A box is not a brep, unless you convert it first, or set the type hint of your “box” input to brep (which then does the conversion for you).
However, as you may have noticed in my code, this line is not even necessary, since a box object has already a center property built in.

1 Like

Thank you so much for all of the info. Really appreciate the details. - Karl

This example came from a book. Do you know any good resources for translating (dealing with the differences) between the script and APIs? - Thanks, Karl

Hm, there’s always the documentation for both - the rhinoscriptsyntax and API - that you can take a look at, if you are searching for specific functions and methods.
If you want to look up how a certain method of the rhinoscriptsyntax wraps code from the API, you can do the following in GHPython:

import rhinoscriptsyntax as rs
import inspect

print inspect.getsource(rs.GetPointOnCurve)

This will print a behind-the-scenes look at the rhinocommon function that is called, when you use rs.GetPointOnCurve from the rhinoscriptsyntax. For this example, the following gets printed:

def GetPointOnCurve(curve_id, message=None):
    """Pauses for user input of a point constrainted to a curve object
    Parameters:
      curve_id (guid): identifier of the curve to get a point on
      message (str, optional): a prompt of message
    Returns:
      point: 3d point if successful
      None: on error
    Example:
      import rhinoscriptsyntax as rs
      obj = rs.GetObject("Pick a curve")
      if rs.IsCurve(obj):
          point = rs.GetPointOnCurve(obj, "Point on curve")
          if point: rs.AddPoint(point)
    See Also:
      GetPoint
      GetPointOnMesh
      GetPointOnSurface
      GetPoints
    """
    curve = rhutil.coercecurve(curve_id, -1, True)
    gp = Rhino.Input.Custom.GetPoint()
    if message: gp.SetCommandPrompt(message)
    gp.Constrain(curve, False)
    gp.Get()
    if gp.CommandResult()!=Rhino.Commands.Result.Success:
        return scriptcontext.errorhandler()
    pt = gp.Point()
    gp.Dispose()
    return pt