| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | __title__ = "FreeCAD OpenSCAD Workbench - Parametric Features" |
| | __author__ = "Sebastian Hoogen" |
| | __url__ = ["https://www.freecad.org"] |
| |
|
| | try: |
| | long |
| | except NameError: |
| | long = int |
| |
|
| | ''' |
| | This Script includes python Features to represent OpenSCAD Operations |
| | ''' |
| |
|
| |
|
| | class ViewProviderTree: |
| | "A generic View Provider for Elements with Children" |
| |
|
| | def __init__(self, obj): |
| | obj.Proxy = self |
| | self.Object = obj.Object |
| |
|
| | def attach(self, obj): |
| | self.Object = obj.Object |
| | return |
| |
|
| | def updateData(self, fp, prop): |
| | return |
| |
|
| | def getDisplayModes(self,obj): |
| | modes=[] |
| | return modes |
| |
|
| | def setDisplayMode(self,mode): |
| | return mode |
| |
|
| | def onChanged(self, vp, prop): |
| | return |
| |
|
| | def dumps(self): |
| | |
| | return None |
| |
|
| | def loads(self,state): |
| | if state is not None: |
| | import FreeCAD |
| | doc = FreeCAD.ActiveDocument |
| | self.Object = doc.getObject(state['ObjectName']) |
| |
|
| | def claimChildren(self): |
| | objs = [] |
| | if hasattr(self.Object.Proxy,"Base"): |
| | objs.append(self.Object.Proxy.Base) |
| | if hasattr(self.Object,"Base"): |
| | objs.append(self.Object.Base) |
| | if hasattr(self.Object,"Objects"): |
| | objs.extend(self.Object.Objects) |
| | if hasattr(self.Object,"Components"): |
| | objs.extend(self.Object.Components) |
| | if hasattr(self.Object,"Children"): |
| | objs.extend(self.Object.Children) |
| |
|
| | return objs |
| |
|
| | def getIcon(self): |
| | import OpenSCAD_rc |
| | if isinstance(self.Object.Proxy,RefineShape): |
| | return(":/icons/OpenSCAD_RefineShapeFeature.svg") |
| | if isinstance(self.Object.Proxy,IncreaseTolerance): |
| | return(":/icons/OpenSCAD_IncreaseToleranceFeature.svg") |
| | if isinstance(self.Object.Proxy,MatrixTransform): |
| | return """/* XPM */ |
| | static char * matrix_xpm[] = { |
| | "16 16 3 1", |
| | " c #0079FF", |
| | ". c #FFFFFF", |
| | "+ c #000000", |
| | " ......... .", |
| | " ............. .", |
| | " . . . . . .", |
| | " . . . . . .", |
| | " ............. .", |
| | " . . . . . .", |
| | " . . . . . .", |
| | " ............. .", |
| | " . . . . . .", |
| | " . . . . . .", |
| | " ............. .", |
| | " ...........+. .", |
| | " ..+..+..+..+. .", |
| | " ............. .", |
| | " ......... .", |
| | "................"};""" |
| | else: |
| | return """/* XPM */ |
| | static char * openscadlogo_xpm[] = { |
| | "16 16 33 1", |
| | " c None", |
| | ". c #61320B", |
| | "+ c #5D420B", |
| | "@ c #4F4C09", |
| | "# c #564930", |
| | "$ c #754513", |
| | "% c #815106", |
| | "& c #666509", |
| | "* c #875F55", |
| | "= c #6E7000", |
| | "- c #756A53", |
| | "; c #717037", |
| | "> c #946637", |
| | ", c #92710E", |
| | "' c #797A0A", |
| | ") c #7C7720", |
| | "! c #8A8603", |
| | "~ c #88886F", |
| | "{ c #AF8181", |
| | "] c #999908", |
| | "^ c #BB8D8D", |
| | "/ c #AAAA00", |
| | "( c #A9A880", |
| | "_ c #B5B419", |
| | ": c #C1A9A9", |
| | "< c #B1B19A", |
| | "[ c #BEBE00", |
| | "} c #B9B8B4", |
| | "| c #CACC00", |
| | "1 c #D4D4BC", |
| | "2 c #DBD2D0", |
| | "3 c #EEEEED", |
| | "4 c #FDFFFC", |
| | "4444444444444444", |
| | "4444443113444444", |
| | "4444<;']]!;<^^24", |
| | "444(&@!]]]=&#^{3", |
| | "44<']')@++)!&*{^", |
| | "44)]/[|//[/]'@{{", |
| | "42=/_|||||[]!&*{", |
| | "4(&][|||||[/'@#}", |
| | "3-..,|||||[)&&~4", |
| | "^*$%.!|||[!+/](4", |
| | "^{%%%._[[_&/[_14", |
| | ":{>%%.!//])_[_44", |
| | "2{{%%+!]!!)]]344", |
| | "4:{{#@&=&&@#3444", |
| | "44224}~--~}44444", |
| | "4444444444444444"}; |
| | """ |
| |
|
| |
|
| | class OpenSCADPlaceholder: |
| | def __init__(self,obj,children=None,arguments=None): |
| | obj.addProperty("App::PropertyLinkList",'Children','OpenSCAD',"Base Objects", locked=True) |
| | obj.addProperty("App::PropertyString",'Arguments','OpenSCAD',"Arguments", locked=True) |
| | obj.Proxy = self |
| | if children: |
| | obj.Children = children |
| | if arguments: |
| | obj.Arguments = arguments |
| |
|
| | def execute(self,fp): |
| | import Part |
| | fp.Shape = Part.Compound([]) |
| |
|
| |
|
| | class Resize: |
| | def __init__(self,obj,target,vector): |
| | import FreeCAD |
| | |
| | self.Target = target |
| | self.Vector = vector |
| | |
| | |
| | obj.addProperty("Part::PropertyPartShape","Shape","Resize", "Shape of the Resize", locked=True) |
| | obj.addProperty("App::PropertyVector","Vector","Resize", |
| | " Resize Vector", locked=True).Vector = FreeCAD.Vector(vector) |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | import FreeCAD |
| | mat = FreeCAD.Matrix() |
| | mat.A11 = self.Vector[0] |
| | mat.A22 = self.Vector[1] |
| | mat.A33 = self.Vector[2] |
| | fp.Shape = self.Target.Shape.transformGeometry(mat) |
| |
|
| | def dumps(self): |
| | return None |
| |
|
| | def loads(self,state): |
| | return None |
| |
|
| |
|
| | class MatrixTransform: |
| | def __init__(self, obj,matrix=None,child=None): |
| | obj.addProperty("App::PropertyLink","Base","Base", |
| | "The base object that must be tranfsformed", locked=True) |
| | obj.addProperty("App::PropertyMatrix","Matrix","Matrix", "Transformation Matrix", locked=True) |
| | obj.Proxy = self |
| | obj.Matrix = matrix |
| | obj.Base = child |
| |
|
| | def onChanged(self, fp, prop): |
| | "Do something when a property has changed" |
| | pass |
| |
|
| | def updateProperty(self, fp, prop, value): |
| | epsilon = 0.0001 |
| | if abs(getattr(fp, prop) - value) > epsilon: |
| | setattr(fp, prop, value) |
| |
|
| | def execute(self, fp): |
| | if fp.Matrix and fp.Base: |
| | sh = fp.Base.Shape |
| | m = sh.Placement.toMatrix().multiply(fp.Matrix) |
| | fp.Shape = sh.transformGeometry(m) |
| | |
| | |
| |
|
| |
|
| | class ImportObject: |
| | def __init__(self, obj,child=None): |
| | obj.addProperty("App::PropertyLink", "Base", "Base", |
| | "The base object that must be tranfsformed", locked=True) |
| | obj.Proxy = self |
| | obj.Base = child |
| |
|
| | def onChanged(self, fp, prop): |
| | "Do something when a property has changed" |
| | pass |
| |
|
| | def execute(self, fp): |
| | pass |
| | |
| | |
| |
|
| |
|
| | class RefineShape: |
| | '''return a refined shape''' |
| | def __init__(self, obj, child=None): |
| | obj.addProperty("App::PropertyLink", "Base", "Base", |
| | "The base object that must be refined", locked=True) |
| | obj.Proxy = self |
| | obj.Base = child |
| |
|
| | def onChanged(self, fp, prop): |
| | "Do something when a property has changed" |
| | pass |
| |
|
| | def execute(self, fp): |
| | if fp.Base and fp.Base.Shape.isValid(): |
| | import OpenSCADUtils |
| | sh = fp.Base.Shape.removeSplitter() |
| | fp.Shape = OpenSCADUtils.applyPlacement(sh) |
| |
|
| | class IncreaseTolerance: |
| | '''increase the tolerance of every vertex |
| | in the current implementation its' placement is linked''' |
| | def __init__(self,obj,child,tolerance=0): |
| | obj.addProperty("App::PropertyLink", "Base", "Base", |
| | "The base object that wire must be extracted", locked=True) |
| | obj.addProperty("App::PropertyDistance","Vertex","Tolerance","Vertexes tolerance (0 default)", locked=True) |
| | obj.addProperty("App::PropertyDistance","Edge","Tolerance","Edges tolerance (0 default)", locked=True) |
| | obj.addProperty("App::PropertyDistance","Face","Tolerance","Faces tolerance (0 default)", locked=True) |
| | obj.Base = child |
| | obj.Vertex = tolerance |
| | obj.Edge = tolerance |
| | obj.Face = tolerance |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | if fp.Base: |
| | sh=fp.Base.Shape.copy() |
| | |
| | if hasattr(fp, "Tolerance") and fp.Proxy.__module__ == "OpenSCADFeatures": |
| | for vertex in sh.Vertexes: |
| | vertex.Tolerance = max(vertex.Tolerance,fp.Tolerance.Value) |
| | |
| | else: |
| | for vertex in sh.Vertexes: |
| | vertex.Tolerance = max(vertex.Tolerance, fp.Vertex.Value) |
| | for edge in sh.Edges: |
| | edge.Tolerance = max(edge.Tolerance, fp.Edge.Value) |
| | for face in sh.Faces: |
| | face.Tolerance = max(face.Tolerance, fp.Face.Value) |
| |
|
| | fp.Shape = sh |
| | fp.Placement = sh.Placement |
| |
|
| |
|
| | class GetWire: |
| | '''return the first wire from a given shape''' |
| | def __init__(self, obj, child=None): |
| | obj.addProperty("App::PropertyLink","Base","Base", |
| | "The base object that wire must be extracted", locked=True) |
| | obj.Proxy = self |
| | obj.Base = child |
| |
|
| | def onChanged(self, fp, prop): |
| | "Do something when a property has changed" |
| | pass |
| |
|
| | def execute(self, fp): |
| | if fp.Base: |
| | import Part |
| | |
| | fp.Shape=Part.Wire(fp.Base.Shape.Wires[0]) |
| | |
| |
|
| | class Frustum: |
| | def __init__(self, obj,r1=1,r2=2,n=3,h=4): |
| | obj.addProperty("App::PropertyInteger","FacesNumber","Base","Number of faces", locked=True) |
| | obj.addProperty("App::PropertyDistance","Radius1","Base","Radius of lower the inscribed control circle", locked=True) |
| | obj.addProperty("App::PropertyDistance","Radius2","Base","Radius of upper the inscribed control circle", locked=True) |
| | obj.addProperty("App::PropertyDistance","Height","Base","Height of the Frustum", locked=True) |
| |
|
| | obj.FacesNumber = n |
| | obj.Radius1 = r1 |
| | obj.Radius2= r2 |
| | obj.Height= h |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | if all((fp.Radius1,fp.Radius2,fp.FacesNumber,fp.Height)): |
| | import math |
| | import FreeCAD |
| | import Part |
| | |
| | plm = fp.Placement |
| | wires = [] |
| | faces = [] |
| | for ir,r in enumerate((fp.Radius1,fp.Radius2)): |
| | angle = (math.pi*2)/fp.FacesNumber |
| | pts = [FreeCAD.Vector(r.Value,0,ir*fp.Height.Value)] |
| | for i in range(fp.FacesNumber-1): |
| | ang = (i+1)*angle |
| | pts.append(FreeCAD.Vector(r.Value*math.cos(ang),\ |
| | r.Value*math.sin(ang),ir*fp.Height.Value)) |
| | pts.append(pts[0]) |
| | shape = Part.makePolygon(pts) |
| | face = Part.Face(shape) |
| | if ir == 0: |
| | face.reverse() |
| | wires.append(shape) |
| | faces.append(face) |
| | |
| | shellperi = Part.makeLoft(wires) |
| | shell = Part.Shell(shellperi.Faces+faces) |
| | fp.Shape = Part.Solid(shell) |
| | fp.Placement = plm |
| |
|
| | class Twist: |
| | def __init__(self, obj, child=None, h=1.0, angle=0.0, scale=[1.0,1.0]): |
| | import FreeCAD |
| | obj.addProperty("App::PropertyLink","Base","Base", |
| | "The base object that must be transformed", locked=True) |
| | obj.addProperty("App::PropertyQuantity","Angle","Base","Twist Angle", locked=True) |
| | obj.Angle = FreeCAD.Units.Angle |
| | obj.addProperty("App::PropertyDistance","Height","Base","Height of the Extrusion", locked=True) |
| | obj.addProperty("App::PropertyFloatList","Scale","Base","Scale to apply during the Extrusion", locked=True) |
| |
|
| | obj.Base = child |
| | obj.Angle = angle |
| | obj.Height = h |
| | obj.Scale = scale |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | import FreeCAD |
| | import Part |
| | import math |
| | import sys |
| | if fp.Base and fp.Height and fp.Base.Shape.isValid(): |
| | solids = [] |
| | for lower_face in fp.Base.Shape.Faces: |
| | upper_face = lower_face.copy() |
| | face_transform = FreeCAD.Matrix() |
| | face_transform.rotateZ(math.radians(fp.Angle.Value)) |
| | face_transform.scale(fp.Scale[0], fp.Scale[1], 1.0) |
| | face_transform.move(FreeCAD.Vector(0,0,fp.Height.Value)) |
| | upper_face.transformShape(face_transform, False, True) |
| |
|
| | spine = Part.makePolygon([(0,0,0),(0,0,fp.Height.Value)]) |
| | if fp.Angle.Value == 0.0: |
| | auxiliary_spine = None |
| | else: |
| | num_revolutions = abs(fp.Angle.Value)/360.0 |
| | pitch = fp.Height.Value / num_revolutions |
| | height = fp.Height.Value |
| | radius = 1.0 |
| | if fp.Angle.Value < 0.0: |
| | left_handed = True |
| | else: |
| | left_handed = False |
| |
|
| | auxiliary_spine = Part.makeHelix(pitch, height, radius, 0.0, left_handed) |
| |
|
| | faces = [lower_face,upper_face] |
| | for wire1,wire2 in zip(lower_face.Wires,upper_face.Wires): |
| | pipe_shell = Part.BRepOffsetAPI.MakePipeShell(spine) |
| | pipe_shell.setSpineSupport(spine) |
| | pipe_shell.add(wire1) |
| | pipe_shell.add(wire2) |
| | if auxiliary_spine: |
| | pipe_shell.setAuxiliarySpine(auxiliary_spine,True,0) |
| | assert(pipe_shell.isReady()) |
| | pipe_shell.build() |
| | faces.extend(pipe_shell.shape().Faces) |
| | try: |
| | fullshell = Part.Shell(faces) |
| | solid=Part.Solid(fullshell) |
| | if solid.Volume < 0: |
| | solid.reverse() |
| | assert(solid.Volume >= 0) |
| | solids.append(solid) |
| | except Part.OCCError: |
| | solids.append(Part.Compound(faces)) |
| | fp.Shape=Part.Compound(solids) |
| |
|
| |
|
| |
|
| | class PrismaticToroid: |
| | def __init__(self, obj,child=None,angle=360.0,n=3): |
| | obj.addProperty("App::PropertyLink","Base","Base", |
| | "The 2D face that will be swept", locked=True) |
| | obj.addProperty("App::PropertyAngle","Angle","Base","Angle to sweep through", locked=True) |
| | obj.addProperty("App::PropertyInteger","Segments","Base","Number of segments per 360° (OpenSCAD's \"$fn\")", locked=True) |
| |
|
| | obj.Base = child |
| | obj.Angle = angle |
| | obj.Segments = n |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | import FreeCAD |
| | import Part |
| | import math |
| | import sys |
| | if fp.Base and fp.Angle and fp.Segments and fp.Base.Shape.isValid(): |
| | solids = [] |
| | min_sweep_angle_per_segment = 360.0 / fp.Segments |
| | num_segments = math.floor(abs(fp.Angle) / min_sweep_angle_per_segment) |
| | num_ribs = num_segments + 1 |
| | sweep_angle_per_segment = fp.Angle / num_segments |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | for start_face in fp.Base.Shape.Faces: |
| | ribs = [] |
| | end_face = start_face |
| | for rib in range(num_ribs): |
| | angle = rib * sweep_angle_per_segment |
| | intermediate_face = start_face.copy() |
| | face_transform = FreeCAD.Matrix() |
| | face_transform.rotateY (math.radians (angle)) |
| | intermediate_face.transformShape (face_transform) |
| | if rib == num_ribs-1: |
| | end_face = intermediate_face |
| |
|
| | edges = [] |
| | for edge in intermediate_face.OuterWire.Edges: |
| | if edge.BoundBox.XMin != 0.0 or edge.BoundBox.XMax != 0.0: |
| | edges.append(edge) |
| |
|
| | ribs.append(Part.Wire(edges)) |
| |
|
| | faces = [] |
| | shell = Part.makeShellFromWires (ribs) |
| | for face in shell.Faces: |
| | faces.append(face) |
| |
|
| | if abs(fp.Angle) < 360.0 and faces: |
| | if fp.Angle > 0: |
| | faces.append(start_face.reversed()) |
| | faces.append(end_face) |
| | else: |
| | faces.append(start_face) |
| | faces.append(end_face.reversed()) |
| |
|
| | try: |
| | shell = Part.makeShell(faces) |
| | shell.sewShape() |
| | shell.fix(1e-7,1e-7,1e-7) |
| | clean_shell = shell.removeSplitter() |
| | solid = Part.makeSolid (clean_shell) |
| | if solid.Volume < 0: |
| | solid.reverse() |
| | solids.append(solid) |
| | except Part.OCCError: |
| | FreeCAD.Console.PrintWarning("Could not create solid: creating compound instead") |
| | solids.append(Part.Compound(faces)) |
| | fp.Shape = Part.Compound(solids) |
| |
|
| | class OffsetShape: |
| | def __init__(self, obj,child=None,offset=1.0): |
| | obj.addProperty("App::PropertyLink","Base","Base", |
| | "The base object that must be transformed", locked=True) |
| | obj.addProperty("App::PropertyDistance","Offset","Base","Offset outwards", locked=True) |
| |
|
| | obj.Base = child |
| | obj.Offset = offset |
| | obj.Proxy = self |
| |
|
| | def execute(self, fp): |
| | if fp.Base and fp.Offset: |
| | fp.Shape=fp.Base.Shape.makeOffsetShape(fp.Offset.Value,1e-6) |
| |
|
| | class CGALFeature: |
| | def __init__(self,obj,opname=None,children=None,arguments=None): |
| | obj.addProperty("App::PropertyLinkList",'Children','OpenSCAD',"Base Objects", locked=True) |
| | obj.addProperty("App::PropertyString",'Arguments','OpenSCAD',"Arguments", locked=True) |
| | obj.addProperty("App::PropertyString",'Operation','OpenSCAD',"Operation", locked=True) |
| | obj.Proxy = self |
| | if opname: |
| | obj.Operation = opname |
| | if children: |
| | obj.Children = children |
| | if arguments: |
| | obj.Arguments = arguments |
| |
|
| | def execute(self,fp): |
| | |
| | maxmeshpoints = None |
| | import Part |
| | import OpenSCAD.OpenSCADUtils |
| | shape = OpenSCAD.OpenSCADUtils.process_ObjectsViaOpenSCADShape(fp.Document,fp.Children,\ |
| | fp.Operation, maxmeshpoints=maxmeshpoints) |
| | if shape: |
| | fp.Shape = shape |
| | else: |
| | raise ValueError |
| |
|
| | def makeSurfaceVolume(filename): |
| | import FreeCAD |
| | import Part |
| | import sys |
| | coords = [] |
| | with open(filename) as f1: |
| | min_z = sys.float_info.max |
| | for line in f1.readlines(): |
| | sline = line.strip() |
| | if sline and not sline.startswith('#'): |
| | ycoord = len(coords) |
| | lcoords = [] |
| | for xcoord, num in enumerate(sline.split()): |
| | fnum = float(num) |
| | lcoords.append(FreeCAD.Vector(float(xcoord),float(ycoord),fnum)) |
| | min_z = min(fnum,min_z) |
| | coords.append(lcoords) |
| |
|
| | num_rows = len(coords) |
| | if num_rows == 0: |
| | FreeCAD.Console.PrintWarning(f"No data found in surface file {filename}") |
| | return None,0,0 |
| | num_cols = len(coords[0]) |
| |
|
| | |
| | |
| | |
| | faces = [] |
| | for row in range(num_rows - 1): |
| | for col in range(num_cols - 1): |
| | a = coords[row + 0][col + 0] |
| | b = coords[row + 0][col + 1] |
| | c = coords[row + 1][col + 1] |
| | d = coords[row + 1][col + 0] |
| | centroid = 0.25 * (a + b + c + d) |
| | ab = Part.makeLine(a,b) |
| | bc = Part.makeLine(b,c) |
| | cd = Part.makeLine(c,d) |
| | da = Part.makeLine(d,a) |
| |
|
| | diag_a = Part.makeLine(a, centroid) |
| | diag_b = Part.makeLine(b, centroid) |
| | diag_c = Part.makeLine(c, centroid) |
| | diag_d = Part.makeLine(d, centroid) |
| |
|
| | wire1 = Part.Wire([ab,diag_a,diag_b]) |
| | wire2 = Part.Wire([bc,diag_b,diag_c]) |
| | wire3 = Part.Wire([cd,diag_c,diag_d]) |
| | wire4 = Part.Wire([da,diag_d,diag_a]) |
| |
|
| | try: |
| | face = Part.Face(wire1) |
| | faces.append(face) |
| | face = Part.Face(wire2) |
| | faces.append(face) |
| | face = Part.Face(wire3) |
| | faces.append(face) |
| | face = Part.Face(wire4) |
| | faces.append(face) |
| | except Exception: |
| | FreeCAD.Console.PrintWarning("Failed to create the face from {},{},{},{}".format(coords[row + 0][col + 0],\ |
| | coords[row + 0][col + 1],coords[row + 1][col + 1],coords[row + 1][col + 0])) |
| |
|
| | last_row = num_rows - 1 |
| | last_col = num_cols - 1 |
| |
|
| | |
| | |
| | |
| | lines = [] |
| | corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) |
| | lines.append(Part.makeLine(corner1,coords[0][0])) |
| | for col in range(num_cols - 1): |
| | a = coords[0][col] |
| | b = coords[0][col + 1] |
| | lines.append(Part.makeLine(a, b)) |
| | corner2 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) |
| | lines.append(Part.makeLine(corner2,coords[0][last_col])) |
| | lines.append(Part.makeLine(corner1,corner2)) |
| | wire = Part.Wire(lines) |
| | face = Part.Face(wire) |
| | faces.append(face) |
| |
|
| | |
| | lines = [] |
| | corner1 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) |
| | lines.append(Part.makeLine(corner1,coords[last_row][0])) |
| | for col in range(num_cols - 1): |
| | a = coords[last_row][col] |
| | b = coords[last_row][col + 1] |
| | lines.append(Part.makeLine(a, b)) |
| | corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) |
| | lines.append(Part.makeLine(corner2,coords[last_row][last_col])) |
| | lines.append(Part.makeLine(corner1,corner2)) |
| | wire = Part.Wire(lines) |
| | face = Part.Face(wire) |
| | faces.append(face) |
| |
|
| | |
| | lines = [] |
| | corner1 = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) |
| | lines.append(Part.makeLine(corner1,coords[0][0])) |
| | for row in range(num_rows - 1): |
| | a = coords[row][0] |
| | b = coords[row + 1][0] |
| | lines.append(Part.makeLine(a, b)) |
| | corner2 = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) |
| | lines.append(Part.makeLine(corner2,coords[last_row][0])) |
| | lines.append(Part.makeLine(corner1,corner2)) |
| | wire = Part.Wire(lines) |
| | face = Part.Face(wire) |
| | faces.append(face) |
| |
|
| | |
| | lines = [] |
| | corner1 = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) |
| | lines.append(Part.makeLine(corner1,coords[0][last_col])) |
| | for row in range(num_rows - 1): |
| | a = coords[row][last_col] |
| | b = coords[row + 1][last_col] |
| | lines.append(Part.makeLine(a, b)) |
| | corner2 = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) |
| | lines.append(Part.makeLine(corner2,coords[last_row][last_col])) |
| | lines.append(Part.makeLine(corner1,corner2)) |
| | wire = Part.Wire(lines) |
| | face = Part.Face(wire) |
| | faces.append(face) |
| |
|
| | |
| | a = FreeCAD.Vector(coords[0][0].x, coords[0][0].y, min_z - 1) |
| | b = FreeCAD.Vector(coords[0][last_col].x, coords[0][last_col].y, min_z - 1) |
| | c = FreeCAD.Vector(coords[last_row][last_col].x, coords[last_row][last_col].y, min_z - 1) |
| | d = FreeCAD.Vector(coords[last_row][0].x, coords[last_row][0].y, min_z - 1) |
| | ab = Part.makeLine(a,b) |
| | bc = Part.makeLine(b,c) |
| | cd = Part.makeLine(c,d) |
| | da = Part.makeLine(d,a) |
| | wire = Part.Wire([ab,bc,cd,da]) |
| | face = Part.Face(wire) |
| | faces.append(face) |
| |
|
| | s = Part.Shell(faces) |
| | solid = Part.Solid(s) |
| | return solid,last_col,last_row |
| |
|