Skip to content

Commit

Permalink
More Refactoring and Bug Fixes. API Changes
Browse files Browse the repository at this point in the history
More Refactoring and Bug Fixes. API Changes (e.g. Face.AddInternalBoundary is not Face.AddInternalBoundaries
  • Loading branch information
wassimj committed Aug 13, 2022
1 parent 4d4602a commit 7c7e5d6
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 160 deletions.
6 changes: 2 additions & 4 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ def nodes_index():
("Topologic.WireSplit", "SvWireSplit"),
("Topologic.WireStar", "SvWireStar"),
("Topologic.WireTrapezoid", "SvWireTrapezoid"),
("Topologic.FaceAddFaceAsAperture", "SvFaceAddFaceAsAperture"),
("Topologic.FaceAddInternalBoundary", "SvFaceAddInternalBoundary"),
("Topologic.FaceAddInternalBoundaries", "SvFaceAddInternalBoundaries"),
("Topologic.FaceArea", "SvFaceArea"),
("Topologic.FaceBoundingFace", "SvFaceBoundingFace"),
("Topologic.FaceByEdges", "SvFaceByEdges"),
Expand Down Expand Up @@ -616,8 +615,7 @@ class NODEVIEW_MT_AddTPSubcategoryFace(bpy.types.Menu):
def draw(self, context):
layout = self.layout
layout_draw_categories(self.layout, self.bl_label, [
['SvFaceAddFaceAsAperture'],
['SvFaceAddInternalBoundary'],
['SvFaceAddInternalBoundaries'],
['SvFaceAngle'],
['SvFaceArea'],
['SvFaceBoundingFace'],
Expand Down
100 changes: 100 additions & 0 deletions nodes/Topologic/FaceAddInternalBoundaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import bpy
from bpy.props import IntProperty, FloatProperty, StringProperty, EnumProperty, BoolProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode

import topologic
from . import Replication

def isInside(ib, face, tolerance):
vertices = []
_ = ib.Vertices(None, vertices)
for vertex in vertices:
if topologic.FaceUtility.IsInside(face, vertex, tolerance) == False:
return False
return True

def processItem(item):
face, cluster = item
assert isinstance(face, topologic.Face), "FaceAddInternalBoundaries - Error: The host face input is not a Face"
if isinstance(cluster, topologic.Cluster):
wires = []
_ = cluster.Wires(None, wires)
elif isinstance(cluster, topologic.Wire):
wires = [cluster]
elif isinstance(cluster, list):
wires = [w for w in cluster if isinstance(w, topologic.Wire)]
else:
return face
faceeb = face.ExternalBoundary()
faceibList = []
_ = face.InternalBoundaries(faceibList)
for wire in wires:
faceibList.append(wire)
return topologic.Face.ByExternalInternalBoundaries(faceeb, faceibList)

replication = [("Default", "Default", "", 1),("Trim", "Trim", "", 2),("Iterate", "Iterate", "", 3),("Repeat", "Repeat", "", 4),("Interlace", "Interlace", "", 5)]

class SvFaceAddInternalBoundaries(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Topologic
Tooltip: Adds the input internal boundaries (Cluster) to the input Face
"""
bl_idname = 'SvFaceAddInternalBoundaries'
bl_label = 'Face.AddInternalBoundaries'
bl_icon = 'SELECT_DIFFERENCE'
Replication: EnumProperty(name="Replication", description="Replication", default="Default", items=replication, update=updateNode)

def sv_init(self, context):
self.inputs.new('SvStringsSocket', 'Face')
self.inputs.new('SvStringsSocket', 'Wires Cluster')
self.outputs.new('SvStringsSocket', 'Face')
self.width = 200
for socket in self.inputs:
if socket.prop_name != '':
socket.custom_draw = "draw_sockets"

def draw_sockets(self, socket, context, layout):
row = layout.row()
split = row.split(factor=0.5)
split.row().label(text=(socket.name or "Untitled") + f". {socket.objects_number or ''}")
split.row().prop(self, socket.prop_name, text="")

def draw_buttons(self, context, layout):
row = layout.row()
split = row.split(factor=0.5)
split.row().label(text="Replication")
split.row().prop(self, "Replication",text="")

def process(self):
if not any(socket.is_linked for socket in self.outputs):
return
inputs_nested = []
inputs_flat = []
for anInput in self.inputs:
inp = anInput.sv_get(deepcopy=True)
inputs_nested.append(inp)
inputs_flat.append(Replication.flatten(inp))
inputs_replicated = Replication.replicateInputs(inputs_flat, self.Replication)
outputs = []
for anInput in inputs_replicated:
outputs.append(processItem(anInput))
inputs_flat = []
for anInput in self.inputs:
inp = anInput.sv_get(deepcopy=True)
inputs_flat.append(Replication.flatten(inp))
if self.Replication == "Interlace":
outputs = Replication.re_interlace(outputs, inputs_flat)
else:
match_list = Replication.best_match(inputs_nested, inputs_flat, self.Replication)
outputs = Replication.unflatten(outputs, match_list)
if len(outputs) == 1:
if isinstance(outputs[0], list):
outputs = outputs[0]
self.outputs['Face'].sv_set(outputs)

def register():
bpy.utils.register_class(SvFaceAddInternalBoundaries)

def unregister():
bpy.utils.unregister_class(SvFaceAddInternalBoundaries)
166 changes: 47 additions & 119 deletions nodes/Topologic/FaceAddInternalBoundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,91 +4,7 @@
from sverchok.data_structure import updateNode

import topologic
import time

# From https://stackabuse.com/python-how-to-flatten-list-of-lists/
def flatten(element):
returnList = []
if isinstance(element, list) == True:
for anItem in element:
returnList = returnList + flatten(anItem)
else:
returnList = [element]
return returnList

def repeat(list):
maxLength = len(list[0])
for aSubList in list:
newLength = len(aSubList)
if newLength > maxLength:
maxLength = newLength
for anItem in list:
if (len(anItem) > 0):
itemToAppend = anItem[-1]
else:
itemToAppend = None
for i in range(len(anItem), maxLength):
anItem.append(itemToAppend)
return list

# From https://stackoverflow.com/questions/34432056/repeat-elements-of-list-between-each-other-until-we-reach-a-certain-length
def onestep(cur,y,base):
# one step of the iteration
if cur is not None:
y.append(cur)
base.append(cur)
else:
y.append(base[0]) # append is simplest, for now
base = base[1:]+[base[0]] # rotate
return base

def iterate(list):
maxLength = len(list[0])
returnList = []
for aSubList in list:
newLength = len(aSubList)
if newLength > maxLength:
maxLength = newLength
for anItem in list:
for i in range(len(anItem), maxLength):
anItem.append(None)
y=[]
base=[]
for cur in anItem:
base = onestep(cur,y,base)
returnList.append(y)
return returnList

def trim(list):
minLength = len(list[0])
returnList = []
for aSubList in list:
newLength = len(aSubList)
if newLength < minLength:
minLength = newLength
for anItem in list:
anItem = anItem[:minLength]
returnList.append(anItem)
return returnList

# Adapted from https://stackoverflow.com/questions/533905/get-the-cartesian-product-of-a-series-of-lists
def interlace(ar_list):
if not ar_list:
yield []
else:
for a in ar_list[0]:
for prod in interlace(ar_list[1:]):
yield [a,]+prod

def transposeList(l):
length = len(l[0])
returnList = []
for i in range(length):
tempRow = []
for j in range(len(l)):
tempRow.append(l[j][i])
returnList.append(tempRow)
return returnList
from . import Replication

def isInside(ib, face, tolerance):
vertices = []
Expand All @@ -99,67 +15,79 @@ def isInside(ib, face, tolerance):
return True

def processItem(item):
face = item[0]
ibList = item[1]
if isinstance(ibList, list) == False:
ibList = [ibList]
face, cluster = item
assert isinstance(face, topologic.Face), "FaceAddInternalBoundaries - Error: The host face input is not a Face"
assert isinstance(face, topologic.Cluster), "FaceAddInternalBoundaries - Error: The internal boundaries input is not a Cluster"
wires = []
_ = cluster.Wires(None, wires)
faceeb = face.ExternalBoundary()
faceibList = []
_ = face.InternalBoundaries(faceibList)
for ib in ibList:
faceibList.append(ib)
for wire in wires:
faceibList.append(wire)
return topologic.Face.ByExternalInternalBoundaries(faceeb, faceibList)

replication = [("Default", "Default", "", 1),("Trim", "Trim", "", 2),("Iterate", "Iterate", "", 3),("Repeat", "Repeat", "", 4),("Interlace", "Interlace", "", 5)]

class SvFaceAddInternalBoundary(bpy.types.Node, SverchCustomTreeNode):
class SvFaceAddInternalBoundaries(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Topologic
Tooltip: Adds the input internal boundary (Wire) to the input Face
Tooltip: Adds the input internal boundaries (Cluster) to the input Face
"""
bl_idname = 'SvFaceAddInternalBoundary'
bl_label = 'Face.AddInternalBoundary'
Replication: EnumProperty(name="Replication", description="Replication", default="Default", items=replication, update=updateNode)

def sv_init(self, context):
self.inputs.new('SvStringsSocket', 'Face')
self.inputs.new('SvStringsSocket', 'Wire')
self.inputs.new('SvStringsSocket', 'Wires Cluster')
self.outputs.new('SvStringsSocket', 'Face')
self.width = 175
for socket in self.inputs:
if socket.prop_name != '':
socket.custom_draw = "draw_sockets"

def draw_sockets(self, socket, context, layout):
row = layout.row()
split = row.split(factor=0.5)
split.row().label(text=(socket.name or "Untitled") + f". {socket.objects_number or ''}")
split.row().prop(self, socket.prop_name, text="")

def draw_buttons(self, context, layout):
layout.prop(self, "Replication",text="")
row = layout.row()
split = row.split(factor=0.5)
split.row().label(text="Replication")
split.row().prop(self, "Replication",text="")

def process(self):
start = time.time()
if not any(socket.is_linked for socket in self.outputs):
return
faceList = self.inputs['Face'].sv_get(deepcopy=True)
ibList = self.inputs['Wire'].sv_get(deepcopy=True)
faceList = flatten(faceList)
inputs = [faceList, ibList]
inputs_nested = []
inputs_flat = []
for anInput in self.inputs:
inp = anInput.sv_get(deepcopy=True)
inputs_nested.append(inp)
inputs_flat.append(Replication.flatten(inp))
inputs_replicated = Replication.replicateInputs(inputs_flat, self.Replication)
outputs = []
if ((self.Replication) == "Default"):
inputs = repeat(inputs)
inputs = transposeList(inputs)
elif ((self.Replication) == "Trim"):
inputs = trim(inputs)
inputs = transposeList(inputs)
elif ((self.Replication) == "Iterate"):
inputs = iterate(inputs)
inputs = transposeList(inputs)
elif ((self.Replication) == "Repeat"):
inputs = repeat(inputs)
inputs = transposeList(inputs)
elif ((self.Replication) == "Interlace"):
inputs = list(interlace(inputs))
for anInput in inputs:
for anInput in inputs_replicated:
outputs.append(processItem(anInput))
inputs_flat = []
for anInput in self.inputs:
inp = anInput.sv_get(deepcopy=True)
inputs_flat.append(Replication.flatten(inp))
if self.Replication == "Interlace":
outputs = Replication.re_interlace(outputs, inputs_flat)
else:
match_list = Replication.best_match(inputs_nested, inputs_flat, self.Replication)
outputs = Replication.unflatten(outputs, match_list)
if len(outputs) == 1:
if isinstance(outputs[0], list):
outputs = outputs[0]
self.outputs['Face'].sv_set(outputs)
end = time.time()
print("Face Add Internal Boundary Operation consumed "+str(round(end - start,4))+" seconds")

def register():
bpy.utils.register_class(SvFaceAddInternalBoundary)
bpy.utils.register_class(SvFaceAddInternalBoundaries)

def unregister():
bpy.utils.unregister_class(SvFaceAddInternalBoundary)
bpy.utils.unregister_class(SvFaceAddInternalBoundaries)

0 comments on commit 7c7e5d6

Please sign in to comment.