VB to Python

Hi I am trying to convert the VB code to Python, it is producing some output but totally incorrect.

The VB code is from this link:

Both codes are below, any help is appreciated. Thanks in advance.

  Private Sub RunScript(ByVal P As List(Of Point3d), ByRef M As Object) 
    If P Is Nothing Then Return
    If P.Count > 3 Then

      Dim ptsL As New List(Of point3d)
      ptsL.AddRange(P)
      Dim rnd As New random

      'create first mesh======================================================
      Dim msh As New mesh

      While msh.Vertices.Count < 4
        Dim ok As Boolean = True
        Dim addedIdx As Integer = rnd.Next(0, ptsL.Count - 1)
        'check if its not on line
        If msh.Vertices.Count = 2 Then
          ok = checkIfOnLine(msh.Vertices(0), msh.Vertices(1), ptsL(addedIdx))
        End If

        If ok = True Then
          msh.Vertices.Add(ptsL(addedIdx))
          ptsL.RemoveAt(addedIdx)
        End If
      End While

      msh.Faces.AddFace(0, 1, 2)
      msh.Faces.AddFace(1, 2, 3)
      msh.Faces.AddFace(2, 3, 0)
      msh.Faces.AddFace(3, 0, 1)

      msh.Vertices.CombineIdentical(True, True)
      msh.FaceNormals.ComputeFaceNormals
      msh.UnifyNormals
      msh.Normals.ComputeNormals
      '========================================================================

      While ptsL.count > 0

        Dim nextPtIdx As Integer = rnd.Next(0, ptsL.Count - 1)
        Dim nextPt As New Point3d(ptsL(nextPtIdx))

        'if inside then do nothing, else do mesh

        If (isPtInMesh(nextPt, msh)) = False Then
          Dim fList As New List(Of Integer)
          fList = seenFaces(nextPt, msh)
          fList.Sort
          For i As Integer = fList.Count - 1 To 0 Step -1
            msh.Faces.RemoveAt(fList(i))
          Next
          msh = createNewFaces(nextPt, msh)
        Else

        End If

        ptsL.RemoveAt(nextPtIdx)

      End While

      M = msh

    End If


  End Sub 

  '<Custom additional code> 

  Function checkIfOnLine(pt1 As point3d, pt2 As point3d, pttested As point3d) As Boolean
    Dim fine As Boolean = True

    Dim dist1 As Double = pttested.DistanceTo(pt1)
    Dim dist2 As Double = pttested.DistanceTo(pt2)
    Dim dist3 As Double = pt1.DistanceTo(pt2)
    If dist1 + dist2 > dist3 Then
      fine = True
    Else
      fine = False
    End If
    Return fine
  End Function

  Function IsPtInMesh(point As Point3d, ByVal mesh As Mesh) As Boolean
    mesh.FaceNormals.ComputeFaceNormals
    mesh.UnifyNormals
    mesh.Normals.ComputeNormals

    Dim box As BoundingBox = mesh.GetBoundingBox(True)
    If (Not box.Contains(point)) Then Return False

    Dim polyline As New Polyline()
    polyline.Add(point)
    polyline.Add(box.Max + New Vector3d(100, 100, 100))
    Dim x As Point3d() = Intersect.Intersection.MeshPolyline(mesh, New PolylineCurve(polyline), Nothing)

    If x Is Nothing Then Return False

    If x.length Mod 2 = 0 Then
      Return False
    Else
      Return True
    End If

  End Function

  Function seenFaces(ByVal point As point3d, ByVal mesh As mesh) As List(Of Integer)
    Dim sFaces As New List (Of Integer)

    For i As Integer = 0 To mesh.Faces.Count - 1 Step 1
      Dim actV As Vector3d = mesh.FaceNormals(i)
      Dim actFc As point3d = mesh.Faces.GetFaceCenter(i)
      Dim seeV As vector3d
      seeV = vec2Pts(point, actFc)

      If dotProduct(seeV, actV) < 0.001 Then
        sFaces.Add(i)
      End If

    Next
    Return sFaces

  End Function

  Function vec2Pts (pt1 As point3d, pt2 As point3d) As Vector3d
    Dim vec As New vector3d(pt2.X - pt1.X, pt2.y - pt1.y, pt2.z - pt1.z)
    Return vec
  End Function

  Function dotProduct (v1 As Vector3d, v2 As vector3d) As Double
    Dim dot As Double = (v2.X * v1.X) + (v2.y * v1.y) + (v2.z * v1.z)
    Return dot
  End Function

  Function createNewFaces (pt As point3d, mesh As mesh) As mesh

    Dim naked As New List (Of polyline)
    naked.AddRange(mesh.GetNakedEdges)
    Dim edges As New List(Of line)

    For i As Integer = 0 To naked.Count - 1 Step 1
      Dim actN As New Polyline
      actN = naked(i)
      edges.AddRange(actN.GetSegments)
    Next

    Dim newM As New mesh

    For i As Integer = 0 To edges.Count - 1 Step 1
      Dim newTriangle As New mesh
      Dim actE As line = edges(i)
      newTriangle.Vertices.Add(actE.From)
      newTriangle.Vertices.Add(actE.To)
      newTriangle.Vertices.Add(pt)
      newTriangle.Faces.AddFace(0, 1, 2)
      newM.Append(newTriangle)
    Next

    newM.Vertices.CombineIdentical(True, True)
    mesh.Append(newM)
    mesh.Vertices.CombineIdentical(True, True)
    mesh.FaceNormals.ComputeFaceNormals
    mesh.UnifyNormals
    mesh.Normals.ComputeNormals

    Return mesh

  End Function
  '</Custom additional code> 


