def sub_gimbal_freecad_construction(c, ai_bottom_angle, ai_top_angle): """ generate the the freecad-object gimbal """ # intermediate parameters z1 = c['base_thickness'] + c['bell_face_height'] + c['leg_length'] z2 = c['inter_axle_length'] # make the freecad-objects from bell_bagel_assembly and cross_cube i_bba = bell_bagel_assembly.bba() i_bba.apply_external_constraint(c) fc_bb_bottom = i_bba.get_fc_obj_3dconf('bell_bagel_assembly_conf1') fc_bb_top = fc_bb_bottom.copy() i_cross_cube = cross_cube.cross_cube() i_cross_cube.apply_external_constraint(cross_cube_constraint(c)) fc_cc = i_cross_cube.get_fc_obj_3dconf('cross_cube_assembly_with_rods_and_axles') # place fc_bb_bottom.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),90) fc_bb_top.rotate(Base.Vector(0,0,z1),Base.Vector(0,1,0),180) fc_bb_top.translate(Base.Vector(0,0,z2)) fc_cc.translate(Base.Vector(-1*c['cube_width']/2.0, -1*c['cube_width']/2.0, z1-(c['top_thickness'] + c['height_margin'] + c['axle_diameter']/2.0))) fc_cc.rotate(Base.Vector(0,0,0),Base.Vector(0,0,1),90) # apply the rotation fc_bb_top.rotate(Base.Vector(0,0,z1+z2),Base.Vector(0,1,0),ai_top_angle*180/math.pi) fc_top = Part.makeCompound([fc_bb_top, fc_cc]) fc_top.rotate(Base.Vector(0,0,z1),Base.Vector(1,0,0),ai_bottom_angle*180/math.pi) r_fc_gimbal = Part.makeCompound([fc_bb_bottom, fc_top]) return(r_fc_gimbal)
def execute(self,selfobj): tip = selfobj.Tip if len(tip) == 0: tip = selfobj.Group shapes = [] for obj in tip: if hasattr(obj, 'Shape'): shapes.append(obj.Shape) else: App.Console.PrintWarning(u"Object {obj} has no shape, skipped for making a compound.\n".format(obj= obj.Label)) result_shape = Part.Shape() opmode = selfobj.Operation if opmode == 'None': pass elif opmode == 'Compound': result_shape = Part.makeCompound(shapes) elif opmode == 'Fusion': if len(shapes)>1: result_shape = shapes[0].multiFuse(shapes[1:]) else: result_shape = Part.makeCompound(shapes) elif opmode == 'Common': if len(shapes)>0: result_shape = shapes[0] for sh in shapes[1:]: result_shape = result_shape.common(sh) else: result_shape = Part.Shape() else: raise ValueError("Operation mode {opmode} is not implemented".format(opmode= opmode)) selfobj.Shape = result_shape
def derivedExecute(self,obj): # cache stuff base = obj.Base.Shape tool = obj.Tool.Shape if tool.ShapeType != 'Compound': tool = Part.makeCompound([tool]) if obj.FlattenToolHierarchy: toolChildren = LCE.AllLeaves(tool) else: toolChildren = tool.childShapes() # validity logic if not latticeBaseFeature.isObjectLattice(obj.Tool): latticeExecuter.warning(obj, 'Tool is not a lattice object. Results may be unexpected.\n') outputIsLattice = latticeBaseFeature.isObjectLattice(obj.Base) plmMatcher = App.Placement() #extra placement, that makes first item to preserve its original placement if obj.KeepBaseFirstItemPos: plmMatcher = toolChildren[0].Placement.inverse() # Pre-collect base placement list, if base is a lattice. For speed. if outputIsLattice: baseLeaves = LCE.AllLeaves(base) basePlms = [] for leaf in baseLeaves: basePlms.append(plmMatcher.multiply(leaf.Placement)) baseLeaves = None #free memory # initialize output containers and loop variables outputShapes = [] #output list of shapes outputPlms = [] #list of placements # the essence for toolChild in toolChildren: #cache some stuff toolPlm = toolChild.Placement if outputIsLattice: for basePlm in basePlms: outputPlms.append(toolPlm.multiply(basePlm)) else: outputShape = base.copy() outputShape.Placement = toolPlm.multiply(plmMatcher.multiply(outputShape.Placement)) outputShapes.append(outputShape) if outputIsLattice: return outputPlms else: obj.Shape = Part.makeCompound(outputShapes) return None
def compoundFromAssembly(root, flatten, exclude, recursive = True, visit_set = None): if visit_set is None: visit_set = set() #recursion guard if root in visit_set: raise ValueError("Circular dependency") visit_set.add(root) if hasattr(root, 'Shape'): return root.Shape else: children = Containers.getDirectChildren(root) shapes = [] for child in children: if child in exclude: continue if child.isDerivedFrom('App::Origin'): continue #otherwise, origins create empty compounds - undesirable. if hasattr(child, 'Shape'): shapes.append(child.Shape) elif Containers.isContainer(child) and recursive: cmp = compoundFromAssembly(child, flatten, exclude, recursive, visit_set) if flatten: shapes.extend(cmp.childShapes()) else: shapes.append(cmp) transform = root.Placement if hasattr(root, 'Placement') else None ret = Part.makeCompound(shapes) if transform is not None: ret.Placement = transform return ret
def updateTrajectoryLines(): EAFolder = FreeCAD.ActiveDocument.ExplodedAssembly.Group # remove all the previous trajectory lines for traj in EAFolder: for lines in traj.Group: FreeCAD.ActiveDocument.removeObject(lines.Name) # re-draw all trajectories for traj in EAFolder: lines_compound = [] objects = [] for name in traj.names: objects.append(FreeCAD.ActiveDocument.getObject(name)) inc_D = traj.Distance dir_vectors = [] rot_centers = [] for s in xrange(len(objects)): dir_vectors.append(FreeCAD.Vector(tuple(traj.dir_vectors[s]))) rot_centers.append(FreeCAD.Vector(tuple(traj.rot_centers[s]))) for n in xrange(len(objects)): pa = rot_centers[n]# objects[n].Placement.Base pb = rot_centers[n] + dir_vectors[n]*inc_D lines_compound.append(Part.makeLine(pa, pb)) l_obj = FreeCAD.ActiveDocument.addObject('Part::Feature','trajectory_line') l_obj.Shape = Part.makeCompound(lines_compound) l_obj.ViewObject.DrawStyle = "Dashed" l_obj.ViewObject.LineWidth = 1.0 traj.addObject(l_obj) FreeCAD.Gui.updateGui()
def execute(self,obj): # gather all the child shapes into a compound shapes = self.getShapes(obj) if shapes: import Part obj.Shape = Part.makeCompound(shapes)
def execute(self, fp): try: if fp.Border == None or fp.Holes == None: return if fp.Thickness.Value <= 0: fp.Thickness.Value = 0.1 return try: self.oldHeight = fp.Shape.BoundBox.ZMax except: self.oldHeight = 0 # holes borderOutline = OpenSCAD2Dgeom.edgestofaces(fp.Border.Shape.Wires) holes = [] for i in fp.Holes.Shape.Wires: holes.append(Part.Face(i)) if len(holes): face = borderOutline.cut(Part.makeCompound(holes)) else: face = borderOutline # fp.Shape = face.extrude(FreeCAD.Base.Vector(0, 0, fp.Thickness.Value)) except: pass
def computeShape(self, obj): """ Computes simulation involved shapes. @param obj Created Part::FeaturePython object. @return Shape """ print("[ShipSimulation] Computing mesh shape...") nx = obj.FS_Nx ny = obj.FS_Ny mesh = FSMesh(obj) planes = [] # Create planes Percentage = 0 Count = 0 print("0%") for i in range(1,nx-1): for j in range(1,ny-1): Count = Count+1 done = int(round(100 * Count / ((nx-2)*(ny-2)))) if done != Percentage: Percentage = done print("%i%%" % (done)) v0 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j-1].pos + mesh[i-1][j-1].pos).multiply(0.25) v1 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j-1].pos + mesh[i+1][j-1].pos).multiply(0.25) v2 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j+1].pos + mesh[i+1][j+1].pos).multiply(0.25) v3 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j+1].pos + mesh[i-1][j+1].pos).multiply(0.25) p = Part.makePolygon([v0,v1,v2,v3,v0]) planes.append(Part.makeFilledFace(p.Edges)) # Join into a compound return Part.makeCompound(planes)
def guessDepths(objshape, subs=None): """ takes an object shape and optional list of subobjects and returns a depth_params object with suggested height/depth values. objshape = Part::Shape. subs = list of subobjects from objshape """ bb = objshape.BoundBox # parent boundbox clearance = bb.ZMax + 5.0 safe = bb.ZMax start = bb.ZMax final = bb.ZMin if subs is not None: subobj = Part.makeCompound(subs) fbb = subobj.BoundBox # feature boundbox start = fbb.ZMax if fbb.ZMax == fbb.ZMin and fbb.ZMax == bb.ZMax: # top face final = fbb.ZMin elif fbb.ZMax > fbb.ZMin and fbb.ZMax == bb.ZMax: # vertical face, full cut final = fbb.ZMin elif fbb.ZMax > fbb.ZMin and fbb.ZMin > bb.ZMin: # internal vertical wall final = fbb.ZMin elif fbb.ZMax == fbb.ZMin and fbb.ZMax > bb.ZMin: # face/shelf final = fbb.ZMin return depth_params(clearance, safe, start, 1.0, 0.0, final, user_depths=None, equalstep=False)
def makeBase(l,z,lpol,zpol,lone,zone,zero): lines=[] f=np.sqrt(len2(lpol,zero)) e=np.sqrt(len2(lone,zero)) dist=e*f*l/((l-1)*e+f) pa=pointat(zero,lpol,dist) print (l,z,dist,pa) # lines.append(Part.makeLine(vec(zpol),vec(pa))) # lines.append(Part.makeCircle(10000,vec(pa))) f=np.sqrt(len2(zpol,zero)) e=np.sqrt(len2(zone,zero)) dist=e*f*z/((z-1)*e+f) pb=pointat(zero,zpol,dist) print (l,z,dist,pb) # lines.append(Part.makeLine(vec(lpol),vec(pb))) # lines.append(Part.makeCircle(10000,vec(pb))) pc=schnittpunkt(lpol,pb,zpol,pa) print (pa,pb,pc) lines.append(Part.makeCircle(15000,vec(pc))) comp=Part.makeCompound(lines) # Part.show(comp) return pc
def execute(self, fp): """Detects the entity recomputations. Keyword arguments: fp -- Part::FeaturePython object affected. """ fp.Shape = Part.makeCompound(fp.Shape.Solids)
def updateData(self,obj,prop): if prop == "Shape": if hasattr(self,"centerline"): if self.centerline: self.centerlinegroup.removeChild(self.centerline) if hasattr(obj.Proxy,"wires"): if obj.Proxy.wires: from pivy import coin import re,Part self.centerline = coin.SoSeparator() comp = Part.makeCompound(obj.Proxy.wires) pts = re.findall("point \[(.*?)\]",comp.writeInventor().replace("\n","")) pts = [p.split(",") for p in pts] for pt in pts: ps = coin.SoSeparator() plist = [] for p in pt: c = [] for pstr in p.split(" "): if pstr: c.append(float(pstr)) plist.append(c) coords = coin.SoCoordinate3() coords.point.setValues(plist) ps.addChild(coords) ls = coin.SoLineSet() ls.numVertices = -1 ps.addChild(ls) self.centerline.addChild(ps) self.centerlinegroup.addChild(self.centerline) ArchComponent.ViewProviderComponent.updateData(self,obj,prop)
def areaOpOnChanged(self, obj, prop): '''areaOpOnChanged(obj, prop) ... facing specific depths calculation.''' PathLog.track(prop) if prop == "StepOver" and obj.StepOver == 0: obj.StepOver = 1 # default depths calculation not correct for facing if prop == "Base": job = PathUtils.findParentJob(obj) obj.OpStartDepth = job.Stock.Shape.BoundBox.ZMax if len(obj.Base) >= 1: print('processing') sublist = [] for i in obj.Base: o = i[0] for s in i[1]: sublist.append(o.Shape.getElement(s)) # If the operation has a geometry identified the Finaldepth # is the top of the bboundbox which includes all features. # Otherwise, top of part. obj.OpFinalDepth = Part.makeCompound(sublist).BoundBox.ZMax else: obj.OpFinalDepth = job.Base.Shape.BoundBox.ZMax
def __init__(self, obj, shapes, ship): """ Transform a generic object to a ship instance. Keyword arguments: obj -- Part::FeaturePython created object which should be transformed in a weight instance. shapes -- Set of solid shapes which will compound the tank. ship -- Ship where the tank is allocated. """ # Add an unique property to identify the Weight instances tooltip = str( QtGui.QApplication.translate( "ship_tank", "True if it is a valid tank instance, False otherwise", None, QtGui.QApplication.UnicodeUTF8, ) ) obj.addProperty("App::PropertyBool", "IsTank", "Tank", tooltip).IsTank = True # Add the volume property (The volume of fluid will be set by each # loading condition) tooltip = str( QtGui.QApplication.translate("ship_tank", "Volume of fluid [m^3]", None, QtGui.QApplication.UnicodeUTF8) ) obj.addProperty("App::PropertyFloat", "Vol", "Tank", tooltip).Vol = 0.0 # Add the density property (The volume of fluid will be set by each # loading condition) tooltip = str( QtGui.QApplication.translate("ship_tank", "Density [kg / m^3]", None, QtGui.QApplication.UnicodeUTF8) ) obj.addProperty("App::PropertyFloat", "Dens", "Tank", tooltip).Dens = 0.0 # Set the subshapes obj.Shape = Part.makeCompound(shapes) obj.Proxy = self
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return top face''' # Facing is done either against base objects if obj.Base: PathLog.debug("obj.Base: {}".format(obj.Base)) faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) else: PathLog.debug('The base subobject is not a face') return planeshape = Part.makeCompound(faces) PathLog.debug("Working on a collection of faces {}".format(faces)) # If no base object, do planing of top surface of entire model else: planeshape = self.baseobject.Shape PathLog.debug("Working on a shape {}".format(self.baseobject.Name)) # Find the correct shape depending on Boundary shape. PathLog.debug("Boundary Shape: {}".format(obj.BoundaryShape)) bb = planeshape.BoundBox if obj.BoundaryShape == 'Boundbox': bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin), FreeCAD.Vector(0, 0, 1)) env = PathUtils.getEnvelope(partshape=bbperim, depthparams=self.depthparams) elif obj.BoundaryShape == 'Stock': stock = PathUtils.findParentJob(obj).Stock.Shape env = stock else: env = PathUtils.getEnvelope(partshape=planeshape, depthparams=self.depthparams) return [(env, False)]
def export_xyz_to_dxf(ai_solid, ai_size_x, ai_size_y, ai_size_z, ai_xy_slice_list, ai_xz_slice_list, ai_yz_slice_list, ai_output_file): """ Cut a FreeCAD Part Object in many slices in the three directions X, Y and Z and put all those slices in a DXF file """ # calculate the space between two drawings l_space = max(ai_size_x/5.0, ai_size_y/5.0, ai_size_z/5.0) # vec_z_unit = Base.Vector(0,0,1) # l_slice_list = [] l_pos_y = 0 for lo in ['xy','xz','yz']: #l_solid = ai_solid l_solid = ai_solid.copy() l_depth_list = [] l_shift_x = 0 l_gauge_max = 0 if(lo=='xy'): l_solid.rotate(Base.Vector(ai_size_x/2.0, ai_size_y/2.0, ai_size_z/2.0), Base.Vector(0,0,1), 0) l_solid.translate(Base.Vector(0,0,0)) # place the module corner at origin (0,0,0) l_solid.translate(Base.Vector(0,2*ai_size_z+7*l_space,0)) l_pos_y = 2*ai_size_z+6*l_space l_depth_list = ai_xy_slice_list l_shift_x = ai_size_x l_gauge_max = ai_size_z elif(lo=='xz'): l_solid.rotate(Base.Vector(ai_size_x/2.0, ai_size_y/2.0, ai_size_z/2.0), Base.Vector(1,0,0), -90) l_solid.translate(Base.Vector((ai_size_x-ai_size_x)/2.0, (ai_size_z-ai_size_y)/2.0, (ai_size_y-ai_size_z)/2.0)) # place the module corner at origin (0,0,0) l_solid.translate(Base.Vector(0,1*ai_size_z+4*l_space,0)) l_pos_y = 1*ai_size_z+3*l_space l_depth_list = ai_xz_slice_list l_shift_x = ai_size_x l_gauge_max = ai_size_y elif(lo=='yz'): l_solid.rotate(Base.Vector(ai_size_x/2.0, ai_size_y/2.0, ai_size_z/2.0), Base.Vector(0,0,1), -90) l_solid.rotate(Base.Vector(ai_size_x/2.0, ai_size_y/2.0, ai_size_z/2.0), Base.Vector(1,0,0), -90) l_solid.translate(Base.Vector((ai_size_y-ai_size_x)/2.0, (ai_size_z-ai_size_y)/2.0, (ai_size_x-ai_size_z)/2.0)) # place the module corner at origin (0,0,0) l_solid.translate(Base.Vector(0,l_space,0)) l_pos_y = 0*ai_size_z+0*l_space l_depth_list = ai_yz_slice_list l_shift_x = ai_size_y l_gauge_max = ai_size_x l_pos_x = 0 for l_depth in l_depth_list: #print("dbg163: l_shift_x l_space l_gauge_max l_depth l_pos_x l_pos_y", l_shift_x, l_space, l_gauge_max, l_depth, l_pos_x, l_pos_y) l_slice_list.extend(draw_gauge(l_shift_x, l_space/2.0, l_gauge_max, l_depth, l_pos_x, l_pos_y)) l_pos_x += l_shift_x+2*l_space ll_depth = l_depth if(lo=='xz'): ll_depth = ai_size_y-l_depth #print("dbg168: ll_depth:", ll_depth) l_slice_list.extend(l_solid.slice(vec_z_unit, ll_depth)) l_solid.translate(Base.Vector(l_shift_x+2*l_space,0,0)) l_slice = Part.makeCompound(l_slice_list) # temporary commented because of OpenCascade bug #r_dxf = Drawing.projectToDXF(l_slice, vec_z_unit) ##r_dxf = Drawing.projectToDXF(ai_solid, ai_vector) #fh_output = open(ai_output_file, 'w') #fh_output.write(r_dxf) #fh_output.close() return(1)
def createGeometry(self,obj): import Part pl = obj.Placement if obj.Components: shapes = [] if obj.JoinMode: walls = [] structs = [] for c in obj.Components: if Draft.getType(c) == "Wall": walls.append(c.Shape) elif Draft.getType(c) == "Structure": structs.append(c.Shape) else: shapes.append(c.Shape) for group in [walls,structs]: if group: sh = group.pop(0).copy() for subsh in group: sh = sh.oldFuse(subsh) shapes.append(sh) else: for c in obj.Components: shapes.append(c.Shape) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def connect(list_of_shapes, tolerance = 0.0): """connect(list_of_shapes, tolerance = 0.0): connects solids (walled objects), shells and wires by throwing off small parts that result when splitting them at intersections. Compounds in list_of_shapes are automatically exploded, so self-intersecting compounds are valid for connect.""" # explode all compounds before GFA. new_list_of_shapes = [] for sh in list_of_shapes: new_list_of_shapes.extend( compoundLeaves(sh) ) list_of_shapes = new_list_of_shapes #test if shapes are compatible for connecting dim = ShapeMerge.dimensionOfShapes(list_of_shapes) if dim == 0: raise TypeError("Cannot connect vertices!") if len(list_of_shapes) < 2: return Part.makeCompound(list_of_shapes) if not generalFuseIsAvailable(): #fallback to legacy result = list_of_shapes[0] for i in range(1, len(list_of_shapes)): result = connect_legacy(result, list_of_shapes[i], tolerance) return result pieces, map = list_of_shapes[0].generalFuse(list_of_shapes[1:], tolerance) ao = GeneralFuseResult(list_of_shapes, (pieces, map)) ao.splitAggregates() #print len(ao.pieces)," pieces total" keepers = [] all_danglers = [] # debug #add all biggest dangling pieces for src in ao.source_shapes: danglers = [piece for piece in ao.piecesFromSource(src) if len(ao.sourcesOfPiece(piece)) == 1] all_danglers.extend(danglers) largest = shapeOfMaxSize(danglers) if largest is not None: keepers.append(largest) touch_test_list = Part.Compound(keepers) #add all intersection pieces that touch danglers, triple intersection pieces that touch duals, and so on for ii in range(2, ao.largestOverlapCount()+1): list_ii_pieces = [piece for piece in ao.pieces if len(ao.sourcesOfPiece(piece)) == ii] keepers_2_add = [] for piece in list_ii_pieces: if ShapeMerge.isConnected(piece, touch_test_list): keepers_2_add.append(piece) if len(keepers_2_add) == 0: break keepers.extend(keepers_2_add) touch_test_list = Part.Compound(keepers_2_add) #merge, and we are done! #print len(keepers)," pieces to keep" return ShapeMerge.mergeShapes(keepers)
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() if obj.Base: PathLog.debug("base items exist. Processing...") removalshapes = [] for b in obj.Base: PathLog.debug("Base item: {}".format(b)) for sub in b[1]: if "Face" in sub: shape = Part.makeCompound([getattr(b[0].Shape, sub)]) else: edges = [getattr(b[0].Shape, sub) for sub in b[1]] shape = Part.makeFace(edges, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(self.baseobject.Shape) removalshapes.append((obj.removalshape, False)) else: # process the job base object as a whole PathLog.debug("processing the whole job base object") env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=None, depthparams=self.depthparams) obj.removalshape = env.cut(self.baseobject.Shape) removalshapes = [(obj.removalshape, False)] return removalshapes
def main(filename,canny1=100,canny2=200,rho=1,theta=1, threshold=10, minLineLength =25, maxLineGap =10, showimage=False,showimagewithlines=False,newDocument=True): # def main(f): f=filename im = cv2.imread(f) gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray,canny1,canny2) xsize=len(im[0]) ysize=len(im) #image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) lines = cv2.HoughLinesP(edges,1,np.pi/180*theta,threshold, minLineLength = minLineLength, maxLineGap = maxLineGap) # lines = cv2.HoughLinesP(edges,1,np.pi/180,10, minLineLength = 25, maxLineGap = 10) #lines = cv2.HoughLinesP(edges,1,np.pi/2,2)[0] k=0 fclines=[] for l in lines: k += 1 [[x1,y1,x2,y2]] = l fl=fclinev2(x1,-y1,x2,-y2) fclines.append(fl) #print (x1,y1,x2,y2) a=cv2.line(im,(x1,y1),(x2,y2),(0,255,255),2) c=Part.makeCompound(fclines) c.Placement.Base=FreeCAD.Vector(-xsize/2*scaler,ysize/2*scaler,0) if newDocument: d=App.newDocument("HoughLines") # App.setActiveDocument("Unnamed1") # App.ActiveDocument=d # Gui.ActiveDocument=Gui.getDocument("Unnamed1") Part.show(c) cv2.imwrite('/tmp/out.png',im) import Image, ImageGui #ImageGui.open(unicode("/tmp/out.png","utf-8")) if showimage: fimg=App.activeDocument().addObject('Image::ImagePlane','Image 2') fimg.Label=f fimg.ImageFile = f fimg.XSize = xsize*scaler fimg.YSize = ysize*scaler fimg.Placement.Base.z=-5 if showimagewithlines: fimg=App.activeDocument().addObject('Image::ImagePlane','Image with Houghlines') fimg.ImageFile = '/tmp/out.png' fimg.XSize = xsize*scaler fimg.YSize = ysize*scaler fimg.Placement.Base.z=-10 FreeCADGui.SendMsgToActiveView("ViewFit") print ("lines:",k)
def execute(self,obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils base = None pl = obj.Placement extdata = self.getExtrusionData(obj) if extdata: base = extdata[0] extv = extdata[2].Rotation.multVec(extdata[1]) if isinstance(base,list): shps = [] for b in base: b.Placement = extdata[2].multiply(b.Placement) b = b.extrude(extv) shps.append(b) base = Part.makeCompound(shps) else: base.Placement = extdata[2].multiply(base.Placement) base = base.extrude(extv) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return elif obj.Base.Shape.Solids: base = obj.Base.Shape.copy() elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning(translate("Arch","This mesh is an invalid solid")+"\n") obj.Base.ViewObject.show() if not base: FreeCAD.Console.PrintError(translate("Arch","Error: Invalid base object")+"\n") return base = self.processSubShapes(obj,base,pl) self.applyShape(obj,base,pl) # set the length property if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Edges: if not obj.Base.Shape.Faces: if hasattr(obj.Base.Shape,"Length"): l = obj.Base.Shape.Length if obj.Length.Value != l: obj.Length = l
def __init__(self, obj, shapes, ship): """ Transform a generic object to a ship instance. Position arguments: obj -- Part::FeaturePython created object which should be transformed in a weight instance. shapes -- Set of shapes which will compound the weight element. ship -- Ship where the weight is allocated. """ # Add an unique property to identify the Weight instances tooltip = str(QtGui.QApplication.translate( "ship_weight", "True if it is a valid weight instance, False otherwise", None)) obj.addProperty("App::PropertyBool", "IsWeight", "Weight", tooltip).IsWeight = True # Add the mass property for puntual weights tooltip = str(QtGui.QApplication.translate( "ship_weight", "Mass [kg]", None)) obj.addProperty("App::PropertyFloat", "Mass", "Weight", tooltip).Mass = 0.0 # Add the density property for linear elements tooltip = str(QtGui.QApplication.translate( "ship_weight", "Linear density [kg / m]", None)) obj.addProperty("App::PropertyFloat", "LineDens", "Weight", tooltip).LineDens = 0.0 # Add the area density property for surface elements tooltip = str(QtGui.QApplication.translate( "ship_weight", "Area density [kg / m^2]", None)) obj.addProperty("App::PropertyFloat", "AreaDens", "Weight", tooltip).AreaDens = 0.0 # Add the density property for volumetric elements tooltip = str(QtGui.QApplication.translate( "ship_weight", "Density [kg / m^3]", None)) obj.addProperty("App::PropertyFloat", "Dens", "Weight", tooltip).Dens = 0.0 # Set the subshapes obj.Shape = Part.makeCompound(shapes) obj.Proxy = self
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' if obj.UseComp: self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: # The user has selected subobjects from the base. Process each. holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: FreeCAD.Console.PrintWarning("found a base object which is not a face. Can't continue.") return for wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(self.baseobject.Shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if len(faces) > 0: profileshape = Part.makeCompound(faces) if obj.processPerimeter: env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=profileshape, depthparams=self.depthparams) shapes.append((env, False)) else: # Try to build targets from the job base if hasattr(self.baseobject, "Proxy"): if isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.baseobject.Proxy.getHoles(self.baseobject, transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable(self.baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if obj.processPerimeter: for shape in self.baseobject.Proxy.getOutlines(self.baseobject, transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) PathLog.debug("%d shapes" % len(shapes)) return shapes
def __init__(self, obj, solids): """ Transform a generic object to a ship instance. Keyword arguments: obj -- Part::FeaturePython created object which should be transformed in a ship instance. solids -- Set of solids which will compound the ship hull. """ # Add an unique property to identify the Ship instances tooltip = str(QtGui.QApplication.translate( "Ship", "True if it is a valid ship instance, False otherwise", None, QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyBool", "IsShip", "Ship", tooltip).IsShip = True # Add the main dimensions tooltip = str(QtGui.QApplication.translate( "Ship", "Ship length [m]", None, QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyLength", "Length", "Ship", tooltip).Length = 0.0 tooltip = str(QtGui.QApplication.translate( "Ship", "Ship breadth [m]", None, QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyLength", "Breadth", "Ship", tooltip).Breadth = 0.0 tooltip = str(QtGui.QApplication.translate( "Ship", "Ship draft [m]", None, QtGui.QApplication.UnicodeUTF8)) obj.addProperty("App::PropertyLength", "Draft", "Ship", tooltip).Draft = 0.0 # Add the subshapes obj.Shape = Part.makeCompound(solids) tooltip = str(QtGui.QApplication.translate( "Ship", "Set of external faces of the ship hull", None, QtGui.QApplication.UnicodeUTF8)) obj.addProperty("Part::PropertyPartShape", "ExternalFaces", "Ship", tooltip) obj.Proxy = self
def mergeWires(list_of_edges_wires, flag_single = False, split_connections = []): edges = [] for sh in list_of_edges_wires: edges.extend(sh.Edges) if flag_single: return Part.Wire(edges) else: groups = splitIntoGroupsBySharing(edges, lambda(sh): sh.Vertexes, split_connections) return Part.makeCompound([Part.Wire(Part.getSortedClusters(group)[0]) for group in groups])
def mergeShells(list_of_faces_shells, flag_single = False, split_connections = []): faces = [] for sh in list_of_faces_shells: faces.extend(sh.Faces) if flag_single: return Part.makeShell(faces) else: groups = splitIntoGroupsBySharing(faces, lambda(sh): sh.Edges, split_connections) return Part.makeCompound([Part.Shell(group) for group in groups])
def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True): import Part, MeshPart, DraftGeomUtils if mesh.isSolid() and (mesh.countComponents() == 1) and fast: # use the best method faces = [] for f in mesh.Facets: p=f.Points+[f.Points[0]] pts = [] for pp in p: pts.append(FreeCAD.Vector(pp[0],pp[1],pp[2])) try: f = Part.Face(Part.makePolygon(pts)) except: pass else: faces.append(f) shell = Part.makeShell(faces) solid = Part.Solid(shell) solid = solid.removeSplitter() return solid faces = [] segments = mesh.getPlanarSegments(tolerance) #print len(segments) for i in segments: if len(i) > 0: wires = MeshPart.wireFromSegment(mesh, i) if wires: if flat: nwires = [] for w in wires: nwires.append(DraftGeomUtils.flattenWire(w)) wires = nwires try: faces.append(makeFace(wires,method=int(cut)+1)) except: return None try: se = Part.makeShell(faces) se = se.removeSplitter() if flat: return se except Part.OCCError: try: cp = Part.makeCompound(faces) except Part.OCCError: return None else: return cp else: try: solid = Part.Solid(se) except Part.OCCError: return se else: return solid
def execute(self, obj): if 'tGlue' in self.Type: z = getPCBheight()[1] + 0.04 h = obj.Height.Value if h <= 0: h = 0.01 else: # bottomSide z = -0.04 h = -obj.Height.Value if h >= 0: h = -0.01 # obiekty = [] # for i in obj.Base.Geometry: if i.__class__.__name__ == 'GeomLineSegment': x1 = i.StartPoint.x y1 = i.StartPoint.y x2 = i.EndPoint.x y2 = i.EndPoint.y # obiekty.append(self.createLine(x1, y1, x2, y2, obj.Width.Value)) elif i.__class__.__name__ == 'GeomCircle': x = i.Center.x y = i.Center.y r = i.Radius # obiekty.append(self.createCircle(x, y, r, obj.Width.Value)) elif i.__class__.__name__ == 'GeomArcOfCircle': curve = degrees(i.LastParameter - i.FirstParameter) xs = i.Center.x ys = i.Center.y r = i.Radius math = mathFunctions() p1 = [math.cosinus(degrees(i.FirstParameter)) * r, math.sinus(degrees(i.FirstParameter)) * r] p1 = [p1[0] + xs, p1[1] + ys] p2 = math.obrocPunkt2(p1, [xs, ys], curve) # obiekty.append(self.createArc(p1, p2, curve, obj.Width.Value)) # #path = obiekty[0] #for i in range(1, len(obiekty)): #path = path.fuse(obiekty[i]) #path = path.removeSplitter() path = Part.makeCompound(obiekty) # cut to board shape if self.cutToBoard: path = cutToBoardShape(path) ################################################### if obj.Flat == False: path = path.extrude(FreeCAD.Base.Vector(0, 0, h)) path.Placement.Base.z = z obj.Shape = path
def export_to_svg(ai_solid, ai_vector, ai_depth, ai_output_file): """ create a SVG of a slice of FreeCAD Part Object. The generated SVG is incomplete. SVG header must be added to it to be opened by Inkscape """ l_slice = Part.makeCompound(ai_solid.slice(ai_vector, ai_depth)) # slice the plank in the ai_vector plan at a the height ai_depth r_dxf = Drawing.projectToSVG(l_slice, ai_vector) # it generates a snippet of svg not directly usable by Inkscape. It needs the svg head and document markers. #r_dxf = Drawing.projectToSVG(ai_solid, ai_vector) # works also :) fh_output = open(ai_output_file, 'w') fh_output.write(r_dxf) fh_output.close() return(1)
def export_to_dxf(ai_solid, ai_vector, ai_depth, ai_output_file): """ create a DXF of a slice of FreeCAD Part Object """ l_slice = Part.makeCompound(ai_solid.slice(ai_vector, ai_depth)) # slice the plank in the ai_vector plan at a the height ai_depth r_dxf = Drawing.projectToDXF(l_slice, ai_vector) #r_dxf = Drawing.projectToDXF(ai_solid, ai_vector) # works also :) fh_output = open(ai_output_file, 'w') fh_output.write(r_dxf) fh_output.close() return(1)
def execute(self, obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils base = None pl = obj.Placement extdata = self.getExtrusionData(obj) if extdata: base = extdata[0] extv = extdata[2].Rotation.multVec(extdata[1]) if isinstance(base, list): shps = [] for b in base: b.Placement = extdata[2].multiply(b.Placement) b = b.extrude(extv) shps.append(b) base = Part.makeCompound(shps) else: base.Placement = extdata[2].multiply(base.Placement) base = base.extrude(extv) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return elif obj.Base.Shape.Solids: base = obj.Base.Shape.copy() elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and ( not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning( translate("Arch", "This mesh is an invalid solid") + "\n") obj.Base.ViewObject.show() if not base: FreeCAD.Console.PrintError( translate("Arch", "Error: Invalid base object") + "\n") return base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl) # set the length property if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Edges: if not obj.Base.Shape.Faces: if hasattr(obj.Base.Shape, "Length"): l = obj.Base.Shape.Length if obj.Length.Value != l: obj.Length = l
def execute(self,obj): if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return pl = obj.Placement if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() if not pl.isNull(): obj.Placement = obj.Shape.Placement.multiply(pl) else: if not obj.Profile: return if not obj.Profile.isDerivedFrom("Part::Part2DObject"): return if not obj.Profile.Shape: return if not obj.Profile.Shape.Wires: return if not obj.Profile.Shape.Faces: for w in obj.Profile.Shape.Wires: if not w.isClosed(): return import DraftGeomUtils, Part, math baseprofile = obj.Profile.Shape.copy() if not baseprofile.Faces: f = [] for w in baseprofile.Wires: f.append(Part.Face(w)) if len(f) == 1: baseprofile = f[0] else: baseprofile = Part.makeCompound(f) shapes = [] normal = DraftGeomUtils.getNormal(obj.Base.Shape) #for wire in obj.Base.Shape.Wires: for e in obj.Base.Shape.Edges: #e = wire.Edges[0] bvec = DraftGeomUtils.vec(e) bpoint = e.Vertexes[0].Point profile = baseprofile.copy() #basepoint = profile.Placement.Base if hasattr(obj,"BasePoint"): if obj.BasePoint == 0 : basepoint = profile.CenterOfMass else : # TODO add mid point of edges and make an ordered list point, mid point , ... basepoint = profile.Vertexes[obj.BasePoint - 1].Point else : basepoint = profile.CenterOfMass profile.translate(bpoint.sub(basepoint)) if obj.Align: axis = profile.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1)) angle = bvec.getAngle(axis) if round(angle,Draft.precision()) != 0: if round(angle,Draft.precision()) != round(math.pi,Draft.precision()): rotaxis = axis.cross(bvec) profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle)) if obj.Rotation: profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation) #profile = wire.makePipeShell([profile],True,False,2) TODO buggy profile = profile.extrude(bvec) if obj.Offset: if not DraftVecUtils.isNull(obj.Offset): profile.translate(obj.Offset) shapes.append(profile) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale=1, rotation=0, linewidth=1, lineColor=(0.0, 0.0, 0.0), fontsize=1, showFill=False, fillColor=(0.8, 0.8, 0.8), techdraw=False): """getSVG(section, [renderMode, allOn, showHidden, scale, rotation, linewidth, lineColor, fontsize, showFill, fillColor, techdraw]): returns an SVG fragment from an Arch section plane. If allOn is True, all cut objects are shown, regardless if they are visible or not. renderMode can be Wireframe (default) or Solid to use the Arch solid renderer. If showHidden is True, the hidden geometry above the section plane is shown in dashed line. If showFill is True, the cut areas get filled with a pattern. lineColor -- Color of lines for the renderMode "Wireframe". fillColor -- If showFill is True and renderMode is "Wireframe", the cut areas are filled with fillColor. """ if not section.Objects: return "" import Part, DraftGeomUtils p = FreeCAD.Placement(section.Placement) direction = p.Rotation.multVec(FreeCAD.Vector(0, 0, 1)) objs = Draft.getGroupContents(section.Objects, walls=True, addgroups=True) if not allOn: objs = Draft.removeHidden(objs) # separate spaces and Draft objects spaces = [] nonspaces = [] drafts = [] windows = [] cutface = None for o in objs: if Draft.getType(o) == "Space": spaces.append(o) elif Draft.getType(o) in ["Dimension", "Annotation"]: drafts.append(o) elif o.isDerivedFrom("Part::Part2DObject"): drafts.append(o) else: nonspaces.append(o) if Draft.getType(o) == "Window": windows.append(o) objs = nonspaces archUserParameters = FreeCAD.ParamGet( "User parameter:BaseApp/Preferences/Mod/Arch") scaledLineWidth = linewidth / scale svgLineWidth = str(scaledLineWidth) + 'px' st = archUserParameters.GetFloat("CutLineThickness", 2) svgCutLineWidth = str(scaledLineWidth * st) + 'px' yt = archUserParameters.GetFloat("SymbolLineThickness", 0.6) svgSymbolLineWidth = str(linewidth * yt) hiddenPattern = archUserParameters.GetString("archHiddenPattern", "30,10") svgHiddenPattern = hiddenPattern.replace(" ", "") fillpattern = '<pattern id="sectionfill" patternUnits="userSpaceOnUse" patternTransform="matrix(5,0,0,5,0,0)"' fillpattern += ' x="0" y="0" width="10" height="10">' fillpattern += '<g>' fillpattern += '<rect width="10" height="10" style="stroke:none; fill:#ffffff" /><path style="stroke:#000000; stroke-width:1" d="M0,0 l10,10" /></g></pattern>' svg = '' # generating SVG if renderMode in ["Solid", 1]: # render using the Arch Vector Renderer import ArchVRM, WorkingPlane wp = WorkingPlane.plane() wp.setFromPlacement(section.Placement) #wp.inverse() render = ArchVRM.Renderer() render.setWorkingPlane(wp) render.addObjects(objs) if showHidden: render.cut(section.Shape, showHidden) else: render.cut(section.Shape) svg += '<g transform="scale(1,-1)">\n' svg += render.getViewSVG(linewidth=svgLineWidth) svg += fillpattern svg += render.getSectionSVG(linewidth=svgCutLineWidth, fillpattern="sectionfill") if showHidden: svg += render.getHiddenSVG(linewidth=svgLineWidth) svg += '</g>\n' # print(render.info()) else: # render using the Drawing module import Drawing, Part shapes, hshapes, sshapes, cutface, cutvolume, invcutvolume = getCutShapes( objs, section, showHidden) if shapes: baseshape = Part.makeCompound(shapes) style = { 'stroke': Draft.getrgb(lineColor), 'stroke-width': svgLineWidth } svg += Drawing.projectToSVG(baseshape, direction, hStyle=style, h0Style=style, h1Style=style, vStyle=style, v0Style=style, v1Style=style) if hshapes: hshapes = Part.makeCompound(hshapes) style = { 'stroke': Draft.getrgb(lineColor), 'stroke-width': svgLineWidth, 'stroke-dasharray': svgHiddenPattern } svg += Drawing.projectToSVG(hshapes, direction, hStyle=style, h0Style=style, h1Style=style, vStyle=style, v0Style=style, v1Style=style) if sshapes: if showFill: #svg += fillpattern svg += '<g transform="rotate(180)">\n' for s in sshapes: if s.Edges: #svg += Draft.getSVG(s,direction=direction.negative(),linewidth=0,fillstyle="sectionfill",color=(0,0,0)) # temporarily disabling fill patterns svg += Draft.getSVG(s, direction=direction.negative(), linewidth=0, fillstyle=Draft.getrgb(fillColor), color=lineColor) svg += "</g>\n" sshapes = Part.makeCompound(sshapes) style = { 'stroke': Draft.getrgb(lineColor), 'stroke-width': svgCutLineWidth } svg += Drawing.projectToSVG(sshapes, direction, hStyle=style, h0Style=style, h1Style=style, vStyle=style, v0Style=style, v1Style=style) if drafts: if not techdraw: svg += '<g transform="scale(1,-1)">' for d in drafts: svg += Draft.getSVG(d, scale=scale, linewidth=svgSymbolLineWidth, fontsize=fontsize, direction=direction, color=lineColor, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' # filter out spaces not cut by the section plane if cutface and spaces: spaces = [ s for s in spaces if s.Shape.BoundBox.intersect(cutface.BoundBox) ] if spaces: if not techdraw: svg += '<g transform="scale(1,-1)">' for s in spaces: svg += Draft.getSVG(s, scale=scale, linewidth=svgSymbolLineWidth, fontsize=fontsize, direction=direction, color=lineColor, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' # add additional edge symbols from windows cutwindows = [] if cutface and windows: cutwindows = [ w.Name for w in windows if w.Shape.BoundBox.intersect(cutface.BoundBox) ] if windows: sh = [] for w in windows: if not hasattr(w.Proxy, "sshapes"): w.Proxy.execute(w) if hasattr(w.Proxy, "sshapes"): if w.Proxy.sshapes and (w.Name in cutwindows): c = Part.makeCompound(w.Proxy.sshapes) c.Placement = w.Placement sh.append(c) # buggy for now... #if hasattr(w.Proxy,"vshapes"): # if w.Proxy.vshapes: # c = Part.makeCompound(w.Proxy.vshapes) # c.Placement = w.Placement # sh.append(c) if sh: if not techdraw: svg += '<g transform="scale(1,-1)">' for s in sh: svg += Draft.getSVG(s, scale=scale, linewidth=svgSymbolLineWidth, fontsize=fontsize, fillstyle="none", direction=direction, color=lineColor, techdraw=techdraw, rotation=rotation) if not techdraw: svg += '</g>' return svg
def makeStraightLanding(self, obj, edge, numberofsteps=None): "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part, DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x, v.y, 0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) h = obj.Height.Value l = obj.Length.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength fLength = float(l - obj.Width.Value) / (numberofsteps - 2) fHeight = float(h) / numberofsteps a = math.atan(fHeight / fLength) print "landing data:", fLength, ":", fHeight # step p1 = self.align(vBase, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0, 0, -fHeight)).add( Vector(0, 0, -obj.StructureThickness.Value / math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength, reslength)).add( Vector(0, 0, resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: p7 = p6.add(Vector(0, 0, obj.TreadThickness.Value)) reslength = fLength + ( obj.StructureThickness.Value / math.sin(a) - (fHeight - obj.TreadThickness.Value) / math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength, reslength)) else: p5 = p6.add(DraftVecUtils.scaleTo(vLength, reslength)) resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight / math.tan(a) p4 = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)).add( Vector(0, 0, -resheight)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p7, p6, p1])) else: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p6, p1])) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0, 0, -fHeight)) reslength = fHeight / math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength, reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value / math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)) reslength = obj.TreadThickness.Value / math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo( vLength, -reslength)).add( Vector(0, 0, -obj.TreadThickness.Value)) pol = Part.Face( Part.makePolygon( [p1c, p1b, p2, p3, p4, p5, p5b, p5c, p1c])) else: pol = Part.Face( Part.makePolygon([p1c, p1b, p2, p3, p4, p5, p1c])) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def makeStraightStairs(self, obj, edge, numberofsteps=None): "builds a simple, straight staircase from a straight edge" # general data import Part, DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo( v, float(edge.Length) / (numberofsteps - 1)) vLength = Vector(vLength.x, vLength.y, 0) if round(v.z, Draft.precision()) != 0: h = v.z else: h = obj.Height.Value vHeight = Vector(0, 0, float(h) / numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) a = math.atan(vHeight.Length / vLength.Length) #print "stair data:",vLength.Length,":",vHeight.Length # steps for i in range(numberofsteps - 1): p1 = vBase.add((Vector(vLength).multiply(i)).add( Vector(vHeight).multiply(i + 1))) p1 = self.align(p1, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness.Value: for i in range(numberofsteps - 1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add( Vector(0, 0, -abs(obj.TreadThickness.Value))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness.Value / math.cos(a) lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1))) resHeight2 = ((numberofsteps - 1) * vHeight.Length) - ( resHeight1 + obj.TreadThickness.Value) resLength = (vLength.Length / vHeight.Length) * resHeight2 h = DraftVecUtils.scaleTo(vLength, -resLength) lProfile.append(lProfile[-1].add(Vector(h.x, h.y, -resHeight2))) lProfile.append(vBase) #print lProfile pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps - 1) h1 = Vector(vHeight).multiply(numberofsteps - 1).add( Vector(0, 0, -abs(obj.TreadThickness.Value))) p1 = vBase.add(l1).add(h1) p1 = self.align(p1, obj.Align, vWidth) lProfile.append(p1) h2 = (obj.StructureThickness.Value / vLength.Length) * hyp lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h2)))) h3 = lProfile[-1].z - vBase.z l3 = (h3 / vHeight.Length) * vLength.Length v3 = DraftVecUtils.scaleTo(vLength, -l3) lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h3))).add(v3)) l4 = (obj.StructureThickness.Value / vHeight.Length) * hyp v4 = DraftVecUtils.scaleTo(vLength, -l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print lProfile pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def execute(self,obj): import Part,DraftGeomUtils,math pl = obj.Placement w = self.getWire(obj) if not w: FreeCAD.Console.PrintError(translate("Arch","Unable to build the base path")+"\n") return if obj.OffsetStart.Value: e = w.Edges[0] v = e.Vertexes[-1].Point.sub(e.Vertexes[0].Point).normalize() v.multiply(obj.OffsetStart.Value) e = Part.LineSegment(e.Vertexes[0].Point.add(v),e.Vertexes[-1].Point).toShape() w = Part.Wire([e]+w.Edges[1:]) if obj.OffsetEnd.Value: e = w.Edges[-1] v = e.Vertexes[0].Point.sub(e.Vertexes[-1].Point).normalize() v.multiply(obj.OffsetEnd.Value) e = Part.LineSegment(e.Vertexes[-1].Point.add(v),e.Vertexes[0].Point).toShape() w = Part.Wire(w.Edges[:-1]+[e]) p = self.getProfile(obj) if not p: FreeCAD.Console.PrintError(translate("Arch","Unable to build the profile")+"\n") return # move and rotate the profile to the first point if hasattr(p,"CenterOfMass"): c = p.CenterOfMass else: c = p.BoundBox.Center delta = w.Vertexes[0].Point-c p.translate(delta) import Draft if Draft.getType(obj.Base) == "BezCurve": v1 = obj.Base.Placement.multVec(obj.Base.Points[1])-w.Vertexes[0].Point else: v1 = w.Vertexes[1].Point-w.Vertexes[0].Point v2 = DraftGeomUtils.getNormal(p) rot = FreeCAD.Rotation(v2,v1) p.rotate(w.Vertexes[0].Point,rot.Axis,math.degrees(rot.Angle)) shapes = [] try: if p.Faces: for f in p.Faces: sh = w.makePipeShell([f.OuterWire],True,False,2) for shw in f.Wires: if shw.hashCode() != f.OuterWire.hashCode(): sh2 = w.makePipeShell([shw],True,False,2) sh = sh.cut(sh2) shapes.append(sh) elif p.Wires: for pw in p.Wires: sh = w.makePipeShell([pw],True,False,2) shapes.append(sh) except Exception: FreeCAD.Console.PrintError(translate("Arch","Unable to build the pipe")+"\n") else: if len(shapes) == 0: return elif len(shapes) == 1: sh = shapes[0] else: sh = Part.makeCompound(shapes) obj.Shape = sh if obj.Base: obj.Length = w.Length else: obj.Placement = pl
def export_faces(filename, isDiel=False, name="", showNormals=False, forceMesh=False, folder=DEF_FOLDER): '''Export faces in FasterCap format as conductor or dielectric interface The function operates on the selection. The selection can be a face, a compound or a solid. 'filename' is the name of the export file 'isDiel' specifies if the mesh is a dielectric, so the function will add a reference point to each panel to indicate which is the external side (outside) 'name' is the name of the conductor created in the file. If not specified, defaults to the label of the first element in the selection set 'forceMesh' force the meshing of all faces, even if they could be exported non-meshed (triangular or quadrilateral faces). 'showNormals' will add a compound object composed by a set of arrows showing the normal direction for each panel 'folder' is the folder in which 'filename' will be saved Example: export_faces("mymesh.txt", folder="C:/temp") ''' # get selection sel = FreeCADGui.Selection.getSelection() # if no valid selection was passed if sel == None: return if name == "": condName = sel[0].Label.replace(" ", "_") else: condName = name # scan objects in selection and extract all faces faces = [] facets = [] for obj in sel: if obj.TypeId == "Mesh::Feature": facets.extend(obj.Mesh.Facets) else: if obj.Shape.ShapeType == "Face": faces.append(obj.Shape) elif obj.Shape.ShapeType == "Compound" or obj.Shape.ShapeType == "Solid": faces.extend(obj.Shape.Faces) # scan faces and find out which faces have more than 4 vertexes # TBD warning: should mesh also curve faces if forceMesh == False: facesComplex = [x for x in faces if len(x.Vertexes) >= 5] facesSimple = [x for x in faces if len(x.Vertexes) < 5] else: facesComplex = faces facesSimple = [] # mesh complex faces doc = FreeCAD.ActiveDocument for face in facesComplex: mesh = doc.addObject("Mesh::Feature", "Mesh") mesh.Mesh = MeshPart.meshFromShape(Shape=face, Fineness=0, SecondOrder=0, Optimize=1, AllowQuad=0) facets.extend(mesh.Mesh.Facets) # now we have faces and facets. Uniform all panels = [] for face in facesSimple: sortEdges = Part.__sortEdges__(face.Edges) # Point of a Vertex is a Vector, as well as Face.normalAt() points = [x.firstVertex().Point for x in sortEdges] panels.append([points, face.normalAt(0, 0)]) for facet in facets: points = [Vector(x) for x in facet.Points] panels.append([points, Vector(facet.Normal)]) if not os.path.isdir(folder): os.mkdir(folder) with open(folder + os.sep + filename, 'w') as fid: # write the preamble if isDiel == True: fid.write( "0 dielectric definition file for the following objects\n") else: fid.write( "0 conductor definition file for the following objects\n") for obj in sel: fid.write("* - " + obj.Label + "\n") fid.write("* created using FreeCAD's ElectroMagnetic workbench\n") fid.write( "* see http://www.freecad.org and http://www.fastfieldsolvers.com\n\n" ) arrows = [] # export faces for panel in panels: pointsNum = len(panel[0]) if pointsNum == 3: fid.write("T " + condName) elif pointsNum == 4: fid.write("Q " + condName) else: FreeCAD.Console.PrintMessage( "Unforeseen number of panel vertexes: " + pointsNum + ", skipping panel") continue center = Vector(0.0, 0.0, 0.0) avgSideLen = 0.0 for j, vertex in enumerate(panel[0]): fid.write(" ") for i in range(3): fid.write(" " + str(vertex[i])) if isDiel == True or showNormals == True: # 'point' is a tuple, transform in vector center = center + vertex # get side length side = panel[0][(j + 1) % 3] - vertex avgSideLen += side.Length if isDiel == True or showNormals == True: # calculate the reference point # (there should be a better way to divide a vector by a scalar..) center.multiply(1.0 / pointsNum) # and now move along the normal, proportional to the average facet dimension scaledNormal = panel[1] scaledNormal.multiply(avgSideLen / pointsNum) refpoint = center + scaledNormal if isDiel == True: fid.write(" ") for i in range(3): fid.write(" " + str(refpoint[i])) fid.write("\n") if showNormals == True: arrows.append(make_arrow(center, refpoint)) fid.closed if showNormals == True: # add the vector normals visualization to the view # Note: could also use Part.show(normals) but in this case we could # not give the (permanent) name to the object, only change the label afterwards normals = Part.makeCompound(arrows) normalobj = FreeCAD.ActiveDocument.addObject("Part::Feature", "Normals") normalobj.Shape = normals
def execute(self, obj): if self.clone(obj): return import Part, DraftGeomUtils pl = obj.Placement # test properties if not obj.Base: FreeCAD.Console.PrintLog(obj.Label + ": no base\n") return if not hasattr(obj.Base, "Shape"): FreeCAD.Console.PrintLog(obj.Label + ": invalid base\n") return if obj.VerticalMullionProfile: if not hasattr(obj.VerticalMullionProfile, "Shape"): FreeCAD.Console.PrintLog( obj.Label + ": invalid vertical mullion profile\n") return if obj.HorizontalMullionProfile: if not hasattr(obj.HorizontalMullionProfile, "Shape"): FreeCAD.Console.PrintLog( obj.Label + ": invalid horizontal mullion profile\n") return if obj.DiagonalMullionProfile: if not hasattr(obj.DiagonalMullionProfile, "Shape"): FreeCAD.Console.PrintLog( obj.Label + ": invalid diagonal mullion profile\n") return facets = [] faces = [] if obj.Base.Shape.Faces: faces = obj.Base.Shape.Faces elif obj.Height.Value and obj.VerticalDirection.Length: ext = FreeCAD.Vector(obj.VerticalDirection) ext.normalize() ext = ext.multiply(obj.Height.Value) faces = [edge.extrude(ext) for edge in obj.Base.Shape.Edges] if not faces: FreeCAD.Console.PrintLog(obj.Label + ": unable to build base faces\n") return # subdivide the faces into quads for face in faces: fp = face.ParameterRange # guessing horizontal/vertical directions vdir = obj.VerticalDirection if not vdir.Length: vdir = FreeCAD.Vector(0, 0, 1) vdir.normalize() basevector = face.valueAt(fp[1], fp[3]).sub(face.valueAt(fp[0], fp[2])) a = basevector.getAngle(vdir) if (a <= math.pi / 2 + ANGLETOLERANCE) and ( a >= math.pi / 2 - ANGLETOLERANCE): facedir = True vertsec = obj.VerticalSections horizsec = obj.HorizontalSections else: facedir = False vertsec = obj.HorizontalSections horizsec = obj.VerticalSections hstep = (fp[1] - fp[0]) if vertsec: hstep = hstep / vertsec vstep = (fp[3] - fp[2]) if horizsec: vstep = vstep / horizsec # construct facets for i in range(vertsec or 1): for j in range(horizsec or 1): p0 = face.valueAt(fp[0] + i * hstep, fp[2] + j * vstep) p1 = face.valueAt(fp[0] + (i + 1) * hstep, fp[2] + j * vstep) p2 = face.valueAt(fp[0] + (i + 1) * hstep, fp[2] + (j + 1) * vstep) p3 = face.valueAt(fp[0] + i * hstep, fp[2] + (j + 1) * vstep) facet = Part.Face(Part.makePolygon([p0, p1, p2, p3, p0])) facets.append(facet) if not facets: FreeCAD.Console.PrintLog(obj.Label + ": failed to subdivide shape\n") return baseshape = Part.makeShell(facets) # make edge/normal relation table edgetable = {} for face in baseshape.Faces: for edge in face.Edges: ec = edge.hashCode() if ec in edgetable: edgetable[ec].append(face) else: edgetable[ec] = [face] self.edgenormals = {} for ec, faces in edgetable.items(): if len(faces) == 1: self.edgenormals[ec] = faces[0].normalAt(0, 0) else: n = faces[0].normalAt(0, 0).add(faces[1].normalAt(0, 0)) if n.Length > 0.001: n.normalize() else: # adjacent faces have same normals n = faces[0].normalAt(0, 0) self.edgenormals[ec] = n # sort edges between vertical/horizontal hedges = [] vedges = [] for edge in baseshape.Edges: v = edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) a = v.getAngle(vdir) if (a <= math.pi / 2 + ANGLETOLERANCE) and ( a >= math.pi / 2 - ANGLETOLERANCE): hedges.append(edge) else: vedges.append(edge) # construct vertical mullions vmullions = [] vprofile = self.getMullionProfile(obj, "Vertical") if vprofile and vertsec: for vedge in vedges: vn = self.edgenormals[vedge.hashCode()] if (vn.x != 0) or (vn.y != 0): avn = FreeCAD.Vector(vn.x, vn.y, 0) rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0), avn) else: rot = FreeCAD.Rotation() if obj.VerticalMullionAlignment: ev = vedge.Vertexes[-1].Point.sub(vedge.Vertexes[0].Point) rot = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), ev).multiply(rot) vmullions.append( self.makeMullion(vedge, vprofile, rot, obj.CenterProfiles)) # construct horizontal mullions hmullions = [] hprofile = self.getMullionProfile(obj, "Horizontal") if hprofile and horizsec: for hedge in hedges: rot = FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -90) vn = self.edgenormals[hedge.hashCode()] if (vn.x != 0) or (vn.y != 0): avn = FreeCAD.Vector(vn.x, vn.y, 0) rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0), avn).multiply(rot) if obj.HorizontalMullionAlignment: rot = FreeCAD.Rotation(avn, vn).multiply(rot) hmullions.append( self.makeMullion(hedge, hprofile, rot, obj.CenterProfiles)) # construct panels panels = [] dedges = [] if obj.PanelThickness.Value: for face in baseshape.Faces: verts = [v.Point for v in face.OuterWire.OrderedVertexes] if len(verts) == 4: if DraftGeomUtils.isPlanar(verts): panel = self.makePanel(verts, obj.PanelThickness.Value) panels.append(panel) else: verts1 = [verts[0], verts[1], verts[2]] panel = self.makePanel(verts1, obj.PanelThickness.Value) panels.append(panel) verts2 = [verts[0], verts[2], verts[3]] panel = self.makePanel(verts2, obj.PanelThickness.Value) panels.append(panel) dedges.append(Part.makeLine(verts[0], verts[2])) # construct diagonal mullions dmullions = [] if dedges: n = (dedges[0].Vertexes[-1].Point.sub(dedges[0].Point)) dprofile = self.getMullionProfile(obj, "Diagonal") if dprofile: for dedge in dedges: rot = FreeCAD.Rotation( FreeCAD.Vector(0, 0, 1), dedge.Vertexes[-1].Point.sub(dedge.Vertexes[0].Point)) dmullions.append( self.makeMullion(dedge, dprofile, rot, obj.CenterProfiles)) # perform subtractions if obj.Refine: subvmullion = None subhmullion = None subdmullion = None if vmullions: subvmullion = vmullions[0].copy() for m in vmullions[1:]: subvmullion = subvmullion.fuse(m) if hmullions: subhmullion = hmullions[0].copy() for m in hmullions[1:]: subhmullion = subhmullion.fuse(m) if dmullions: subdmullion = dmullions[0].copy() for m in dmullions[1:]: subdmullion = subdmullion.fuse(m) if subvmullion: hmullions = [m.cut(subvmullion) for m in hmullions] if subhmullion: dmullions = [m.cut(subvmullion) for m in dmullions] dmullions = [m.cut(subhmullion) for m in dmullions] panels = [m.cut(subvmullion) for m in panels] panels = [m.cut(subhmullion) for m in panels] if subdmullion: panels = [m.cut(subdmullion) for m in panels] # mount shape obj.VerticalMullionNumber = len(vmullions) obj.HorizontalMullionNumber = len(hmullions) obj.DiagonalMullionNumber = len(dmullions) obj.PanelNumber = len(panels) shape = Part.makeCompound(vmullions + hmullions + dmullions + panels) shape = self.processSubShapes(obj, shape, pl) self.applyShape(obj, shape, pl)
def execute(self, obj): """This method is run when the object is created or recomputed.""" import Part if (obj.Length.Value == 0) or (obj.Height.Value == 0): obj.positionBySupport() return plm = obj.Placement shape = None if hasattr(obj, "Rows") and hasattr(obj, "Columns"): # TODO: verify if this is needed: if obj.Rows > 1: rows = obj.Rows else: rows = 1 if obj.Columns > 1: columns = obj.Columns else: columns = 1 # TODO: till here if (rows > 1) or (columns > 1): shapes = [] l = obj.Length.Value / columns h = obj.Height.Value / rows for i in range(columns): for j in range(rows): p1 = App.Vector(i * l, j * h, 0) p2 = App.Vector(p1.x + l, p1.y, p1.z) p3 = App.Vector(p1.x + l, p1.y + h, p1.z) p4 = App.Vector(p1.x, p1.y + h, p1.z) p = Part.makePolygon([p1, p2, p3, p4, p1]) if "ChamferSize" in obj.PropertiesList: if obj.ChamferSize.Value != 0: w = DraftGeomUtils.filletWire( p, obj.ChamferSize.Value, chamfer=True) if w: p = w if "FilletRadius" in obj.PropertiesList: if obj.FilletRadius.Value != 0: w = DraftGeomUtils.filletWire( p, obj.FilletRadius.Value) if w: p = w if hasattr(obj, "MakeFace"): if obj.MakeFace: p = Part.Face(p) shapes.append(p) if shapes: shape = Part.makeCompound(shapes) if not shape: p1 = App.Vector(0, 0, 0) p2 = App.Vector(p1.x + obj.Length.Value, p1.y, p1.z) p3 = App.Vector(p1.x + obj.Length.Value, p1.y + obj.Height.Value, p1.z) p4 = App.Vector(p1.x, p1.y + obj.Height.Value, p1.z) shape = Part.makePolygon([p1, p2, p3, p4, p1]) if "ChamferSize" in obj.PropertiesList: if obj.ChamferSize.Value != 0: w = DraftGeomUtils.filletWire(shape, obj.ChamferSize.Value, chamfer=True) if w: shape = w if "FilletRadius" in obj.PropertiesList: if obj.FilletRadius.Value != 0: w = DraftGeomUtils.filletWire(shape, obj.FilletRadius.Value) if w: shape = w if hasattr(obj, "MakeFace"): if obj.MakeFace: shape = Part.Face(shape) else: shape = Part.Face(shape) obj.Shape = shape if hasattr(obj, "Area") and hasattr(shape, "Area"): obj.Area = shape.Area obj.Placement = plm obj.positionBySupport()
def execute(self, obj): if self.clone(obj): return if len(obj.InList) != 1: return if Draft.getType(obj.InList[0]) != "Structure": return if not obj.InList[0].Shape: return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return if not obj.Diameter.Value: return if not obj.Amount: return father = obj.InList[0] wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print obj.Rounding if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value import DraftGeomUtils wire = DraftGeomUtils.filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) size = (ArchCommands.projectToVector(father.Shape.copy(), axis)).Length if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) #.normalize() # don't normalize so the vector can also be used to determine the distance size = axis.Length #print axis #print size if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: return # all tests ok! pl = obj.Placement import Part circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) except Part.OCCError: print "Arch: error sweeping rebar profile along the base sketch" return # building final shape shapes = [] if obj.Amount == 1: offset = DraftVecUtils.scaleTo(axis, size / 2) bar.translate(offset) shapes.append(bar) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) vinterval = DraftVecUtils.scaleTo(axis, interval) for i in range(obj.Amount): if i == 0: if baseoffset: bar.translate(baseoffset) shapes.append(bar) else: bar = bar.copy() bar.translate(vinterval) shapes.append(bar) if hasattr(obj, "Spacing"): obj.Spacing = interval if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription output += "(" + obj.Label + ")" if obj.Side != "On": output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print ("found a base object which is not a face. Can't continue.") return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def writeObject(self,obj,view): if not view.Source: return "" if obj.Renderer: try: renderer = importlib.import_module("renderers."+obj.Renderer) except ImportError: FreeCAD.Console.PrintError(translate("Render","Error importing renderer")+" "+str(obj.Renderer)) return "" else: # get color and alpha mat = None color = None alpha = None if view.Material: mat = view.Material else: if "Material" in view.Source.PropertiesList: if view.Source.Material: mat = view.Source.Material if mat: if "Material" in mat.PropertiesList: if "DiffuseColor" in mat.Material: color = mat.Material["DiffuseColor"].strip("(").strip(")").split(",")[:3] if "Transparency" in mat.Material: if float(mat.Material["Transparency"]) > 0: alpha = 1.0-float(mat.Material["Transparency"]) else: alpha = 1.0 if view.Source.ViewObject: if not color: if hasattr(view.Source.ViewObject,"ShapeColor"): color = view.Source.ViewObject.ShapeColor[:3] if not alpha: if hasattr(view.Source.ViewObject,"Transparency"): if view.Source.ViewObject.Transparency > 0: alpha = 1.0-(float(view.Source.ViewObject.Transparency)/100.0) if not color: color = (1.0, 1.0, 1.0) if not alpha: alpha = 1.0 # get mesh import Draft import Part import MeshPart mesh = None if hasattr(view.Source,"Group"): shps = [o.Shape for o in Draft.getGroupContents(view.Source) if hasattr(o,"Shape")] mesh = MeshPart.meshFromShape(Shape=Part.makeCompound(shps), LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False) elif view.Source.isDerivedFrom("Part::Feature"): mesh = MeshPart.meshFromShape(Shape=view.Source.Shape, LinearDeflection=0.1, AngularDeflection=0.523599, Relative=False) elif view.Source.isDerivedFrom("Mesh::Feature"): mesh = view.Source.Mesh if not mesh: return "" return renderer.writeObject(view,mesh,color,alpha)
def execute(self, fp): """ Called when a recomputation is needed. @param fp Part::FeaturePython object. """ fp.Shape = Part.makeCompound(fp.Shape.Solids)
def export_mesh(filename, meshobj=None, isDiel=False, showNormals=False, folder=DEF_FOLDER): '''Export mesh in FasterCap format as conductor or dielectric interface 'filename' is the name of the export file 'meshobj' must be a Mesh::Feature object 'isDiel' specifies if the mesh is a dielectric, so the function will add a reference point to each panel to indicate which is the external side (outside) 'showNormals' will add a compound object composed by a set of arrows showing the normal direction for each panel 'folder' is the folder in which 'filename' will be saved Example: mymeshGui = Gui.ActiveDocument.Mesh mymeshObj = mymeshGui.Object export_mesh("mymesh.txt", meshobj=mymeshObj, folder="C:/temp") ''' # if no valid mesh was passed if meshobj == None: return elif meshobj.TypeId != "Mesh::Feature": FreeCAD.Console.PrintMessage( "Error: 'meshobj' is not an object of type 'Mesh::Feature'") return if not os.path.isdir(folder): os.mkdir(folder) with open(folder + os.sep + filename, 'w') as fid: # write the preamble if isDiel == True: fid.write("0 dielectric definition file for mesh '" + meshobj.Label) else: fid.write("0 conductor definition file for mesh '" + meshobj.Label) fid.write("' created using FreeCAD's ElectroMagnetic workbench\n") fid.write( "* see http://www.freecad.org and http://www.fastfieldsolvers.com\n" ) fid.write("\n") # export facets arrows = [] condName = meshobj.Label.replace(" ", "_") for facet in meshobj.Mesh.Facets: if len(facet.Points) == 3: fid.write("T " + condName) elif len(facet.Points) == 4: fid.write("Q " + condName) else: FreeCAD.Console.PrintMessage( "Unforeseen number of mesh facet points: " + len(facet.Points) + ", skipping facet") continue center = Vector(0.0, 0.0, 0.0) avgSideLen = 0.0 for j, point in enumerate(facet.Points): fid.write(" ") for i in range(3): fid.write(" " + str(point[i])) if isDiel == True or showNormals == True: # 'point' is a tuple, transform in vector center = center + Vector(point) # get side length side = Vector(facet.Points[(j + 1) % 3]) - Vector(point) avgSideLen += side.Length if isDiel == True or showNormals == True: # calculate the reference point # (there should be a better way to divide a vector by a scalar..) center.multiply(1.0 / len(facet.Points)) # and now move along the normal, proportional to the average facet dimension scaledNormal = Vector(facet.Normal) scaledNormal.multiply(avgSideLen / len(facet.Points)) refpoint = center + scaledNormal if isDiel == True: fid.write(" ") for i in range(3): fid.write(" " + str(refpoint[i])) fid.write("\n") if showNormals == True: arrows.append(make_arrow(center, refpoint)) if showNormals == True: # add the vector normals visualization to the view # Note: could also use Part.show(normals) but in this case we could # not give the (permanent) name to the object, only change the label afterwards normals = Part.makeCompound(arrows) normalobj = FreeCAD.ActiveDocument.addObject( "Part::Feature", "Normals") normalobj.Shape = normals fid.closed
def find_poloidal_upper_and_lower_faces(front_face, back_face, envelope, envelope_front_face_id, envelope_back_face_id): list_of_edges_to_fillet = [] list_of_edge_to_fillet_ids = [] list_of_edge_to_fillet_lengths = [] for counter, edge in enumerate(front_face.Edges): if round(edge.Vertexes[0].Point.z - edge.Vertexes[1].Point.z) == 0: list_of_edges_to_fillet.append(edge) list_of_edge_to_fillet_ids.append(counter) list_of_edge_to_fillet_lengths.append(edge.Length) for counter, edge in enumerate(back_face.Edges): if round(edge.Vertexes[0].Point.z - edge.Vertexes[1].Point.z) == 0: list_of_edges_to_fillet.append(edge) list_of_edge_to_fillet_ids.append(counter) list_of_edge_to_fillet_lengths.append(edge.Length) faces_with_vectors_not_pointing_in_y = [] for i, face in enumerate(envelope.Faces): if i != envelope_front_face_id and i != envelope_back_face_id: #print(face.normalAt(0, 0)) if abs(face.normalAt(0, 0).y) < max(abs(face.normalAt(0, 0).x), abs(face.normalAt(0, 0).z)): faces_with_vectors_not_pointing_in_y.append(face) if len(faces_with_vectors_not_pointing_in_y) == 2: if faces_with_vectors_not_pointing_in_y[ 0].CenterOfMass.z > faces_with_vectors_not_pointing_in_y[ 1].CenterOfMass.z: return faces_with_vectors_not_pointing_in_y else: return faces_with_vectors_not_pointing_in_y[::-1] else: top_bottom_faces = [] for i, face in enumerate(envelope.Faces): if i != self.envelope_front_face_id and i != self.envelope_back_face_id: list_of_z_points = [] for vertexes in face.Vertexes: list_of_z_points.append(round(vertexes.Point.z, 1)) #print(' ',vertexes.Point.z) #print(list_of_z_points) number_of_matching_z_points = Counter(list_of_z_points) if number_of_matching_z_points.values() == [ 2, 2 ] or number_of_matching_z_points.values() == [4]: top_bottom_faces.append(face) if len(top_bottom_faces) == 2: if top_bottom_faces[0].CenterOfMass.Point.z > top_bottom_faces[ 1].CenterOfMass.Point.z: return top_bottom_faces else: return top_bottom_faces[::-1] else: Part.makeCompound(top_bottom_faces).exportStep( os.path.join(self.output_folder, 'error_top_bottom_faces.step')) Part.makeCompound([front_face]).exportStep( os.path.join(self.output_folder, 'error_top_bottom_faces_ff.step')) raise ValueError('method failed, on ' + self.envelope_directory_filename + ' to many or few faces found')
def execute(self, obj): import Part, math, DraftGeomUtils pl = obj.Placement self.baseface = None base = None if obj.Base and obj.Angles: w = None if obj.Base.isDerivedFrom("Part::Feature"): if (obj.Base.Shape.Faces and obj.Face): w = obj.Base.Shape.Faces[obj.Face - 1].Wires[0] elif obj.Base.Shape.Wires: w = obj.Base.Shape.Wires[0] if w: if w.isClosed(): self.profilsDico = [] self.shps = [] self.subVolshps = [] heights = [] edges = DraftGeomUtils.sortEdges(w.Edges) l = len(edges) print("le contour contient " + str(l) + " aretes") for i in range(l): self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i], obj.IdRel[i], obj.Overhang[i], obj.Thickness[i]) for i in range(l): self.calcMissingData(i) for i in range(l): self.calcEdgeGeometry(edges, i) for i in range(l): self.calcDraftEdges(i) for i in range(l): self.calcEave(i) for p in self.profilsDico: heights.append(p["height"]) obj.Heights = heights for i in range(l): self.getRoofPaneProject(i) profilCurrent = self.findProfil(i) midpoint = DraftGeomUtils.findMidpoint( profilCurrent["edge"]) ptsPaneProject = profilCurrent["points"] lp = len(ptsPaneProject) if lp != 0: #print FreeCAD.Vector(ptsPaneProject[0]) ptsPaneProject.append(ptsPaneProject[0]) edgesWire = [] for p in range(lp): edge = Part.makeLine(ptsPaneProject[p], ptsPaneProject[p + 1]) edgesWire.append(edge) wire = Part.Wire(edgesWire) d = wire.BoundBox.DiagonalLength thicknessV = profilCurrent["thickness"] / ( math.cos(math.radians(profilCurrent["angle"]))) overhangV = profilCurrent["overhang"] * math.tan( math.radians(profilCurrent["angle"])) if wire.isClosed(): f = Part.Face(wire) #Part.show(f) f = f.extrude( FreeCAD.Vector( 0, 0, profilCurrent["height"] + 2 * thicknessV + 2 * overhangV)) f.translate( FreeCAD.Vector(0.0, 0.0, -2 * overhangV)) ptsPaneProfil = [ FreeCAD.Vector(-profilCurrent["overhang"], -overhangV, 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0), FreeCAD.Vector( profilCurrent["run"], profilCurrent["height"] + thicknessV, 0.0), FreeCAD.Vector(-profilCurrent["overhang"], -overhangV + thicknessV, 0.0) ] self.createProfilShape(ptsPaneProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, self.shps, f) ## subVolume shape ptsSubVolumeProfil = [ FreeCAD.Vector(-profilCurrent["overhang"], -overhangV, 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"], 0.0), FreeCAD.Vector(profilCurrent["run"], profilCurrent["height"] + 10000, 0.0), FreeCAD.Vector(0.0, profilCurrent["height"] + 10000, 0.0) ] self.createProfilShape(ptsSubVolumeProfil, midpoint, profilCurrent["rot"], profilCurrent["vec"], profilCurrent["run"], d, self.subVolshps, f) ## SubVolume self.sub = self.subVolshps.pop() for s in self.subVolshps: self.sub = self.sub.fuse(s) self.sub = self.sub.removeSplitter() if not self.sub.isNull(): if not DraftGeomUtils.isNull(pl): self.sub.Placement = pl ## BaseVolume base = Part.makeCompound(self.shps) if not base.isNull(): if not DraftGeomUtils.isNull(pl): base.Placement = pl base = self.processSubShapes(obj, base) if base: if not base.isNull(): obj.Shape = base
def makeRibs(self, obj): pl = obj.Placement ribs = [] curvebox = FreeCAD.BoundBox(float("-inf"), float("-inf"), float("-inf"), float("inf"), float("inf"), float("inf")) for n in range(0, len(obj.Hullcurves)): cbbx = obj.Hullcurves[n].Shape.BoundBox if self.doScaleXYZ[n][0]: if cbbx.XMin > curvebox.XMin: curvebox.XMin = cbbx.XMin if cbbx.XMax < curvebox.XMax: curvebox.XMax = cbbx.XMax if self.doScaleXYZ[n][1]: if cbbx.YMin > curvebox.YMin: curvebox.YMin = cbbx.YMin if cbbx.YMax < curvebox.YMax: curvebox.YMax = cbbx.YMax if self.doScaleXYZ[n][2]: if cbbx.ZMin > curvebox.ZMin: curvebox.ZMin = cbbx.ZMin if cbbx.ZMax < curvebox.ZMax: curvebox.ZMax = cbbx.ZMax if curvebox.XMin == float("-inf"): curvebox.XMin = obj.Hullcurves[0].Shape.BoundBox.XMin if curvebox.XMax == float("inf"): curvebox.XMax = obj.Hullcurves[0].Shape.BoundBox.XMax if curvebox.YMin == float("-inf"): curvebox.YMin = obj.Hullcurves[0].Shape.BoundBox.YMin if curvebox.YMax == float("inf"): curvebox.YMax = obj.Hullcurves[0].Shape.BoundBox.YMax if curvebox.ZMin == float("-inf"): curvebox.ZMin = obj.Hullcurves[0].Shape.BoundBox.ZMin if curvebox.ZMax == float("inf"): curvebox.ZMax = obj.Hullcurves[0].Shape.BoundBox.ZMax areavec = Vector(curvebox.XLength, curvebox.YLength, curvebox.ZLength) deltavec = areavec.scale( obj.Axis.x, obj.Axis.y, obj.Axis.z) - (obj.OffsetStart + obj.OffsetEnd) * obj.Axis sections = int(obj.Items) startvec = Vector(curvebox.XMin, curvebox.YMin, curvebox.ZMin) if obj.Axis.x < 0: startvec.x = curvebox.XMax if obj.Axis.y < 0: startvec.y = curvebox.YMax if obj.Axis.z < 0: startvec.z = curvebox.ZMax pos0 = startvec + (obj.OffsetStart * obj.Axis) for x in range(0, sections): if sections > 1: d = CurvedShapes.distribute(x / (sections - 1), obj.Distribution, obj.DistributionReverse) posvec = pos0 + (deltavec * d) else: posvec = pos0 dolly = self.makeRib(obj, posvec) if dolly: if not obj.Twist == 0: dolly.rotate(dolly.BoundBox.Center, obj.Axis, obj.Twist * posvec.Length / areavec.Length) ribs.append(dolly) if (obj.Surface or obj.Solid) and obj.Items > 1: obj.Shape = CurvedShapes.makeSurfaceSolid(ribs, obj.Solid) else: obj.Shape = Part.makeCompound(ribs) obj.Placement = pl if self.extract: CompoundTools.Explode.explodeCompound(obj) obj.ViewObject.hide()
def createAnnotation(annotation,doc,ifcscale,preferences): """creates an annotation object""" anno = None if annotation.is_a("IfcGrid"): axes = [] uvwaxes = () if annotation.UAxes: uvwaxes = annotation.UAxes if annotation.VAxes: uvwaxes = uvwaxes + annotation.VAxes if annotation.WAxes: uvwaxes = uvwaxes + annotation.WAxes for axis in uvwaxes: if axis.AxisCurve: sh = get2DShape(axis.AxisCurve,ifcscale) if sh and (len(sh[0].Vertexes) == 2): # currently only straight axes are supported sh = sh[0] l = sh.Length pl = FreeCAD.Placement() pl.Base = sh.Vertexes[0].Point pl.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),sh.Vertexes[-1].Point.sub(sh.Vertexes[0].Point)) o = Arch.makeAxis(1,l) o.Length = l o.Placement = pl o.CustomNumber = axis.AxisTag axes.append(o) if axes: name = "Grid" grid_placement = None if annotation.Name: name = annotation.Name if six.PY2: name = name.encode("utf8") if annotation.ObjectPlacement: # https://forum.freecadweb.org/viewtopic.php?f=39&t=40027 grid_placement = getPlacement(annotation.ObjectPlacement,scaling=1) if preferences['PREFIX_NUMBERS']: name = "ID" + str(aid) + " " + name anno = Arch.makeAxisSystem(axes,name) if grid_placement: anno.Placement = grid_placement print(" axis") else: name = "Annotation" if annotation.Name: name = annotation.Name if six.PY2: name = name.encode("utf8") if "annotation" not in name.lower(): name = "Annotation " + name if preferences['PREFIX_NUMBERS']: name = "ID" + str(aid) + " " + name shapes2d = [] for rep in annotation.Representation.Representations: if rep.RepresentationIdentifier in ["Annotation","FootPrint","Axis"]: sh = get2DShape(rep,ifcscale) if sh in doc.Objects: # dirty hack: get2DShape might return an object directly if non-shape based (texts for ex) anno = sh else: shapes2d.extend(sh) if shapes2d: import Part sh = Part.makeCompound(shapes2d) #if preferences['DEBUG']: print(" shape") anno = doc.addObject("Part::Feature",name) anno.Shape = sh p = getPlacement(annotation.ObjectPlacement,ifcscale) if p: # and annotation.is_a("IfcAnnotation"): anno.Placement = p #else: #if preferences['DEBUG']: print(" no shape") return anno
def execute(self, obj): """ Compute the wall shape as boolean operations among the component objects """ # print("running " + obj.Name + " execute() method\n") import Part # gather base wall_shape (from obj.BaseGeometry or from default shape) wall_shape = None if hasattr(obj, "BaseGeometry") and obj.BaseGeometry: wall_shape = self.get_shape_from_base_geometry(obj) else: wall_shape = self.get_default_shape(obj) if wall_shape is None: return """ Perform boolean operations between the base shape and Additions, Subtractions, and Openings. Openings have to provide a proper shape to cut the wall through opening.Proxy.get_void_shape(opening) method that returns a Part Shape already in the right relative position. If the user wants to use a random shape to cut the wall he will use the Subtractions list. """ if hasattr(obj, "Additions") and obj.Additions: # get wall base shape from BaseGeometry objects shape_collection = [] for o in obj.Additions: if hasattr(o, "Shape") and not o.Shape.isNull(): shape_collection.append(o.Shape) if shape_collection: shape_collection.append(wall_shape) # TODO: Is it better to fuse the additions instead of grouping them with a compound? wall_shape = Part.makeCompound(shape_collection) # subtract Subtractions if hasattr(obj, "Subtractions") and obj.Subtractions: for o in obj.Subtractions: cut_shape = None if o in obj.Group and hasattr(o, "Shape"): # subtraction object is inside the wall relative_placement = o.Placement if hasattr(o, "InList") and o.InList[0] != obj: # dont' remember why this is necessary... relative_placement = o.InList[0].Placement.multiply(o.Placement) cut_shape = o.Shape.copy() cut_shape.Placement = relative_placement elif hasattr(o, "Shape"): # subtraction object is not inside the wall, compute it's correct relative placement global_placement = o.getGlobalPlacement() relative_placement = obj.getGlobalPlacement().inverse().multiply(global_placement) cut_shape = o.Shape.copy() cut_shape.Placement = relative_placement if cut_shape is not None: wall_shape = wall_shape.cut(cut_shape) if hasattr(obj, "Openings") and obj.Openings: # objects marked as Openings must be appropriate Opening objects to cut the wall # TODO: Add a flag to also subtract window positive shapes from wall for o in obj.Openings: # cut opening void void = None if o in obj.Group and hasattr(o, "VoidShape"): void = o.VoidShape.copy() elif hasattr(o, "VoidShape"): # opening object is not inside the wall, compute it's correct relative placement global_placement = o.getGlobalPlacement() relative_placement = obj.getGlobalPlacement().inverse().multiply(global_placement) void = o.VoidShape.copy() # void placement can be different from opening placement: void.Placement = relative_placement.multiply(o.Placement.inverse().multiply(void.Placement)) if void is not None: wall_shape = wall_shape.cut(void) obj.Shape = wall_shape
def execute(self, obj): if self.clone(obj): return if not obj.Base: FreeCAD.Console.PrintError( "No Base, return without a rebar shape for {}.\n".format( obj.Name)) return if not obj.Base.Shape: FreeCAD.Console.PrintError( "No Shape in Base, return without a rebar shape for {}.\n". format(obj.Name)) return if obj.Base.Shape.Faces: FreeCAD.Console.PrintError( "Faces in Shape of Base, return without a rebar shape for {}.\n" .format(obj.Name)) return if not obj.Base.Shape.Edges: FreeCAD.Console.PrintError( "No Edges in Shape of Base, return without a rebar shape for {}.\n" .format(obj.Name)) return if not obj.Diameter.Value: FreeCAD.Console.PrintError( "No Diameter Value, return without a rebar shape for {}.\n". format(obj.Name)) return if not obj.Amount: FreeCAD.Console.PrintError( "No Amount, return without a rebar shape for {}.\n".format( obj.Name)) return father = obj.Host fathershape = None if not father: # support for old-style rebars if obj.InList: if hasattr(obj.InList[0], "Armatures"): if obj in obj.InList[0].Armatures: father = obj.InList[0] if father: if hasattr(father, 'Shape'): fathershape = father.Shape import Part # corner cases: # compound from more Wires # compound without Wires but with multiple Edges # Does they make sense? If yes handle them. # Does it makes sense to handle Shapes with Faces or even Solids? if not obj.Base.Shape.Wires and len(obj.Base.Shape.Edges) == 1: wire = Part.Wire(obj.Base.Shape.Edges[0]) else: wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print(obj.Rounding) if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value from DraftGeomUtils import filletWire wire = filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) if fathershape: size = (ArchCommands.projectToVector(fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) axis.normalize() if fathershape: size = (ArchCommands.projectToVector( fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Distance"): if obj.Distance.Value: size = obj.Distance.Value spacinglist = None if hasattr(obj, "CustomSpacing"): if obj.CustomSpacing: spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing) influenceArea = sum( spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2 # Drop this check to solve issue as discussed here: https://github.com/FreeCAD/FreeCAD/pull/2550 # if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: # return # all tests ok! if hasattr(obj, "Length"): length = getLengthOfRebar(obj) if length: obj.Length = length pl = obj.Placement circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) basewire = wire.copy() except Part.OCCError: print("Arch: error sweeping rebar profile along the base sketch") return # building final shape shapes = [] placementlist = [] self.wires = [] rot = FreeCAD.Rotation() if obj.Amount == 1: if hasattr(obj, "RebarShape"): barplacement = CalculatePlacement( obj.Amount, 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value, obj.RebarShape) else: barplacement = CalculatePlacement(obj.Amount, 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None if hasattr(obj, "RebarShape") and obj.RebarShape == "Stirrup": interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value + obj.Diameter.Value) else: interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) for i in range(obj.Amount): if hasattr(obj, "RebarShape"): barplacement = CalculatePlacement(obj.Amount, i + 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value, obj.RebarShape) else: barplacement = CalculatePlacement(obj.Amount, i + 1, obj.Diameter.Value, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = interval # Calculate placement of bars from custom spacing. if spacinglist: placementlist[:] = [] if hasattr(obj, "RebarShape") and obj.RebarShape == "Stirrup": reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value + obj.Diameter.Value) else: reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) # Avoid unnecessary checks to pass like. For eg.: when we have values # like influenceArea is 100.00001 and reqInflueneArea is 100 if round(influenceArea) > round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Influence area of rebars is greater than " + str(reqInfluenceArea) + ".\n") elif round(influenceArea) < round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Last span is greater that end offset.\n") for i in range(len(spacinglist)): if i == 0: barplacement = CustomSpacingPlacement( spacinglist, 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) else: barplacement = CustomSpacingPlacement( spacinglist, i + 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) obj.Amount = len(spacinglist) obj.Spacing = 0 obj.PlacementList = placementlist for i in range(len(obj.PlacementList)): if i == 0: bar.Placement = obj.PlacementList[i] shapes.append(bar) basewire.Placement = obj.PlacementList[i] self.wires.append(basewire) else: bar = bar.copy() bar.Placement = obj.PlacementList[i] shapes.append(bar) w = basewire.copy() w.Placement = obj.PlacementList[i] self.wires.append(w) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl obj.TotalLength = obj.Length * len(obj.PlacementList)
def execute(self, obj): PathLog.track() if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return commandlist = [] toolLoad = obj.ToolController self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.SafeHeight.Value, step_down=obj.StepDown, z_finish_step=obj.FinishDepth.Value, final_depth=obj.FinalDepth.Value, user_depths=None) if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 commandlist.append(Path.Command("(" + obj.Label + ")")) # Facing is done either against base objects if obj.Base: PathLog.debug("obj.Base: {}".format(obj.Base)) faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) else: PathLog.debug('The base subobject is not a face') return planeshape = Part.makeCompound(faces) PathLog.info("Working on a collection of faces {}".format(faces)) # If no base object, do planing of top surface of entire model else: parentJob = PathUtils.findParentJob(obj) if parentJob is None: PathLog.debug("No base object. No parent job found") return baseobject = parentJob.Base if baseobject is None: PathLog.debug("Parent job exists but no Base Object") return planeshape = baseobject.Shape PathLog.info("Working on a shape {}".format(baseobject.Name)) # if user wants the boundbox, calculate that PathLog.info("Boundary Shape: {}".format(obj.BoundaryShape)) bb = planeshape.BoundBox if obj.BoundaryShape == 'Boundbox': bbperim = Part.makeBox(bb.XLength, bb.YLength, 1, FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin), FreeCAD.Vector(0, 0, 1)) env = PathUtils.getEnvelope(partshape=bbperim, depthparams=self.depthparams) else: env = PathUtils.getEnvelope(partshape=planeshape, depthparams=self.depthparams) # save the envelope for reference obj.removalshape = env try: commandlist.extend(self._buildPathArea(obj, env).Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError(translate("Path_MillFace", "The selected settings did not produce a valid path.\n")) # Let's finish by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) path = Path.Path(commandlist) obj.Path = path
def execute(self, obj): "constructs the shape of the stairs" import Part self.steps = [] self.pseudosteps = [] self.structures = [] pl = obj.Placement landings = 0 # base tests if not obj.Width.Value: return if not obj.Height.Value: if not obj.Base: return if obj.NumberOfSteps < 2: return if obj.Base: if not obj.Base.isDerivedFrom("Part::Feature"): return if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() obj.Placement = FreeCAD.Placement( obj.Base.Placement).multiply(pl) obj.TreadDepth = 0.0 obj.RiserHeight = 0.0 return if not obj.Base.Shape.Edges: return if obj.Base.Shape.Faces: return if (len(obj.Base.Shape.Edges) == 1): edge = obj.Base.Shape.Edges[0] if isinstance(edge.Curve, Part.Line): if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) else: if obj.Landings == "At center": landings = 1 self.makeCurvedStairsWithLandings(obj, edge) else: self.makeCurvedStairs(obj, edge) else: if not obj.Length.Value: return edge = Part.Line(Vector(0, 0, 0), Vector(obj.Length.Value, 0, 0)).toShape() if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) if self.structures or self.steps: shape = Part.makeCompound(self.structures + self.steps) shape = self.processSubShapes(obj, shape, pl) obj.Shape = shape obj.Placement = pl elif self.pseudosteps: shape = Part.makeCompound(self.pseudosteps) obj.Shape = shape obj.Placement = pl else: print "unable to calculate a stairs shape" # compute step data if obj.NumberOfSteps > 1: l = obj.Length.Value h = obj.Height.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength obj.TreadDepth = float(l - (landings * obj.Width.Value)) / ( obj.NumberOfSteps - (1 + landings)) obj.RiserHeight = float(h) / obj.NumberOfSteps obj.BlondelRatio = obj.RiserHeight.Value * 2 + obj.TreadDepth.Value
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] # pylint: disable=attribute-defined-outside-init baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock allTuples.append(tup) if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.debug( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] faceDepths = [] startDepths = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) # Add face depth to list faceDepths.append(shape.BoundBox.ZMin) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # Set initial Start and Final Depths and recalculate depthparams finDep = obj.FinalDepth.Value strDep = obj.StartDepth.Value if strDep > stock.Shape.BoundBox.ZMax: strDep = stock.Shape.BoundBox.ZMax startDepths.append(strDep) self.depthparams = self._customDepthParams(obj, strDep, finDep) for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: if obj.HandleMultipleFeatures == 'Collectively': custDepthparams = self.depthparams if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off': if profileshape.BoundBox.ZMin > obj.FinalDepth.Value: finDep = profileshape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finDep - 0.5) # only an envelope try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=custDepthparams) except Exception: # pylint: disable=broad-except # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate( 'Path', 'Unable to create path for face(s).')) else: tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) elif obj.HandleMultipleFeatures == 'Individually': for shape in faces: profShape = Part.makeCompound([shape]) finalDep = obj.FinalDepth.Value custDepthparams = self.depthparams if obj.Side == 'Inside': if finalDep < shape.BoundBox.ZMin: # Recalculate depthparams finalDep = shape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finalDep - 0.5) env = PathUtils.getEnvelope( base.Shape, subshape=profShape, depthparams=custDepthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finalDep shapes.append(tup) # Lower high Start Depth to top of Stock startDepth = max(startDepths) if obj.StartDepth.Value > startDepth: obj.StartDepth.Value = startDepth else: # Try to build targets from the job base if 1 == len(self.model): if hasattr(self.model[0], "Proxy"): PathLog.info("hasattr() Proxy") if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace( wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes # pylint: disable=attribute-defined-outside-init PathLog.debug("%d shapes" % len(shapes)) return shapes
def import_fastercap(filename, folder=DEF_FOLDER, use_mesh=True): '''Import file in FasterCap format as Mesh or Part.compound 'filename' is the name of the export file 'folder' is the folder where the file resides Example: fastercapObj = import_fastercap('cube.txt') ''' if not os.path.isdir(folder): FreeCAD.Console.PrintMessage("Error: '" + folder + "' is not a valid folder\n") return if not os.path.exists(folder + os.sep + filename): FreeCAD.Console.PrintMessage("Error: '" + filename + "' is not a valid file in the directory " + folder + "\n") return try: with open(folder + os.sep + filename, 'rb') as fid: # reset the list of triangle vertexes panelVertexes = [] chargeDensity = [] # and scan all the file for i, line in enumerate(fid): # if first line, or empty line, skip if i == 0 or line in ['', '\n', '\r\n']: continue # now check for actual statements # # first split the line into the components splitLine = line.split() # if the line was actually composed only by separators, continue if len(splitLine) == 0: continue # then check content # # if triangle if splitLine[0] == 'T': try: # if using mesh, we need a flat list of vertexed, that will be used in triplets # to build the triangular-only mesh faces if use_mesh == True: panelVertexes.extend( [ [float(splitLine[2]), float(splitLine[3]), float(splitLine[4])], [float(splitLine[5]), float(splitLine[6]), float(splitLine[7])], [float(splitLine[8]), float(splitLine[9]), float(splitLine[10])] ]) # if using faces, we need FreeCAD.Vector or tuple of three floats for each vertex, in a vector # with as many elements as the vertexes of the polygon supporting the face else: panelVertexes.append( [ (float(splitLine[2]), float(splitLine[3]), float(splitLine[4])), (float(splitLine[5]), float(splitLine[6]), float(splitLine[7])), (float(splitLine[8]), float(splitLine[9]), float(splitLine[10])) ]) except (IndexError, ValueError): FreeCAD.Console.PrintMessage("Error on line " + format(i) + " : " + line + "\n") # if there is trailing charge density information, store it if len(splitLine) >= 12: chargeDensity.append(float(splitLine[11])) # if quadrilateral if splitLine[0] == 'Q': try: if use_mesh == True: panelVertexes.extend( [ [float(splitLine[2]), float(splitLine[3]), float(splitLine[4])], [float(splitLine[5]), float(splitLine[6]), float(splitLine[7])], [float(splitLine[8]), float(splitLine[9]), float(splitLine[10])], [float(splitLine[2]), float(splitLine[3]), float(splitLine[4])], [float(splitLine[8]), float(splitLine[9]), float(splitLine[10])], [float(splitLine[11]), float(splitLine[12]), float(splitLine[13])] ]) # if there is trailing charge density information, store it if len(splitLine) >= 15: # add twice, as a quadrilateral panel spits into two triangles in a triangular mesh chargeDensity.extend([float(splitLine[14]), float(splitLine[14])]) else: panelVertexes.extend( [[ (float(splitLine[2]), float(splitLine[3]), float(splitLine[4])), (float(splitLine[5]), float(splitLine[6]), float(splitLine[7])), (float(splitLine[8]), float(splitLine[9]), float(splitLine[10])), (float(splitLine[11]), float(splitLine[12]), float(splitLine[13])) ]]) # if there is trailing charge density information, store it if len(splitLine) >= 15: chargeDensity.append(float(splitLine[14])) except ValueError: FreeCAD.Console.PrintMessage("Error on line " + format(i) + " : " + line + "\n") # if there is trailing charge density information, store it if len(splitLine) >= 15: chargeDensity.append(float(splitLine[14])) fid.closed except OSError as err: FreeCAD.Console.PrintMessage("OS error: " + format(err) + "\n") return if use_mesh == True: # now create the mesh. As of FreeCAD 0.16 we cannot color the mesh faces individually, # so we'll ignore the charge information, even if present fastercapMesh = Mesh.Mesh(panelVertexes) # and show it Mesh.show(fastercapMesh) return fastercapMesh else: # check if there is charge information if len(chargeDensity) > 0: # check if every panel has the info if len(chargeDensity) != len(panelVertexes): FreeCAD.Console.PrintMessage("\nWarning: charge densities vector has length " + format(len(chargeDensity)) + " while panels are " + format(len(panelVertexes))) chargeDensity = [] # create faces facelist = [] for panel in panelVertexes: # to create closed wires, the last point should be identical to the first wirepoly = Part.makePolygon(panel + [panel[0]]) face = Part.Face(wirepoly) facelist.append(face) # cannot use a shell, otherwise face order will be all scrambled up, # as Part will stitch faces when building the shell, cutting the # edges where there are other triangle vertexes in contact, and # doing so changes the face order #shellObj = Part.makeShell(facelist) # a compound instead will just contain a list of faces compObj = Part.makeCompound(facelist) # might use "Part.show(compObj)" but we need access to the Part::Feature 'featObj' # to be able to change its ViewObject properties doc = App.ActiveDocument partFeatObj = doc.addObject("Part::Feature","FasterCap_Compound") partFeatObj.Shape = compObj doc.recompute() # add density color if len(chargeDensity) > 0: # create colormap gradTable = [ (0.0, 1.0, 1.0), (0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (1.0, 1.0, 0.0)] colorMap = colormap(gradTable) # # create gradient table (debug only). Should implement using Pivy to have a fixed table at the side #~ facelist = [] #~ for i in range(0,256): #~ wirepoly = Part.makePolygon( [ (0.0, i*10.0, 0.0), (0.0, (i+1)*10.0, 0.0), (0.0, (i+1)*10.0, 50.0), #~ (0.0, i*10.0, 50.0), (0.0, i*10.0, 0.0) ] ) #~ face = Part.Face(wirepoly) #~ facelist.append(face) #~ shellGradObj = Part.makeShell(facelist) #~ gradObj = doc.addObject("Part::Feature","Gradient_Table") #~ gradObj.Shape = shellGradObj #~ doc.recompute() #~ gradObj.ViewObject.DiffuseColor = [colorMap[x] for x in range(0,256)] # end debug # # convert the charge density values into color indexes coeff = (COLORMAP_LEN - 1) / (max(chargeDensity) - min(chargeDensity)) partFeatObj.ViewObject.DiffuseColor = [colorMap[(int)((x-min(chargeDensity))*coeff)] for x in chargeDensity] return partFeatObj
def processSubShapes(self,obj,base,placement=None): "Adds additions and subtractions to a base shape" import Draft,Part #print("Processing subshapes of ",obj.Label, " : ",obj.Additions) if placement: if placement.isIdentity(): placement = None else: placement = FreeCAD.Placement(placement) placement = placement.inverse() # treat additions for o in obj.Additions: if not base: if o.isDerivedFrom("Part::Feature"): base = o.Shape else: if base.isNull(): if o.isDerivedFrom("Part::Feature"): base = o.Shape else: # special case, both walls with coinciding endpoints import ArchWall js = ArchWall.mergeShapes(o,obj) if js: add = js.cut(base) if placement: add.Placement = add.Placement.multiply(placement) base = base.fuse(add) elif o.isDerivedFrom("Part::Feature"): if o.Shape: if not o.Shape.isNull(): if o.Shape.Solids: s = o.Shape.copy() if placement: s.Placement = s.Placement.multiply(placement) if base: if base.Solids: try: base = base.fuse(s) except Part.OCCError: print("Arch: unable to fuse object ", obj.Name, " with ", o.Name) else: base = s # treat subtractions subs = obj.Subtractions for link in obj.InList: if hasattr(link,"Hosts"): for host in link.Hosts: if host == obj: subs.append(link) for o in subs: if base: if base.isNull(): base = None if base: if (Draft.getType(o) == "Window") or (Draft.isClone(o,"Window",True)): # windows can be additions or subtractions, treated the same way f = o.Proxy.getSubVolume(o) if f: if base.Solids and f.Solids: if placement: f.Placement = f.Placement.multiply(placement) if len(base.Solids) > 1: base = Part.makeCompound([sol.cut(f) for sol in base.Solids]) else: base = base.cut(f) elif (Draft.getType(o) == "Roof") or (Draft.isClone(o,"Roof")): # roofs define their own special subtraction volume f = o.Proxy.getSubVolume(o) if f: if base.Solids and f.Solids: if len(base.Solids) > 1: base = Part.makeCompound([sol.cut(f) for sol in base.Solids]) else: base = base.cut(f) elif o.isDerivedFrom("Part::Feature"): if o.Shape: if not o.Shape.isNull(): if o.Shape.Solids and base.Solids: s = o.Shape.copy() if placement: s.Placement = s.Placement.multiply(placement) try: if len(base.Solids) > 1: base = Part.makeCompound([sol.cut(s) for sol in base.Solids]) else: base = base.cut(s) except Part.OCCError: print("Arch: unable to cut object ",o.Name, " from ", obj.Name) return base
def execute(self, fp): b = fp.pin_circle_radius d = fp.roller_diameter e = fp.eccentricity n = fp.teeth_number p = b / n s = fp.segment_count ang = fp.pressure_angle_lim c = fp.pressure_angle_offset q = 2 * math.pi / float(s) # Find the pressure angle limit circles minAngle = -1.0 maxAngle = -1.0 for i in range(0, 180): x = self.calc_pressure_angle(p, d, n, i * math.pi / 180.) if (x < ang) and (minAngle < 0): minAngle = float(i) if (x < -ang) and (maxAngle < 0): maxAngle = float(i - 1) minRadius = self.calc_pressure_limit(p, d, e, n, minAngle * math.pi / 180.) maxRadius = self.calc_pressure_limit(p, d, e, n, maxAngle * math.pi / 180.) # unused # Wire(Part.makeCircle(minRadius,App.Vector(-e, 0, 0))) # Wire(Part.makeCircle(maxRadius,App.Vector(-e, 0, 0))) App.Console.PrintMessage("Generating cam disk\r\n") #generate the cam profile - note: shifted in -x by eccentricicy amount i = 0 x = self.calc_x(p, d, e, n, q * i / float(n)) y = self.calc_y(p, d, e, n, q * i / n) x, y = self.check_limit(x, y, maxRadius, minRadius, c) points = [App.Vector(x - e, y, 0)] for i in range(0, s): x = self.calc_x(p, d, e, n, q * (i + 1) / n) y = self.calc_y(p, d, e, n, q * (i + 1) / n) x, y = self.check_limit(x, y, maxRadius, minRadius, c) points.append([x - e, y, 0]) wi = make_bspline_wire([points]) wires = [] mat = App.Matrix() mat.move(App.Vector(e, 0., 0.)) mat.rotateZ(2 * np.pi / n) mat.move(App.Vector(-e, 0., 0.)) for _ in range(n): wi = wi.transformGeometry(mat) wires.append(wi) cam = Face(Wire(wires)) #add a circle in the center of the cam centerCircle = Face( Wire(Part.makeCircle(fp.hole_radius.Value, App.Vector(-e, 0, 0)))) cam = cam.cut(centerCircle) to_be_fused = [] if fp.show_disk0 == True: if fp.disk_height.Value == 0: to_be_fused.append(cam) else: to_be_fused.append( cam.extrude(App.Vector(0, 0, fp.disk_height.Value))) #secondary cam disk if fp.show_disk1 == True: App.Console.PrintMessage("Generating secondary cam disk\r\n") second_cam = cam.copy() mat = App.Matrix() mat.rotateZ(np.pi) mat.move(App.Vector(-e, 0, 0)) mat.rotateZ(np.pi / n) mat.move(App.Vector(e, 0, 0)) second_cam = second_cam.transformGeometry(mat) if fp.disk_height.Value == 0: to_be_fused.append(second_cam) else: to_be_fused.append( second_cam.extrude(App.Vector(0, 0, -fp.disk_height.Value))) #pins if fp.show_pins == True: App.Console.PrintMessage("Generating pins\r\n") pins = [] for i in range(0, n + 1): x = p * n * math.cos(2 * math.pi / (n + 1) * i) y = p * n * math.sin(2 * math.pi / (n + 1) * i) pins.append(Wire(Part.makeCircle(d / 2, App.Vector(x, y, 0)))) pins = Face(pins) z_offset = -fp.pin_height.Value / 2 if fp.center_pins == True: if fp.show_disk0 == True and fp.show_disk1 == False: z_offset += fp.disk_height.Value / 2 elif fp.show_disk0 == False and fp.show_disk1 == True: z_offset += -fp.disk_height.Value / 2 #extrude if z_offset != 0: pins.translate(App.Vector(0, 0, z_offset)) if fp.pin_height != 0: pins = pins.extrude(App.Vector(0, 0, fp.pin_height.Value)) to_be_fused.append(pins) if to_be_fused: fp.Shape = Part.makeCompound(to_be_fused)
def execute(self, obj): "creates the panel shape" if self.clone(obj): return import Part, DraftGeomUtils # base tests if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return elif obj.Base.isDerivedFrom("Mesh::Feature"): if not obj.Base.Mesh.isSolid(): return else: if obj.Length.Value: length = obj.Length.Value else: return if obj.Width.Value: width = obj.Width.Value else: return if obj.Thickness.Value: thickness = obj.Thickness.Value else: if not obj.Base: return elif obj.Base.isDerivedFrom("Part::Feature"): if not obj.Base.Shape.Solids: return # creating base shape pl = obj.Placement base = None normal = None if hasattr(obj, "Normal"): if obj.Normal.Length > 0: normal = Vector(obj.Normal) normal.normalize() normal.multiply(thickness) baseprofile = None if obj.Base: base = obj.Base.Shape.copy() if not base.Solids: p = FreeCAD.Placement(obj.Base.Placement) if base.Faces: baseprofile = base if not normal: normal = baseprofile.Faces[0].normalAt( 0, 0).multiply(thickness) base = base.extrude(normal) elif base.Wires: fm = False if hasattr(obj, "FaceMaker"): if obj.FaceMaker != "None": try: base = Part.makeFace( base.Wires, "Part::FaceMaker" + str(obj.FaceMaker)) fm = True except: FreeCAD.Console.PrintError( translate("Arch", "Facemaker returned an error") + "\n") return if not fm: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) if not normal: normal = baseprofile.normalAt( 0, 0).multiply(thickness) base = baseprofile.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if not normal: normal = Vector(0, 0, 1).multiply(thickness) l2 = length / 2 or 0.5 w2 = width / 2 or 0.5 v1 = Vector(-l2, -w2, 0) v2 = Vector(l2, -w2, 0) v3 = Vector(l2, w2, 0) v4 = Vector(-l2, w2, 0) base = Part.makePolygon([v1, v2, v3, v4, v1]) baseprofile = Part.Face(base) base = baseprofile.extrude(normal) if hasattr(obj, "Area"): if baseprofile: obj.Area = baseprofile.Area if hasattr(obj, "WaveLength"): if baseprofile and obj.WaveLength.Value and obj.WaveHeight.Value: # corrugated element bb = baseprofile.BoundBox bb.enlarge(bb.DiagonalLength) p1 = Vector(bb.getPoint(0).x, bb.getPoint(0).y, bb.Center.z) if obj.WaveType == "Curved": p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.Arc(p1, p2, p3).toShape() p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.Arc(p3, p4, p5).toShape() else: if obj.WaveHeight.Value < obj.WaveLength.Value: p2 = p1.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p4 = p3.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3, p4]) p5 = p4.add( Vector(obj.WaveHeight.Value, 0, -obj.WaveHeight.Value)) p6 = p5.add( Vector( obj.WaveLength.Value - 2 * obj.WaveHeight.Value, 0, 0)) p7 = p6.add( Vector(obj.WaveHeight.Value, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p4, p5, p6, p7]) else: p2 = p1.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) p3 = p2.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) e1 = Part.makePolygon([p1, p2, p3]) p4 = p3.add( Vector(obj.WaveLength.Value / 2, 0, -obj.WaveHeight.Value)) p5 = p4.add( Vector(obj.WaveLength.Value / 2, 0, obj.WaveHeight.Value)) e2 = Part.makePolygon([p3, p4, p5]) edges = [e1, e2] for i in range(int(bb.XLength / (obj.WaveLength.Value * 2))): e1 = e1.copy() e1.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) e2 = e2.copy() e2.translate(Vector(obj.WaveLength.Value * 2, 0, 0)) edges.extend([e1, e2]) basewire = Part.Wire(edges) baseface = basewire.extrude(Vector(0, bb.YLength, 0)) base = baseface.extrude(Vector(0, 0, thickness)) rot = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), normal) base.rotate(bb.Center, rot.Axis, math.degrees(rot.Angle)) if obj.WaveDirection.Value: base.rotate(bb.Center, normal, obj.WaveDirection.Value) n1 = normal.negative().normalize().multiply( obj.WaveHeight.Value * 2) self.vol = baseprofile.copy() self.vol.translate(n1) self.vol = self.vol.extrude(n1.negative().multiply(2)) base = self.vol.common(base) base = base.removeSplitter() if not base: FreeCAD.Console.PrintError( transpate("Arch", "Error computing shape of ") + obj.Label + "\n") return False if base and (obj.Sheets > 1) and normal and thickness: bases = [base] for i in range(1, obj.Sheets): n = FreeCAD.Vector(normal).normalize().multiply(i * thickness) b = base.copy() b.translate(n) bases.append(b) base = Part.makeCompound(bases) if base and normal and hasattr(obj, "Offset"): if obj.Offset.Value: v = DraftVecUtils.scaleTo(normal, obj.Offset.Value) base.translate(v) # process subshapes base = self.processSubShapes(obj, base, pl) # applying if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError( translate("Arch", "Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl
def execute(self,obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils base = None pl = obj.Placement extdata = self.getExtrusionData(obj) if extdata: bplates = extdata[0] extv = extdata[2].Rotation.multVec(extdata[1]) if isinstance(bplates,list): shps = [] for b in bplates: b.Placement = extdata[2].multiply(b.Placement) b = b.extrude(extv) shps.append(b) base = Part.makeCompound(shps) else: bplates.Placement = extdata[2].multiply(bplates.Placement) base = bplates.extrude(extv) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return elif obj.Base.Shape.Solids: base = obj.Base.Shape.copy() # blocks calculation elif hasattr(obj,"MakeBlocks") and hasattr(self,"basewires"): if obj.MakeBlocks and self.basewires and extdata and obj.Width and obj.BlockLength.Value and obj.BlockHeight.Value: #print "calculating blocks" if len(self.basewires) == 1: blocks = [] n = FreeCAD.Vector(extv) n.normalize() cuts1 = [] cuts2 = [] for i in range(2): if i == 0: offset = obj.OffsetFirst.Value else: offset = obj.OffsetSecond.Value for edge in self.basewires[0].Edges: while offset < (edge.Length-obj.Joint.Value): #print i," Edge ",edge," : ",edge.Length," - ",offset if offset: t = edge.tangentAt(offset) p = t.cross(n) p.multiply(1.1*obj.Width.Value) p1 = edge.valueAt(offset).add(p) p2 = edge.valueAt(offset).add(p.negative()) sh = Part.LineSegment(p1,p2).toShape() if obj.Joint.Value: sh = sh.extrude(t.multiply(obj.Joint.Value)) sh = sh.extrude(n) if i == 0: cuts1.append(sh) else: cuts2.append(sh) offset += (obj.BlockLength.Value+obj.Joint.Value) else: offset -= (edge.Length-obj.Joint.Value) if cuts1 and cuts2: if isinstance(bplates,list): bplates = bplates[0] fsize = obj.BlockHeight.Value+obj.Joint.Value bvec = FreeCAD.Vector(n) bvec.multiply(obj.BlockHeight.Value) svec = FreeCAD.Vector(n) svec.multiply(fsize) plate1 = bplates.cut(cuts1).Faces blocks1 = Part.makeCompound([f.extrude(bvec) for f in plate1]) plate2 = bplates.cut(cuts2).Faces blocks2 = Part.makeCompound([f.extrude(bvec) for f in plate2]) interval = extv.Length/(fsize) entires = int(interval) rest = (interval - entires) for i in range(entires): if i % 2: # odd b = blocks2.copy() else: b = blocks1.copy() if i: t = FreeCAD.Vector(svec) t.multiply(i) b.translate(t) blocks.append(b) if rest: rest = extv.Length-(entires*fsize) rvec = FreeCAD.Vector(n) rvec.multiply(rest) if entires % 2: b = Part.makeCompound([f.extrude(rvec) for f in plate2]) else: b = Part.makeCompound([f.extrude(rvec) for f in plate1]) t = FreeCAD.Vector(svec) t.multiply(entires) b.translate(t) blocks.append(b) if blocks: base = Part.makeCompound(blocks) else: FreeCAD.Console.PrintWarning(translate("Arch","Error computing block cuts for wall")+obj.Label+"\n") else: FreeCAD.Console.PrintWarning(translate("Arch","Cannot compute blocks for wall")+obj.Label+"\n") elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning(translate("Arch","This mesh is an invalid solid")+"\n") obj.Base.ViewObject.show() if not base: FreeCAD.Console.PrintError(translate("Arch","Error: Invalid base object")+"\n") return base = self.processSubShapes(obj,base,pl) self.applyShape(obj,base,pl) # count blocks if hasattr(obj,"MakeBlocks"): if obj.MakeBlocks: fvol = obj.BlockLength.Value * obj.BlockHeight.Value * obj.Width.Value if fvol: #print("base volume:",fvol) #for s in base.Solids: #print(abs(s.Volume - fvol)) ents = [s for s in base.Solids if abs(s.Volume - fvol) < 1] obj.CountEntire = len(ents) obj.CountBroken = len(base.Solids) - len(ents) else: obj.CountEntire = 0 obj.CountBroken = 0 # set the length property if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.Edges: if not obj.Base.Shape.Faces: if hasattr(obj.Base.Shape,"Length"): l = obj.Base.Shape.Length if obj.Length.Value != l: obj.Length = l
def execute(self, obj): if self.clone(obj): return if not obj.Base: return if not obj.Base.Shape: return if not obj.Base.Shape.Wires: return if not obj.Diameter.Value: return if not obj.Amount: return father = obj.Host fathershape = None if not father: # support for old-style rebars if obj.InList: if hasattr(obj.InList[0], "Armatures"): if obj in obj.InList[0].Armatures: father = obj.InList[0] if father: if father.isDerivedFrom("Part::Feature"): fathershape = father.Shape wire = obj.Base.Shape.Wires[0] if hasattr(obj, "Rounding"): #print(obj.Rounding) if obj.Rounding: radius = obj.Rounding * obj.Diameter.Value import DraftGeomUtils wire = DraftGeomUtils.filletWire(wire, radius) bpoint, bvec = self.getBaseAndAxis(wire) if not bpoint: return axis = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0, 0, -1)) if fathershape: size = (ArchCommands.projectToVector(fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Direction"): if not DraftVecUtils.isNull(obj.Direction): axis = FreeCAD.Vector(obj.Direction) axis.normalize() if fathershape: size = (ArchCommands.projectToVector( fathershape.copy(), axis)).Length else: size = 1 if hasattr(obj, "Distance"): if obj.Distance.Value: size = obj.Distance.Value spacinglist = None if hasattr(obj, "CustomSpacing"): if obj.CustomSpacing: spacinglist = strprocessOfCustomSpacing(obj.CustomSpacing) influenceArea = sum( spacinglist) - spacinglist[0] / 2 - spacinglist[-1] / 2 if (obj.OffsetStart.Value + obj.OffsetEnd.Value) > size: return # all tests ok! if hasattr(obj, "Length"): length = getLengthOfRebar(obj) if length: obj.Length = length pl = obj.Placement import Part circle = Part.makeCircle(obj.Diameter.Value / 2, bpoint, bvec) circle = Part.Wire(circle) try: bar = wire.makePipeShell([circle], True, False, 2) basewire = wire.copy() except Part.OCCError: print("Arch: error sweeping rebar profile along the base sketch") return # building final shape shapes = [] placementlist = [] self.wires = [] rot = FreeCAD.Rotation() if obj.Amount == 1: barplacement = CalculatePlacement(obj.Amount, 1, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = 0 else: if obj.OffsetStart.Value: baseoffset = DraftVecUtils.scaleTo(axis, obj.OffsetStart.Value) else: baseoffset = None interval = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) interval = interval / (obj.Amount - 1) for i in range(obj.Amount): barplacement = CalculatePlacement(obj.Amount, i + 1, size, axis, rot, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) if hasattr(obj, "Spacing"): obj.Spacing = interval # Calculate placement of bars from custom spacing. if spacinglist: placementlist[:] = [] reqInfluenceArea = size - (obj.OffsetStart.Value + obj.OffsetEnd.Value) # Avoid unnecessary checks to pass like. For eg.: when we have values # like influenceArea is 100.00001 and reqInflueneArea is 100 if round(influenceArea) > round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Influence area of rebars is greater than " + str(reqInfluenceArea) + ".\n") elif round(influenceArea) < round(reqInfluenceArea): FreeCAD.Console.PrintWarning( "Last span is greater that end offset.\n") for i in range(len(spacinglist)): if i == 0: barplacement = CustomSpacingPlacement( spacinglist, 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) else: barplacement = CustomSpacingPlacement( spacinglist, i + 1, axis, father.Placement.Rotation, obj.OffsetStart.Value, obj.OffsetEnd.Value) placementlist.append(barplacement) obj.Amount = len(spacinglist) obj.Spacing = 0 obj.PlacementList = placementlist for i in range(len(obj.PlacementList)): if i == 0: bar.Placement = obj.PlacementList[i] shapes.append(bar) basewire.Placement = obj.PlacementList[i] self.wires.append(basewire) else: bar = bar.copy() bar.Placement = obj.PlacementList[i] shapes.append(bar) w = basewire.copy() w.Placement = obj.PlacementList[i] self.wires.append(w) if shapes: obj.Shape = Part.makeCompound(shapes) obj.Placement = pl obj.TotalLength = obj.Length * len(obj.PlacementList)
def execute(self, obj): try: if 'glueT' in self.Type: h = obj.Height.Value if h <= 0: h = 0.01 else: # bottomSide h = -obj.Height.Value if h >= 0: h = -0.01 ## self.spisObiektowTXT = [] for i in obj.Base.Geometry: if i.Construction: continue if i.__class__.__name__ == 'LineSegment': x1 = i.StartPoint.x y1 = i.StartPoint.y x2 = i.EndPoint.x y2 = i.EndPoint.y # self.addLineWidth(x1, y1, x2, y2, obj.Width.Value) self.setFace(not obj.Flat, h * 1000) elif i.__class__.__name__ == 'Circle': x = i.Center.x y = i.Center.y r = i.Radius # self.addCircle(x, y, r, 0) self.setFace(not obj.Flat, h * 1000) elif i.__class__.__name__ == 'ArcOfCircle': curve = degrees(i.LastParameter - i.FirstParameter) points = i.discretize(Distance=i.length() / 2) if i.Circle.Axis.z < 0: p1 = [points[2].x, points[2].y] p2 = [points[0].x, points[0].y] else: p1 = [points[0].x, points[0].y] p2 = [points[2].x, points[2].y] p3 = [points[1].x, points[1].y] # mid point self.addArcWidth(p1, p2, curve, obj.Width.Value, p3) self.setFace(not obj.Flat, h * 1000) # if len(self.spisObiektowTXT) > 0: path = Part.makeCompound(self.spisObiektowTXT) # if obj.Flat == False: # path = path.extrude(FreeCAD.Base.Vector(0, 0, h)) obj.Shape = path else: obj.Shape = Part.Shape() obj.recompute() obj.Base.recompute() obj.purgeTouched() obj.Base.purgeTouched() obj.Placement.Base.z = obj.Base.Placement.Base.z obj.Volume = obj.Shape.Volume except Exception as e: FreeCAD.Console.PrintWarning(u"{0}\n".format(e))