Help: Rhino.Geometry.HiddenLineDrawing.Compute viewport question

Hi @stevebaer or @GregArden
I am working on a script to automate some make2d stuff of blocks and I don’t understand how viewports work in this regard.

In ordinary Make2D we can choose Cplane and this is what I am after, but in Rhino Common it seems to me that I have to define what viewport to use, but the resulting geometry doesn’t end up in a predictable place. (if I move my camera a bit then the 2D lines moves to another location, and this just seems very strange to me, so I presume I do something wrong)

This is part of the code I am working on now cleaning up now (as a version 1.2 of what I have working)

Just make a block of a box or something with insertpoint = w(0,0,0), then use top view and run the script.
I would expect the 2D result to end up underneath the geometry of the block, but it ends up somewhere unpredicable. Now pan the view a bit and run the script again, now the result ends up somewhere else… Why is that?

import rhinoscriptsyntax as rs
import Rhino
import scriptcontext as sc

def make2D_of_objects(object_ids):
    tolerance_for_2d = 0.002
    # Get the active view
    rs.CurrentView("Top")
    view = sc.doc.Views.ActiveView
    viewport = view.ActiveViewport
    
    ###########################################################################
    # Process all of the objects
    ###########################################################################
    object_geometries = []
    for obj in object_ids:
        object_geometry = obj.Geometry
        # Check meshes and repair if it is
        if rs.IsMesh(object_geometry):
            object_geometry.Faces.RemoveZeroAreaFaces(0)
            object_geometry.Weld(0.0524) # = 35 degrees
        
        object_geometries.append(object_geometry)
    
    ###########################################################################
    # Create and define hidden line drawing parameters
    ###########################################################################
    parameters = Rhino.Geometry.HiddenLineDrawingParameters()
    parameters.AbsoluteTolerance = tolerance_for_2d
    parameters.Flatten = True
    parameters.IncludeHiddenCurves = False
    parameters.IncludeTangentEdges = False
    parameters.IncludeTangentSeams = False
    parameters.SetViewport(viewport)
    # Add geometry to parameters
    for object_geometry in object_geometries:
        parameters.AddGeometry(object_geometry, None)
    
    ###########################################################################
    # Create the hidden line drawing geometry
    ###########################################################################
    hld = Rhino.Geometry.HiddenLineDrawing.Compute(parameters, True)
    if not hld:
        return False
    
    ###########################################################################
    # Process the result
    ###########################################################################
    lines=[]
    for hld_curve in hld.Segments:
            if hld_curve.SegmentVisibility == Rhino.Geometry.HiddenLineDrawingSegment.Visibility.Visible: 
                # Copy the curve, transform and add to document
                curve = hld_curve.CurveGeometry.DuplicateCurve()
                if not curve.IsShort(0.01):
                    lines.append(curve)
        
    # Join curves
    joined_curves = Rhino.Geometry.Curve.JoinCurves(lines)
    result = []
    for joined_curve in joined_curves:
        result.append(sc.doc.Objects.AddCurve(joined_curve))
    if len(result) == 0:
        return False
    
    return result

object_id = rs.GetObject()
block_objects = rs.BlockObjects(rs.BlockInstanceName(object_id))

objects=[]
for object in block_objects:
    objects.append(sc.doc.Objects.Find(object))

#print objects

make2D_of_objects(objects)

PS! I found that HiddenLineDrawing really doesn’t like bad meshes, so I added a fix for that. It would be nice if the fix could be incorperated.

@rajaa - is this something you can help with?

To be super clear, what I need is to get a way to control the outcome of HiddenLineDrawing so it is in the correct XY position of the geometry i make 2d of.

(I gather the instance xform and reapply that on the calculated geometry in the main script, so you don’t need to cover that part)

Thanks

It is nice that you are fixing the mesh in your sample. I will run this by @GregArden to see if he advises that we do a preprocessing of objects before passing them to HLD.

As for your questions, you will need to do some work to place your drawing in a consistent location.
Instead of taking the current active view, it will help to specify consistent plane, perhaps relative to your objects bounding box. Try something like this:

    {
    ...
    //Find bounding box of objects and adjust the projection plane origin to the center of objs bbox
    var bbox = RoughBoundingBox(obj_refs);
    Plane cplane = view.ActiveViewport.ConstructionPlane();
    ViewportInfo plan_view = GetPlanView(cplane, bbox); //see below

    //use the "plan_view " in the HLD compute
    ...
    }

    // Get the viewport for a CPlane plan view
    // Set the view frustum to loosely contain the world bounding box
    public static ViewportInfo GetPlanView(Plane cplane, BoundingBox bbox)
    {
      Point3d center = bbox.Center;
      double radius = bbox.Diagonal.Length / 2.0;
      center += 2.0 * radius * cplane.Normal;

      ViewportInfo vp = new ViewportInfo();
      vp.ChangeToParallelProjection(false);
      vp.SetCameraLocation(center);
      vp.SetCameraDirection(-cplane.Normal);
      vp.SetCameraUp(cplane.YAxis);
      vp.SetFrustum(-radius, radius, -radius, radius, radius, 3 * radius);
      return vp;
    }