import Rhino
import System
import System.Collections.Generic

def checkIfOnLine(pt1,pt2,pttested):
    dist1=pttested.DistanceTo(pt1)
    dist2=pttested.DistanceTo(pt2)
    dist3=pt1.DistanceTo(pt2)
    if dist1+dist2>dist3:
        fine=True
    else:
        fine=False
    return fine


def isPtInMesh(point,mesh):
    mesh.FaceNormals.ComputeFaceNormals()
    mesh.UnifyNormals()
    mesh.Normals.ComputeNormals()
    box=mesh.GetBoundingBox(True)
    if not box.Contains(point):
        return False
    polyline=Rhino.Geometry.Polyline()
    polyline.Add(point)
    polyline.Add(box.Max + Rhino.Geometry.Vector3d(100, 100, 100))
    x=Rhino.Geometry.Intersect.Intersection.MeshPolyline(mesh,Rhino.Geometry.PolylineCurve(polyline))
    if x==None:
        return False
    if len(x)%2==0:
        return False
    else:
        return True

def seenFaces(point,mesh):
    sFaces=System.Collections.Generic.List[int]()
    for i in range(0,mesh.Faces.Count - 1,1):
        actV = mesh.FaceNormals[i]
        actFc = mesh.Faces.GetFaceCenter(i)
        seeV = vec2Pts(point, actFc)
        if dotProduct(seeV, actV) < 0.001:
            sFaces.Add(i)
    return sFaces


def vec2Pts(pt1,pt2):
    vec=Rhino.Geometry.Vector3d(pt2.X - pt1.X, pt2.Y - pt1.Y, pt2.Z - pt1.Z)
    return vec

def dotProduct(v1,v2):
    dot=(v2.X * v1.X) + (v2.Y * v1.Y) + (v2.Z * v1.Z)
    return dot

def createNewFaces(pt,mesh):
    naked=System.Collections.Generic.List[object]()
    naked.AddRange(mesh.GetNakedEdges())
    edges=System.Collections.Generic.List[object]()
    for i in range(0,naked.Count - 1,1):
        actN=Rhino.Geometry.Polyline()
        actN=naked[i]
        edges.AddRange(actN.GetSegments())
    newM=Rhino.Geometry.Mesh()
    
    for i in range(0,edges.Count - 1,1):
        newTriangle=Rhino.Geometry.Mesh()
        actE=edges[i]
        newTriangle.Vertices.Add(actE.From)
        newTriangle.Vertices.Add(actE.To)
        newTriangle.Vertices.Add(pt)
        newTriangle.Faces.AddFace(0, 1, 2)
        newM.Append(newTriangle)
    newM.Vertices.CombineIdentical(True, True)
    mesh.Append(newM)
    mesh.Vertices.CombineIdentical(True, True)
    mesh.FaceNormals.ComputeFaceNormals()
    mesh.UnifyNormals()
    mesh.Normals.ComputeNormals()
    return mesh



if len(P)>3:
    ptsL=System.Collections.Generic.List[object]()
    ptsL.AddRange(P)
    msh=Rhino.Geometry.Mesh()
    rnd=System.Random()
    while msh.Vertices.Count < 4:
        ok=True
        addedIdx=rnd.Next(0,ptsL.Count-1)
        if msh.Vertices.Count == 2:
            ok=checkIfOnLine(msh.Vertices[0], msh.Vertices[1], ptsL[addedIdx])
        if ok:
            msh.Vertices.Add(ptsL[addedIdx])
            ptsL.RemoveAt(addedIdx)
    msh.Faces.AddFace(0, 1, 2)
    msh.Faces.AddFace(1, 2, 3)
    msh.Faces.AddFace(2, 3, 0)
    msh.Faces.AddFace(3, 0, 1)
    msh.Vertices.CombineIdentical(True, True)
    msh.FaceNormals.ComputeFaceNormals()
    msh.UnifyNormals()
    msh.Normals.ComputeNormals()
    while ptsL.Count > 0:
        nextPtIdx= rnd.Next(0, ptsL.Count - 1)
        nextPt=Rhino.Geometry.Point3d(ptsL[nextPtIdx])
        if not isPtInMesh(nextPt, msh):
            fList=System.Collections.Generic.List[int]()
            fList = seenFaces(nextPt, msh)
            fList.Sort
            for i in range(fList.Count - 1,0,-1):
                msh.Faces.RemoveAt(fList[i])
        else:
            pass
            msh=createNewFaces(nextPt, msh)
        ptsL.RemoveAt(nextPtIdx)
    M = msh

It’d help with debugging if you also upload a Grasshopper file that demonstrates the error.

On a sidenote, I’d highly recommend implementing MIConvexHull for computing fast, clean and stable 2D/3D convex hulls. I’ve been using that on several projects recently (including this one), where the standard Grasshopper convex hull solver would fail. Here’s a quick example that should work if you unzip the MIConvexHull.dll to the default Grasshopper libraries folder:


230425_ConvexHull3D_MIConvexHull_GHPython_00.gh (4.5 KB)
MIConvexHull.zip (15.9 KB)

2 Likes

I hear you, that’s also always a primary concern for me.

Anywho, you should probably still upload a Grasshopper file to debug :wink: