@p1r4t3b0y wrote:
Hi everybody,
This discussion is a continuation of this one from yesterday.
I’m currently trying to translate/port @dave_stasiuk’s script, recommended yesterday by @HS_Kim here, from Visual Basic to Python, because I need it as part of a more elaborate script.However, I don’t know much about VB. I’ve done a rough translation, but something is askew. The Python component doesn’t throw an error per se, however the output isn’t correct. In other words, it doesn’t correspond to what the VB component outputs.
The script is basically about converting grid lines to cells, like so:
My Python script
import Rhino.Geometry as rg import Grasshopper as gh from Grasshopper.Kernel.Data import GH_Path import math tol = 0.01 # model tolerance # Shatter all the input curves by intersecting them with each other Crvs = [] # new list of curves for CStart in range(len(C)): T = [] # new list of floats for CCut in range(len(C)): if CStart != CCut: CI = rg.Intersect.Intersection.CurveCurve(C[CStart], C[CCut], tol, tol) for IE in CI: T.append(IE.ParameterA) CShattered = C[CStart].Split(T) Crvs.extend(CShattered) # Set your "half-curce" lists Vtc = [] # new list of point3d; all unique vertices HC = [] # new list of curves; half-curves HCI = [] # new list of ints; half-curve indices HCO = [] # new list of ints; half-curve opposites HCN = [] # new list of ints; next index for each half-curve HCV = [] # new list of ints; half-curve vertex HCF = [] # new list of ints; half-curve face HCPln = [] # new list of planes; half-curve planes HCK = [] # new list of booleans; flag if half-curve needs to be killed (if either starts or ends hanging) F = gh.DataTree[object]() # datatree of curves; for faces VOut = gh.DataTree[object]() # datatree of ints; for outgoing half_curves from each vertex for Crv in Crvs: # cycle through each curve for CRun in range(0, 3, 2): # create two half-curves: first in one direction, and then the other... HC.append(Crv) HCI.append(len(HCI)) HCO.append(len(HCI)-CRun) # a little index trick HCN.append(-1) HCF.append(-1) HCK.append(False) VtcSet = -1 for VtxCheck in range(len(Vtc)): if Vtc[VtxCheck].DistanceTo(Crv.PointAtStart) < tol: VtcSet = VtxCheck # get the vertex index, if it already exists break if VtcSet > -1: HCV.append(VtcSet) # if the vertex already exists, set the half-curve vertex VOut.Add(HCI[-1], GH_Path(VtcSet)) # add the new half-curve index to the list of outgoing half-curves associates with the vertex else: HCV.append(len(Vtc)) # if the vertex doesn't already exists, add a new vertex index VOut.Add(HCI[-1], GH_Path(len(Vtc))) # add the new half-curve index to the list of outgoing half-curves associates with the vertex Vtc.append(Crv.PointAtStart) # add the new vertex to the vertex list # Create, align and add the plane to be used for sequencing half-curves AddPlane = rg.Plane(Vtc[HCV[-1]], P.ZAxis) AddPlane.Rotate(rg.Vector3d.VectorAngle(AddPlane.XAxis, Crv.TangentAtStart, AddPlane), AddPlane.ZAxis) HCPln.append(AddPlane) Crv.Reverse # reverse the cure for creating the opposite half-curve in the second part of the loop # For each vertex that has only one outgoing half-curve, kill the half-curve and its opposite for Pth in VOut.Paths: if VOut.Branch(Pth).Count == 1: HCK[VOut.Branch(Pth)(0)] = True HCK[HCO[VOut.Branch(Pth)(0)]] = True # Find the "next" half-curve for each starting half-curve by identifiying the outgoing half-curve from the end vertex # that presents the smallest angle by calculating its plane's x-axis angle from the starting half_curves's opposite plane for HCIdx in HCI: PlaneUse = HCPln[HCO[HCIdx]] MinIdx = -1 MinAngle = 2 * math.pi for HCOut in VOut.Branch(HCV[HCO[HCIdx]]): if HCOut != HCO[HCIdx] and HCK[HCIdx] == False and HCK[HCOut] == False: AngleTest = rg.Vector3d.VectorAngle(PlaneUse.XAxis, HCPln[HCOut].XAxis, PlaneUse) if AngleTest < MinAngle: MinIdx = HCOut MinAngle = AngleTest HCN[HCIdx] = MinIdx # Sequencing half-curves into faces by running along "next" half-curves in order until the starting half-curve is returned to FaceEdges = [] # list of ints DeleteEdges = [] # list of ints # Cycle through each half-curve for HCIdx in HCI: EmExit = 0 if HCF[HCIdx] == -1: # if it hasn't yet been assigned to a EdgeCounter = 1 FaceIdx = F.Paths.Count CurrentIdx = HCIdx F.Add(HC[CurrentIdx], GH_Path(FaceIdx)) HCF[CurrentIdx] = FaceIdx while True: if HCN[CurrentIdx] == -1: # if sequence half-curve has no next curve assigned, then the face is invalid DeleteEdges.append(FaceIdx) # and will be added to the delete list break CurrentIdx = HCN[CurrentIdx] F.Add(HC[CurrentIdx], GH_Path(FaceIdx)) EdgeCounter += 1 HCF[CurrentIdx] = FaceIdx if HCN[CurrentIdx] == HCIdx: # exit once the starting hflcruve is reached again break EmExit += 1 if EmExit == len(Crvs)-1: # energency exit prevents infinite loops break FaceEdges.append(EdgeCounter) # Find the perimeter by counting edges... it's possible that an interior face might have the most edges # so this could easily be approved upon Perim = -1 PerimCount = -1 for FE in range(len(FaceEdges)): if FaceEdges[FE] > PerimCount: Perim = FE PerimCount = FaceEdges[FE] DeleteEdges.append(Perim) NewPath = 0 OutputFaces = gh.DataTree[object]() # Only output the faces that haven't been identified as either the perimeter of open for Pth in F.Paths: if not Pth.Indices[0] in DeleteEdges: OutputFaces.AddRange(F.Branch(Pth), GH_Path(NewPath)) NewPath += 1 a = OutputFaces
Dave’s VB script:
'Start by Shattering all of your input curves by intersecting them with each other Dim Crvs As New List(Of Curve) For CStart As Int32 = 0 To C.Count - 1 Dim T As New List(Of Double) For CCut As Int32 = 0 To C.Count - 1 If CStart <> CCut Then Dim CI As Intersect.CurveIntersections = Intersect.Intersection.CurveCurve(C(CStart), C(CCut), RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, RhinoDoc.ActiveDoc.ModelAbsoluteTolerance) For Each IE As Intersect.IntersectionEvent In CI T.Add(IE.ParameterA) Next End If Next Dim CShattered() As Curve = C(CStart).Split(T) Crvs.AddRange(CShattered) Next 'Set your "half-curve" lists Dim Vtc As New List(Of Point3d) 'all unique vertices Dim HC As New List(Of Curve) 'list of half-curves Dim HCI As New List(Of Int32) 'half curve indices Dim HCO As New List(Of Int32) 'half curve opposites Dim HCN As New List(Of Int32) 'next index for each half-curve Dim HCV As New List(Of Int32) 'half-curve vertex Dim HCF As New List(Of Int32) 'half-curve face Dim HCPln As New List(Of Plane) 'half-curve plane Dim HCK As New List(Of Boolean) 'flag if a half-curve needs to be killed (if it either starts or ends hanging) Dim F As New DataTree(Of Curve) 'data tree for faces Dim VOut As New DataTree(Of Int32) 'data tree of outgoing half-curves from each vertex For Each Crv As Curve In Crvs 'cycle through each curve For CRun As Int32 = 0 To 2 Step 2 'create two half-curves: first in one direction, and then the other... HC.Add(Crv) HCI.Add(HCI.Count) HCO.Add(HCI.Count - Crun) 'a little index trick HCN.Add(-1) HCF.Add(-1) HCK.Add(False) Dim VtcSet As Int32 = -1 For VtxCheck As Int32 = 0 To Vtc.Count - 1 If Vtc(VtxCheck).DistanceTo(Crv.PointAtStart) < RhinoDoc.ActiveDoc.ModelAbsoluteTolerance Then VtcSet = VtxCheck 'get the vertex index, if it already exists Exit For End If Next If VtcSet > -1 Then HCV.Add(VtcSet) 'If the vertex already exists, set the half-curve vertex VOut.Add(HCI.Last, New GH_Path(VtcSet)) 'add the new half-curve index to the list of outgoing half-curves associated with the vertex Else HCV.Add(Vtc.Count) 'if the vertex doesn't already exist, add a new vertex index VOut.Add(HCI.Last, New GH_Path(Vtc.Count)) 'add the new half-curve index to the list of outgoing half-curves associated with the vertex Vtc.Add(Crv.PointAtStart) 'add the new vertex to the vertex list End If 'create, align and add the plane to be used for sequencing half-curves Dim AddPlane As New Plane(Vtc(HCV.Last), P.ZAxis) AddPlane.Rotate(Vector3d.VectorAngle(AddPlane.XAxis, Crv.TangentAtStart, AddPlane), AddPlane.ZAxis) HCPln.Add(AddPlane) Crv.Reverse 'reverse the curve for creating the opposite half-curve in the second part of the loop Next Next 'For each Vertex that has only one outgoing half-curve, kill the half-curve and its opposite For Each Pth As GH_Path In VOut.Paths If VOut.Branch(Pth).Count = 1 Then HCK(VOut.Branch(Pth)(0)) = True HCK(HCO(VOut.Branch(Pth)(0))) = True End If Next 'Find the "next" half-curve for each starting half curve by identifying the outgoing half-curve from the end vertex 'that presents the smallest angle by calculating its plane's x-axis angle from x-axis of the starting half-curve's opposite plane For Each HCIdx As Int32 In HCI Dim PlaneUse As Plane = HCPln(HCO(HCIdx)) Dim MinIdx As int32 = -1 Dim MinAngle As Double = 2 * Math.PI For Each HCOut As Int32 In VOut.Branch(HCV(HCO(HCIdx))) If HCOut <> HCO(HCIdx) And HCK(HCIdx) = False And HCK(HCOut) = False Dim AngleTest As Double = Vector3d.VectorAngle(PlaneUse.XAxis, HCPln(HCOut).XAxis, PlaneUse) If AngleTest < MinAngle Then MinIdx = HCOut MinAngle = AngleTest End If End If Next HCN(HCIdx) = MinIdx Next 'Sequence half-curves into faces by running along "next" half-curves in order until the starting half-curve is returned to Dim FaceEdges As New List(Of Int32) Dim DeleteEdges As New List(Of Int32) 'cycle through each half-curve For Each HCIdx As Int32 In HCI Dim EmExit As Int32 = 0 If HCF(HCIdx) = -1 Then 'if it hasn't yet been assigned to a Dim EdgeCounter As Int32 = 1 Dim FaceIdx as Int32 = F.Paths.Count Dim CurrentIdx As Int32 = HCIdx F.Add(HC(CurrentIdx), New GH_Path(FaceIdx)) HCF(CurrentIdx) = FaceIdx Do If HCN(CurrentIdx) = -1 Then 'if sequence half-curve has no next curve assigned, then the face is invalid DeleteEdges.Add(FaceIdx) 'and will be added to the delete list Exit Do End If CurrentIdx = HCN(CurrentIdx) F.Add(HC(CurrentIdx), New GH_Path(FaceIdx)) EdgeCounter += 1 HCF(CurrentIdx) = FaceIdx If HCN(CurrentIdx) = HCIdx Then Exit Do 'exit once the starting half-curve is reached again EmExit += 1 If EmExit = Crvs.Count - 1 Then Exit Do 'emergency exit prevents infinite loops Loop FaceEdges.Add(EdgeCounter) End If Next 'Find the perimeter by counting edges...it's possible that an interior face might have the most edges 'so this could easily be improved upon Dim Perim As Int32 = -1 Dim PerimCount As Int32 = -1 For FE As Int32 = 0 To FaceEdges.Count - 1 If FaceEdges(FE) > PerimCount Then Perim = FE PerimCount = FaceEdges(FE) End If Next DeleteEdges.Add(Perim) Dim NewPath As Int32 = 0 Dim OutputFaces As New DataTree(Of Curve) 'only output those faces that haven't been identified as either the perimeter or open For Each Pth As GH_Path In F.Paths If DeleteEdges.Contains(Pth.Indices(0)) = False Then OutputFaces.AddRange(F.Branch(Pth), New GH_Path(NewPath)) NewPath += 1 End If Next CN = OutputFaces
If you visit this thread by any chance, @dave_stasiuk, could you please briefly explain the logic behind the whole “half-curve” concept? I don’t get it! Thanks.
Here’s the file containing both scripts:
lines_to_grid_cells_2.gh (19.8 KB)Thanks!
Posts: 5
Participants: 3