def update(self, surf, direction, uv): """ Update the 3D view printing curve. @param self Auto call object. @param surf Surf where get the curve. @param direction 0 if u direction, 1 if v. @param uv Curve uv index, between 0 and 1. @return Curve from object (as Part::Feature). """ # Errors if not surf: return None # Get curve if direction == 0: curve = self.getU(surf, uv) elif direction == 1: curve = self.getV(surf, uv) else: return None # Draw at 3D view self.clean() Part.show(curve.toShape()) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs)-1] self.obj.Label = 'surfISOCurve' return self.obj
def update(self, draft, trim, ship): """ Update free surface 3D view @param traft Draft. @param trim Trim in degrees. """ # Destroy old object if exist self.clean() # Set free surface bounds bbox = ship.Shape.BoundBox L = 1.5 * bbox.XLength B = 3.0 * bbox.YLength # Create plane x = -0.5 * L y = -0.5 * B point = Base.Vector(x, y, 0.0) plane = Part.makePlane(L, B, point, Base.Vector(0, 0, 1)) # Set position plane.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 1, 0), trim) plane.translate(Base.Vector(0, 0, draft)) # Create the FreeCAD object Part.show(plane) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs) - 1] self.obj.Label = 'FreeSurface' # Set properties of object guiObj = FreeCADGui.ActiveDocument.getObject(self.obj.Name) guiObj.ShapeColor = (0.4, 0.8, 0.85) guiObj.Transparency = 50
def update(self, draft, trim, ship): """ Update free surface 3D view @param traft Draft. @param trim Trim in degrees. """ # Destroy old object if exist self.clean() # Set free surface bounds bbox = ship.Shape.BoundBox L = 1.5 * bbox.XLength B = 3.0 * bbox.YLength # Create plane x = - 0.5 * L y = - 0.5 * B point = Base.Vector(x,y,0.0) plane = Part.makePlane(L,B, point, Base.Vector(0,0,1)) # Set position plane.rotate(Base.Vector(0,0,0), Base.Vector(0,1,0), trim) plane.translate(Base.Vector(0,0,draft)) # Create the FreeCAD object Part.show(plane) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs)-1] self.obj.Label = 'FreeSurface' # Set properties of object guiObj = FreeCADGui.ActiveDocument.getObject(self.obj.Name) guiObj.ShapeColor = (0.4,0.8,0.85) guiObj.Transparency = 50
def mainFrameCoeff(ship, draft): """ Calculate main frame coefficient. @param ship Selected ship instance @param draft Draft. @return Main frame coefficient """ cm = 0.0 maxY = 0.0 minY = 0.0 # We will take a duplicate of ship shape in order to place it shape = ship.Shape.copy() shape.translate(Vector(0.0,0.0,-draft)) x = 0.0 area = 0.0 # Now we need to know the x range of values bbox = shape.BoundBox xmin = bbox.XMin xmax = bbox.XMax # Create the box L = xmax - xmin B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(1.5*L + x, 3.0*B, - bbox.ZMin + 1.0, p) # Compute common part with ship for s in shape.Solids: # Get solids intersection try: common = box.common(s) except: continue if common.Volume == 0.0: continue # Recompute object adding it to the scene, when we have # computed desired data we can remove it. try: Part.show(common) except: continue # Divide by faces and compute only section placed ones faces = common.Faces for f in faces: faceBounds = f.BoundBox # Orientation filter if faceBounds.XMax - faceBounds.XMin > 0.00001: continue # Place filter if abs(faceBounds.XMax - x) > 0.00001: continue # Valid face, compute area area = area + f.Area maxY = max(maxY, faceBounds.YMax) minY = max(minY, faceBounds.YMin) # Destroy last object generated App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name) dy = maxY - minY if dy*draft > 0.0: cm = area / (dy*draft) return cm
def buildObjs(self): """ Builds objects to show. """ Part.show(self.U) objs = FreeCAD.ActiveDocument.Objects self.objU = objs[len(objs)-1] Part.show(self.V) objs = FreeCAD.ActiveDocument.Objects self.objV = objs[len(objs)-1]
def upper_tabletop_2(d, dressup=True): m = Part.makeBox(d["length"], d["width"], d["upper_tabletop_t"]) m.translate(Base.Vector(-d["length"] / 2, -d["width"] / 2, 0)) m = dc.model.fillet_edges_by_length(m, 35, d["upper_tabletop_t"]) print("Upper tabletop length: ", d["length"]) print("Upper tabletop width: ", d["width"]) ccx = d["length"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) ccy = d["width"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) hx = ccx / 2.0 hy = ccy / 2.0 hole_points = [ Base.Vector(hx, hy, 0), Base.Vector(-hx, hy, 0), Base.Vector(-hx, -hy, 0), Base.Vector(hx, -hy, 0) ] a = 135 for p in hole_points: hole = Part.makeCylinder(d["hole_dia_tabletop"] / 2.0, d["upper_tabletop_t"], p, Base.Vector(0, 0, 1), 360) insert_1 = Part.makeBox(d["leg_t"], d["insertion_width_1"], d["insertion_length"]) insert_1 = dc.model.fillet_edges_by_length(insert_1, d["leg_edge_radii"], d["insertion_length"]) insert_1.translate(Base.Vector(-d["leg_t"] / 2, -d["cx"], 0)) insert_1.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), a) insert_1.translate(p) insert_2 = Part.makeBox(d["leg_t"], d["insertion_width_2"], d["insertion_length"]) insert_2 = dc.model.fillet_edges_by_length(insert_2, d["leg_edge_radii"], d["insertion_length"]) insert_2.translate( Base.Vector(-d["leg_t"] / 2, -d["insertion_width_3"] / 2.0, 0)) insert_2.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), a) insert_2.translate(p) m = m.cut(insert_1).cut(insert_2).cut(hole) a = a + 90 if dressup: m = dc.model.fillet_edges_longer_than(m, d["tabletop_edge_radii"], 300) m.translate(Base.Vector(0, 0, -d["upper_tabletop_t"])) return m
def _cutTopCurve(doc, obj, length, orientationBF, curveRadius): topCurvePlane = obj.newObject(_featureClassMapping["Plane"], "topCurvePlane") topCurvePlane.AttachmentOffset = App.Placement( App.Vector(0, 0, 0), App.Rotation(0, math.degrees(orientationBF), 0) # Yaw = x, Pitch = z, Roll = y (in deg) ) topCurvePlane.MapReversed = False topCurvePlane.Support = [(doc.YZ_Plane, '')] topCurvePlane.MapMode = "FlatFace" # Create bottom curve sketch topSketch = obj.newObject(_featureClassMapping["Sketch"], "topSketch") topSketch.Support = (topCurvePlane, '') topSketch.MapMode = "FlatFace" centerY = length / 2 - curveRadius # one topEdgeY = length / 2 + 1 topSketch.addGeometry( Part.ArcOfCircle( Part.Circle(App.Vector(0, centerY, 0), App.Vector(0, 0, 1), curveRadius), 0, math.pi), False) # (in radian) topSketch.addConstraint(Sketcher.Constraint('Radius', 0, curveRadius)) points = ((curveRadius, centerY), (curveRadius, topEdgeY), (-curveRadius, topEdgeY), (-curveRadius, centerY)) for i in range(len(points) - 1): topSketch.addGeometry( Part.LineSegment(App.Vector(*(points[i])), App.Vector(*(points[i + 1])))) topSketch.addConstraint(Sketcher.Constraint("Vertical", 1)) topSketch.addConstraint(Sketcher.Constraint("Horizontal", 2)) topSketch.addConstraint(Sketcher.Constraint("Vertical", 3)) coincidentPairs = ((0, 1, 1, 1), (0, 2, 3, 2), (1, 2, 2, 1), (2, 2, 3, 1)) for p in coincidentPairs: topSketch.addConstraint(Sketcher.Constraint("Coincident", *p)) topSketch.addConstraint( Sketcher.Constraint("DistanceY", -1, 1, 0, 3, centerY)) topSketch.addConstraint( Sketcher.Constraint("DistanceY", -1, -1, 1, 2, topEdgeY)) # Cut curve pocket = obj.newObject(_featureClassMapping["Pocket"], "topCurvePocket") pocket.Profile = topSketch pocket.Length = 5 pocket.Type = 1 pocket.UpToFace = None pocket.Reversed = 0 pocket.Midplane = 1 pocket.Offset = 0
def lower_tabletop_2(d, dressup=True): ccx = d["length"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) ccy = d["width"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) length = ccx + (2 * d["leg_distance_from_corner"] + d["insertion_width_3"]) / math.sqrt(2.0) width = ccy + (2 * d["leg_distance_from_corner"] + d["insertion_width_3"]) / math.sqrt(2.0) print("Lower tabletop length: ", length) print("Lower tabletop width: ", width) m = Part.makeBox(length, width, d["lower_tabletop_t"]) m.translate(Base.Vector(-length / 2.0, -width / 2.0, 0)) m = dc.model.fillet_edges_by_length(m, 35, d["lower_tabletop_t"]) hx = ccx / 2.0 hy = ccy / 2.0 hole_points = [ Base.Vector(hx, hy, 0), Base.Vector(-hx, hy, 0), Base.Vector(-hx, -hy, 0), Base.Vector(hx, -hy, 0) ] a = 45 for p in hole_points: hole = Part.makeCylinder(d["hole_dia_tabletop"] / 2.0, d["lower_tabletop_t"], p, Base.Vector(0, 0, 1), 360) insert = Part.makeBox(d["leg_t"], d["insertion_width_3"], d["insertion_length"]) insert = dc.model.fillet_edges_by_length(insert, d["leg_edge_radii"], d["insertion_length"]) insert.translate( Base.Vector(-d["leg_t"] / 2, -d["insertion_width_3"] / 2, 0)) insert.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), -a) insert.translate(p) m = m.cut(hole).cut(insert) a = a + 90 if dressup: m = dc.model.fillet_edges_longer_than(m, d["tabletop_edge_radii"], 150) m.translate(Base.Vector(0, 0, -d["lower_tabletop_t"])) return m
def load(): """ Loads the tool. Getting the border don't require any option, so can be executed directly without any task panel. """ edges = Geometry.getBorders() if not edges: wrn = Translator.translate("Can't get any edge from selected objects") FreeCAD.Console.PrintWarning(wrn) return obj = edges[0] for i in range(0, len(edges)): obj = obj.oldFuse(edges[i]) Part.show(obj) objs = FreeCAD.ActiveDocument.Objects obj = objs[len(objs) - 1] obj.Label = 'Border'
def load(): """ Loads the tool. Getting the border don't require any option, so can be executed directly without any task panel. """ edges = Geometry.getBorders() if not edges: wrn = Translator.translate("Can't get any edge from selected objects") FreeCAD.Console.PrintWarning(wrn) return obj = edges[0] for i in range(0,len(edges)): obj = obj.oldFuse(edges[i]) Part.show(obj) objs = FreeCAD.ActiveDocument.Objects obj = objs[len(objs)-1] obj.Label = 'Border'
def _createCylinder(doc, obj, cylindricalRadius, length, hasTopCurve, hasBottomCurve, addition=0.001): sketch = obj.newObject(_featureClassMapping["Sketch"], "cylinderSketch") sketch.Support = (doc.XY_Plane, ['']) sketch.MapMode = "FlatFace" sketch.addGeometry( Part.Circle(App.Vector(0, 0, 0), App.Vector(0, 0, 1), cylindricalRadius), False) sketch.addConstraint(Sketcher.Constraint('Radius', 0, cylindricalRadius)) # Extrude face pad = obj.newObject(_featureClassMapping["Pad"], "cylinderPad") pad.Profile = sketch pad.Type = 4 pad.Length = length / 2 + (addition if hasTopCurve else 0) pad.Length2 = length / 2 + (addition if hasBottomCurve else 0) pad.UpToFace = None pad.Reversed = 0 pad.Midplane = 0 pad.Offset = 0.0
def wettedArea(shape, draft, trim): """ Calculate wetted ship area. @param shape Ship external faces instance. @param draft Draft. @param trim Trim in degrees. @return Wetted ship area. """ area = 0.0 nObjects = 0 # We will take a duplicate of ship shape in order to place it shape = shape.copy() shape.translate(Vector(0.0,0.0,-draft)) shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,-1.0,0.0), trim) # Now we need to know the x range of values bbox = shape.BoundBox xmin = bbox.XMin xmax = bbox.XMax # Create the box L = xmax - xmin B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(3.0*L, 3.0*B, - bbox.ZMin + 1.0, p) # Compute common part with ship for f in shape.Faces: # Get solids intersection try: common = box.common(f) except: continue area = area + common.Area return area
def __init__(self, obj, solids): """ Creates a new ship on active document. @param obj Part::FeaturePython created object. @param faces Ship solids components. """ # Add uniqueness property to identify Ship instances obj.addProperty( "App::PropertyBool", "IsShip", "Ship", str(Translator.translate( "True if is a valid ship instance"))).IsShip = True # Add main dimensions obj.addProperty( "App::PropertyLength", "Length", "Ship", str(Translator.translate("Ship length (Lpp) [m]"))).Length = 0.0 obj.addProperty( "App::PropertyLength", "Beam", "Ship", str(Translator.translate("Ship beam (B) [m]"))).Beam = 0.0 obj.addProperty( "App::PropertyLength", "Draft", "Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft = 0.0 # Add shapes obj.Shape = Part.makeCompound(solids) obj.addProperty("Part::PropertyPartShape", "ExternalFaces", "Ship", str(Translator.translate("Ship only external faces"))) obj.Proxy = self
def glasstop(d, dressup=True): m = Part.makeBox(d["length"], d["width"], d["glass_t"]) m.translate(Base.Vector(-d["length"] / 2, -d["width"] / 2, -d["glass_t"])) if dressup: m = dc.model.chamfer_edges_longer_than(m, 2, 100) return m
def _cutBottomCurve(doc, obj, length, curveRadius): # Create bottom curve sketch bottomSketch = obj.newObject(_featureClassMapping["Sketch"], "bottomSketch") bottomSketch.Support = (doc.YZ_Plane, '') bottomSketch.MapMode = "FlatFace" centerY = curveRadius - length / 2 bottomEdgeY = -(length / 2 + 1) bottomSketch.addGeometry( Part.ArcOfCircle( Part.Circle(App.Vector(0, centerY, 0), App.Vector(0, 0, 1), curveRadius), -math.pi, 0), False) # (in radian) bottomSketch.addConstraint(Sketcher.Constraint('Radius', 0, curveRadius)) points = [(-curveRadius, centerY), (-curveRadius, bottomEdgeY), (curveRadius, bottomEdgeY), (curveRadius, centerY)] for i in range(len(points) - 1): bottomSketch.addGeometry( Part.LineSegment(App.Vector(*(points[i])), App.Vector(*(points[i + 1])))) bottomSketch.addConstraint(Sketcher.Constraint("Vertical", 1)) bottomSketch.addConstraint(Sketcher.Constraint("Horizontal", 2)) bottomSketch.addConstraint(Sketcher.Constraint("Vertical", 3)) coincidentPairs = ((0, 1, 1, 1), (0, 2, 3, 2), (1, 2, 2, 1), (2, 2, 3, 1)) for p in coincidentPairs: bottomSketch.addConstraint(Sketcher.Constraint("Coincident", *p)) bottomSketch.addConstraint( Sketcher.Constraint("DistanceY", -1, 1, 0, 3, centerY)) bottomSketch.addConstraint( Sketcher.Constraint("DistanceY", -1, -1, 1, 2, bottomEdgeY)) # Cut curve pocket = obj.newObject(_featureClassMapping["Pocket"], "bottomCurvePocket") pocket.Profile = bottomSketch pocket.Length = 5 pocket.Type = 1 pocket.UpToFace = None pocket.Reversed = 0 pocket.Midplane = 1 pocket.Offset = 0
def saveData(self, ship, trim, drafts): """ Write data file. @param ship Selected ship instance @param trim Trim in degrees. @param drafts List of drafts to be performed. @return True if error happens. """ # Open the file filename = self.path + 'hydrostatics.dat' try: Output = open(filename, "w") except IOError: msg = Translator.translate("Can't write '" + filename + "' file.\n") FreeCAD.Console.PrintError(msg) return True # Print header Output.write(header) Output.write(" #\n") Output.write(" # File automatically exported by FreeCAD-Ship\n") Output.write(" # This file contains transversal areas data, filled with following columns:\n") Output.write(" # 1: Ship displacement [ton]\n") Output.write(" # 2: Draft [m]\n") Output.write(" # 3: Wetted surface [m2]\n") Output.write(" # 4: 1cm triming ship moment [ton m]\n") Output.write(" # 5: Bouyance center x coordinate\n") Output.write(" # 6: Floating area\n") Output.write(" # 7: KBt\n") Output.write(" # 8: BMt\n") Output.write(" # 9: Cb (block coefficient)\n") Output.write(" # 10: Cf (Floating coefficient)\n") Output.write(" # 11: Cm (Main frame coefficient)\n") Output.write(" #\n") Output.write(" #################################################################\n") # Get external faces faces = self.externalFaces(ship.Shape) if len(faces) == 0: msg = Translator.translate("Can't detect external faces from ship object.\n") FreeCAD.Console.PrintError(msg) else: faces = Part.makeShell(faces) # Print data FreeCAD.Console.PrintMessage("Computing hydrostatics...\n") for i in range(0,len(drafts)): FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(drafts))) draft = drafts[i] point = Tools.Point(ship,faces,draft,trim) string = "%f %f %f %f %f %f %f %f %f %f %f\n" % (point.disp, point.draft, point.wet, point.mom, point.xcb, point.farea, point.KBt, point.BMt, point.Cb, point.Cf, point.Cm) Output.write(string) # Close file Output.close() self.dataFile = filename msg = Translator.translate("Data saved at '" + self.dataFile + "'.\n") FreeCAD.Console.PrintMessage(msg) return False
def update(self, surf, direction, r): """ Update the 3D view printing curve. @param surf Surf where get the curve. @param direction Slice plane normal vector. @param r Absolute position at Slice plane normal direction. @return Curve from object (as Part::Feature). """ # Errors if not surf: return None # Get curve curve = self.getSlice(surf, direction, r) # Draw at 3D view self.clean() self.objs = [] for i in range(0, len(curve)): for j in range(0, len(curve[i])): Part.show(curve[i][j]) objs = FreeCAD.ActiveDocument.Objects objs[len(objs) - 1].Label = 'surfSliceCurve' self.objs.append(objs[len(objs) - 1]) return self.objs
def create_line(start, stop): """ Creates and returns a FreeCAD line from a given set of start and stop coordinates Expects start and stop to be numpy arrays """ assert start.shape == (3, ) or start.shape == (1, 3) assert stop.shape == (3, ) or stop.shape == (1, 3) assert any(np.not_equal( start, stop)), "Start and stop coordinate should not be identical" start = tuple(start) stop = tuple(stop) return Part.makeLine(start, stop)
def update(self, surf, direction, r): """ Update the 3D view printing curve. @param surf Surf where get the curve. @param direction Slice plane normal vector. @param r Absolute position at Slice plane normal direction. @return Curve from object (as Part::Feature). """ # Errors if not surf: return None # Get curve curve = self.getSlice(surf, direction, r) # Draw at 3D view self.clean() self.objs = [] for i in range(0,len(curve)): for j in range(0,len(curve[i])): Part.show(curve[i][j]) objs = FreeCAD.ActiveDocument.Objects objs[len(objs)-1].Label = 'surfSliceCurve' self.objs.append(objs[len(objs)-1]) return self.objs
def __init__(self, obj, faces): """ Creates a new ship on active document. @param faces Ship faces (Part::Shape entities). """ # Add uniqueness property to identify Ship instances obj.addProperty("App::PropertyBool","IsShip","Ship", str(Translator.translate("True if is a valid ship instance"))).IsShip=True # Add main dimensions obj.addProperty("App::PropertyLength","Length","Ship", str(Translator.translate("Ship length (Lpp) [m]"))).Length=0.0 obj.addProperty("App::PropertyLength","Beam","Ship", str(Translator.translate("Ship beam (B) [m]"))).Beam=0.0 obj.addProperty("App::PropertyLength","Draft","Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft=0.0 # Add shapes obj.Shape = Part.makeShell(faces) obj.Proxy = self self.obj = obj
def __init__(self, obj, solids): """ Creates a new ship on active document. @param obj Part::FeaturePython created object. @param faces Ship solids components. """ # Add uniqueness property to identify Ship instances obj.addProperty("App::PropertyBool","IsShip","Ship", str(Translator.translate("True if is a valid ship instance"))).IsShip=True # Add main dimensions obj.addProperty("App::PropertyLength","Length","Ship", str(Translator.translate("Ship length (Lpp) [m]"))).Length=0.0 obj.addProperty("App::PropertyLength","Beam","Ship", str(Translator.translate("Ship beam (B) [m]"))).Beam=0.0 obj.addProperty("App::PropertyLength","Draft","Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft=0.0 # Add shapes obj.Shape = Part.makeCompound(solids) obj.addProperty("Part::PropertyPartShape","ExternalFaces","Ship", str(Translator.translate("Ship only external faces"))) obj.Proxy = self
def process(self): if not self.outputs['Compound'].is_linked: return if not any(sock.is_linked for sock in self.inputs): return solids_s = self.inputs['Solids'].sv_get(default=[[None]]) curves_s = self.inputs['Curves'].sv_get(default=[[None]]) surfaces_s = self.inputs['Surfaces'].sv_get(default=[[None]]) if self.inputs['Solids'].is_linked: solids_s = ensure_nesting_level(solids_s, 2, data_types=(Part.Shape, )) solids_level = get_data_nesting_level( solids_s, data_types=(Part.Shape, )) else: solids_level = 2 if self.inputs['Curves'].is_linked: curves_s = ensure_nesting_level(curves_s, 2, data_types=(SvCurve, )) curves_level = get_data_nesting_level(curves_s, data_types=(SvCurve, )) else: curves_level = 2 if self.inputs['Surfaces'].is_linked: surfaces_s = ensure_nesting_level(surfaces_s, 2, data_types=(SvSurface, )) surfaces_level = get_data_nesting_level( surfaces_s, data_types=(SvSurface, )) else: surfaces_level = 2 max_level = max(solids_level, curves_level, surfaces_level) compounds_out = [] for solids, curves, surfaces in zip_long_repeat( solids_s, curves_s, surfaces_s): shapes = solids + curves + surfaces shapes = [to_solid(s) for s in shapes if s is not None] compound = Part.Compound(shapes) compounds_out.append(compound) self.outputs['Compound'].sv_set(compounds_out)
def _cutThroughHole(doc, obj, orientation, distFromAxis, holeRadius): x = distFromAxis * math.cos(orientation) y = distFromAxis * math.sin(orientation) sketch = obj.newObject(_featureClassMapping["Sketch"], "cylinderSketch") sketch.Support = (doc.XY_Plane, ['']) sketch.MapMode = "FlatFace" holeCircle = sketch.addGeometry( Part.Circle(App.Vector(0, 0), App.Vector(0, 0, 1), 1)) sketch.addConstraint(Sketcher.Constraint('Radius', 0, holeRadius)) sketch.addConstraint(Sketcher.Constraint('DistanceX', -1, 1, 0, 3, x)) sketch.addConstraint(Sketcher.Constraint('DistanceY', -1, 1, 0, 3, y)) pocket = obj.newObject(_featureClassMapping["Pocket"], "holeCut") pocket.Profile = sketch pocket.Type = 1 pocket.Midplane = 1 pocket.Offset = 0
def execute(self, context): node = self.get_node(context) if not node: return {'CANCELLED'} if not node.inputs['Folder Path'].is_linked: self.report({'WARNING'}, "Folder path is not specified") return {'FINISHED'} if not node.inputs['Solids'].is_linked: self.report({'WARNING'}, "Object to be exported is not specified") return {'FINISHED'} folder_path = node.inputs[0].sv_get()[0][0] objects = node.inputs['Solids'].sv_get() #objects = flatten_data(objects, data_types=(Part.Shape, SvCurve, SvSurface)) base_name = node.base_name if not base_name: base_name = "sv_solid" for i, shape in enumerate(objects): #shape = map_recursive(to_solid, object, data_types=(Part.Shape, SvCurve, SvSurface)) debug("Exporting", shape) if isinstance(shape, (list, tuple)): shape = flatten_data(shape, data_types=(Part.Shape, )) if isinstance(shape, (list, tuple)): debug("Make compound:", shape) shape = Part.Compound(shape) file_path = folder_path + base_name + "_" + "%05d" % i if node.mode == "BREP": file_path += ".brp" shape.exportBrep(file_path) elif node.mode == "IGES": file_path += ".igs" shape.exportIges(file_path) else: file_path += ".stp" shape.exportStep(file_path) self.report({'INFO'}, f"Saved object #{i} to {file_path}") return {'FINISHED'}
def __init__(self, obj, faces): """ Creates a new ship on active document. @param faces Ship faces (Part::Shape entities). """ # Add uniqueness property to identify Ship instances obj.addProperty( "App::PropertyBool", "IsShip", "Ship", str(Translator.translate( "True if is a valid ship instance"))).IsShip = True # Add main dimensions obj.addProperty( "App::PropertyLength", "Length", "Ship", str(Translator.translate("Ship length (Lpp) [m]"))).Length = 0.0 obj.addProperty( "App::PropertyLength", "Beam", "Ship", str(Translator.translate("Ship beam (B) [m]"))).Beam = 0.0 obj.addProperty( "App::PropertyLength", "Draft", "Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft = 0.0 # Add shapes obj.Shape = Part.makeShell(faces) obj.Proxy = self self.obj = obj
def update(self, L, B, T): """ Update the 3D view printing annotations. @param L Ship length. @param B Ship beam. @param T Ship draft. """ # Destroy all previous entities self.clean() # Draw base line xStart = -0.6 * L xEnd = 0.6 * L baseLine = Part.makeLine((xStart, 0, 0), (xEnd, 0, 0)) Part.show(baseLine) objs = FreeCAD.ActiveDocument.Objects self.baseLine = objs[len(objs) - 1] self.baseLine.Label = 'BaseLine' self.baseLineLabel = DrawText('BaseLineText', str(Translator.translate('Base line')), Base.Vector(xEnd, 0, 0)) # Draw free surface fsLine = Part.makeLine((xStart, 0, T), (xEnd, 0, T)) Part.show(fsLine) objs = FreeCAD.ActiveDocument.Objects self.fsLine = objs[len(objs) - 1] self.fsLine.Label = 'FreeSurface' self.fsLineLabel = DrawText('FSText', str(Translator.translate('Free surface')), Base.Vector(xEnd, 0, T)) # Draw forward perpendicular zStart = -0.1 * T zEnd = 1.1 * T fpLine = Part.makeLine((0.5 * L, 0, zStart), (0.5 * L, 0, zEnd)) Part.show(fpLine) objs = FreeCAD.ActiveDocument.Objects self.fpLine = objs[len(objs) - 1] self.fpLine.Label = 'ForwardPerpendicular' self.fpLineLabel = DrawText( 'FPText', str(Translator.translate('Forward perpendicular')), Base.Vector(0.5 * L, 0, zEnd)) # Draw after perpendicular apLine = Part.makeLine((-0.5 * L, 0, zStart), (-0.5 * L, 0, zEnd)) Part.show(apLine) objs = FreeCAD.ActiveDocument.Objects self.apLine = objs[len(objs) - 1] self.apLine.Label = 'AfterPerpendicular' self.apLineLabel = DrawText( 'APText', str(Translator.translate('After perpendicular')), Base.Vector(-0.5 * L, 0, zEnd)) # Draw amin frame amLine = Part.makeLine((0, -0.5 * B, zStart), (0, -0.5 * B, zEnd)) Part.show(amLine) objs = FreeCAD.ActiveDocument.Objects self.amLine = objs[len(objs) - 1] self.amLine.Label = 'AminFrame' self.amLineLabel = DrawText('AMText', str(Translator.translate('Amin frame')), Base.Vector(0, -0.5 * B, zEnd))
def execute(self, obj): ''' Print a short message when doing a recomputation, this method is mandatory ''' # FreeCAD.Console.PrintMessage("Recompute Ship\n") obj.Shape = Part.makeShell(obj.Shape.Faces)
def update(self, L, B, T): """ Update the 3D view printing annotations. @param L Ship length. @param B Ship beam. @param T Ship draft. """ # Destroy all previous entities self.clean() # Draw base line xStart = -0.6*L; xEnd = 0.6*L; baseLine = Part.makeLine((xStart,0,0),(xEnd,0,0)) Part.show(baseLine) objs = FreeCAD.ActiveDocument.Objects self.baseLine = objs[len(objs)-1] self.baseLine.Label = 'BaseLine' self.baseLineLabel = DrawText('BaseLineText', str(Translator.translate('Base line')), Base.Vector(xEnd,0,0)) # Draw free surface fsLine = Part.makeLine((xStart,0,T),(xEnd,0,T)) Part.show(fsLine) objs = FreeCAD.ActiveDocument.Objects self.fsLine = objs[len(objs)-1] self.fsLine.Label = 'FreeSurface' self.fsLineLabel = DrawText('FSText', str(Translator.translate('Free surface')), Base.Vector(xEnd,0,T)) # Draw forward perpendicular zStart = -0.1*T zEnd = 1.1*T fpLine = Part.makeLine((0.5*L,0,zStart),(0.5*L,0,zEnd)) Part.show(fpLine) objs = FreeCAD.ActiveDocument.Objects self.fpLine = objs[len(objs)-1] self.fpLine.Label = 'ForwardPerpendicular' self.fpLineLabel = DrawText('FPText', str(Translator.translate('Forward perpendicular')), Base.Vector(0.5*L,0,zEnd)) # Draw after perpendicular apLine = Part.makeLine((-0.5*L,0,zStart),(-0.5*L,0,zEnd)) Part.show(apLine) objs = FreeCAD.ActiveDocument.Objects self.apLine = objs[len(objs)-1] self.apLine.Label = 'AfterPerpendicular' self.apLineLabel = DrawText('APText', str(Translator.translate('After perpendicular')), Base.Vector(-0.5*L,0,zEnd)) # Draw amin frame amLine = Part.makeLine((0,-0.5*B,zStart),(0,-0.5*B,zEnd)) Part.show(amLine) objs = FreeCAD.ActiveDocument.Objects self.amLine = objs[len(objs)-1] self.amLine.Label = 'AminFrame' self.amLineLabel = DrawText('AMText', str(Translator.translate('Amin frame')), Base.Vector(0,-0.5*B,zEnd))
def discretize(self, nS, nP): """ Discretize the surface. @param nS Number of sections @param nP Number of points per section """ self.obj.addProperty("App::PropertyInteger","nSections","Ship", str(Translator.translate("Number of sections"))).nSections=nS self.obj.addProperty("App::PropertyIntegerList","nPoints","Ship", str(Translator.translate("List of number of points per sections (accumulated histogram)"))).nPoints=[0] self.obj.addProperty("App::PropertyFloatList","xSection","Ship", str(Translator.translate("List of sections x coordinate"))).xSection=[] self.obj.addProperty("App::PropertyVectorList","mSections","Ship", str(Translator.translate("List of sections points"))).mSections=[] nPoints = [0] xSection = [] mSections = [] # Get bounds shape = self.obj.Shape bbox = shape.BoundBox x0 = bbox.XMin x1 = bbox.XMax y0 = bbox.YMin y1 = bbox.YMax z0 = bbox.ZMin z1 = bbox.ZMax # Create a set of planes to perfom edges sections planes = [] dz = (z1 - z0) / (nP - 1) for j in range(0,nP): z = z0 + j*dz rX = x1 - x0 rY = max(y1 - y0, abs(y1), abs(y0)) planes.append(Part.makePlane(4*rX,4*rY,Base.Vector(-2*rX,-2*rY,z),Base.Vector(0,0,1))) # Division are performed at x axis dx = (x1 - x0) / (nS - 1.0) for i in range(0,nS): section = [] x = x0 + i*dx xSection.append(x) percen = i*100 / (nS-1) FreeCAD.Console.PrintMessage('%d%%\n' % (percen)); # Slice the surface to get curves wires = shape.slice(Vector(1.0,0.0,0.0), x) if not wires: if (i != 0) or (i != nS-1): msg = 'Found empty section at x=%g\n' % (x) msg = Translator.translate(msg) FreeCAD.Console.PrintWarning(msg) FreeCAD.Console.PrintWarning('\tThis may happens if a bad defined (or really complex) surface has been provided.\n') FreeCAD.Console.PrintWarning('\tPlease, ensure that this section is correct, or fix surfaces and create a new ship.\n') nPoints.append(0) continue # Desarrollate wires into edges list edges = [] for j in range(0,len(wires)): wire = wires[j].Edges for k in range(0,len(wire)): edges.append(wire[k]) # Slice curves to get points (Length based) points = [] for k in range(0,nP): planePoints = [] for j in range(0,len(edges)): aux = self.lineFaceSection(edges[j], planes[k]) for l in range(0,len(aux)): planePoints.append(Vector(aux[l].X, aux[l].Y, aux[l].Z)) if not planePoints: # No section found, symmetry plane point will used planePoints.append(Vector(x,0,z0 + k*dz)) # Get Y coordinates auxY = [] for l in range(0,len(planePoints)): auxY.append(planePoints[l].y) # Sort them auxY.sort() # And store for l in range(0,len(planePoints)): points.append(Vector(planePoints[l].x, auxY[l], planePoints[l].z)) # Store points section = points[:] nPoints.append(len(section)) for j in range(0,len(section)): mSections.append(section[j]) # Save data for i in range(1,len(nPoints)): nPoints[i] = nPoints[i] + nPoints[i-1] self.obj.nPoints = nPoints[:] self.obj.xSection = xSection[:] self.obj.mSections = mSections[:] msg = '%d Discretization points performed\n' % (len(mSections)) msg = Translator.translate(msg) FreeCAD.Console.PrintMessage(msg)
def onChanged(self, fp, prop): ''' Print the name of the property that has changed ''' # FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") if prop == "Length" or prop == "Beam" or prop == "Draft": fp.Shape = Part.makeShell(self.faces)
def _cutKnob(doc, obj, orientation, distFromAxis, radius, outerRadius, baseToCenter): """ ringLength = to bypass the app """ knobPlane = obj.newObject(_featureClassMapping["Plane"], "knobPlane") knobPlane.AttachmentOffset = App.Placement(App.Vector(0, 0, baseToCenter), App.Rotation(0, 0, 0)) knobPlane.MapReversed = False knobPlane.Support = [(doc.XY_Plane, '')] knobPlane.MapMode = "FlatFace" sketch = obj.newObject(_featureClassMapping["Sketch"], "knobSketch") sketch.Support = (knobPlane, '') sketch.MapMode = "FlatFace" sketch.addGeometry( Part.ArcOfCircle(Part.Circle(App.Vector(0, 0), App.Vector(0, 0, 1), 1), math.pi / 2, 3 * math.pi / 2), False) sketch.addConstraint(Sketcher.Constraint('Radius', 0, radius)) # Enforce 180 deg span of arc sketch.addGeometry( Part.LineSegment(App.Vector(0.0, 0.0), App.Vector(1.0, 0.0)), True) sketch.addConstraint(Sketcher.Constraint('Coincident', 1, 1, 0, 1)) sketch.addConstraint(Sketcher.Constraint('Coincident', 1, 2, 0, 3)) sketch.addGeometry( Part.LineSegment(App.Vector(0.0, 0.0), App.Vector(1.0, 0.0)), True) sketch.addConstraint(Sketcher.Constraint('Coincident', 2, 1, 0, 3)) sketch.addConstraint(Sketcher.Constraint('Coincident', 2, 2, 0, 2)) sketch.addConstraint(Sketcher.Constraint('Angle', 1, 2, 2, 1, math.pi)) # Complete shape sketch.addGeometry( Part.LineSegment(App.Vector(0, radius), App.Vector(1.0, radius)), False) # 3 sketch.addGeometry( Part.LineSegment(App.Vector(0.0, -radius), App.Vector(1.0, -radius)), False) # 4 sketch.addConstraint(Sketcher.Constraint('Tangent', 3, 1, 0, 1)) sketch.addConstraint(Sketcher.Constraint('Tangent', 4, 1, 0, 2)) sketch.addConstraint(Sketcher.Constraint('Equal', 3, 4)) sketch.addConstraint(Sketcher.Constraint('Distance', 3, outerRadius)) sketch.addGeometry( Part.LineSegment(App.Vector(1.0, radius), App.Vector(1.0, -radius)), False) # 5 sketch.addConstraint(Sketcher.Constraint('Coincident', 5, 1, 3, 2)) sketch.addConstraint(Sketcher.Constraint('Coincident', 5, 2, 4, 2)) # Enforce orientation sketch.addGeometry( Part.LineSegment(App.Vector(0.0, radius), App.Vector(1.0, radius)), True) # 6 sketch.addConstraint(Sketcher.Constraint('Horizontal', 6)) sketch.addConstraint(Sketcher.Constraint('Distance', 6, radius)) sketch.addConstraint(Sketcher.Constraint('Coincident', 6, 1, 0, 1)) sketch.addConstraint(Sketcher.Constraint('Angle', 6, 1, 3, 1, orientation)) # Enforce disp x = distFromAxis * math.cos(orientation) y = distFromAxis * math.sin(orientation) sketch.addConstraint(Sketcher.Constraint('DistanceX', -1, 1, 0, 3, x)) sketch.addConstraint(Sketcher.Constraint('DistanceY', -1, 1, 0, 3, y)) pocket = obj.newObject(_featureClassMapping["Pocket"], "knobCut") pocket.Profile = sketch pocket.Length = 10.0 pocket.Length2 = 100.0 pocket.Type = 1 pocket.UpToFace = None pocket.Reversed = 1 pocket.Midplane = 0 pocket.Offset = 0.000000
def externalFaces(self, shape): """ Returns detected external faces. @param shape Shape where external faces wanted. @return List of external faces detected. """ result = [] faces = shape.Faces bbox = shape.BoundBox L = bbox.XMax - bbox.XMin B = bbox.YMax - bbox.YMin T = bbox.ZMax - bbox.ZMin dist = math.sqrt(L*L + B*B + T*T) FreeCAD.Console.PrintMessage("Computing external faces...\n") # Valid/unvalid faces detection loop for i in range(0,len(faces)): FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(faces))) f = faces[i] # Create a line normal to surface at middle point u = 0.0 v = 0.0 try: surf = f.Surface u = 0.5*(surf.getUKnots()[0]+surf.getUKnots()[-1]) v = 0.5*(surf.getVKnots()[0]+surf.getVKnots()[-1]) except: cog = f.CenterOfMass [u,v] = f.Surface.parameter(cog) p0 = f.valueAt(u,v) try: n = f.normalAt(u,v).normalize() except: continue p1 = p0 + n.multiply(1.5*dist) line = Part.makeLine(p0, p1) # Look for faces in front of this nPoints = 0 for j in range(0,len(faces)): f2 = faces[j] section = self.lineFaceSection(line, f2) if len(section) <= 2: continue # Add points discarding start and end nPoints = nPoints + len(section) - 2 # In order to avoid special directions we can modify line # normal a little bit. angle = 5 line.rotate(p0,Vector(1,0,0),angle) line.rotate(p0,Vector(0,1,0),angle) line.rotate(p0,Vector(0,0,1),angle) nPoints2 = 0 for j in range(0,len(faces)): if i == j: continue f2 = faces[j] section = self.lineFaceSection(line, f2) if len(section) <= 2: continue # Add points discarding start and end nPoints2 = nPoints + len(section) - 2 # If the number of intersection points is pair, is a # external face. So if we found an odd points intersection, # face must be discarded. if (nPoints % 2) or (nPoints2 % 2): continue result.append(f) return result
def update(self, names, pos): """ Update the 3D view printing annotations. @param names Weight names. @param pos Weight positions (FreeCAD::Base::Vector). """ # Destroy all previous entities self.clean() for i in range(0, len(names)): # Draw gravity line line = Part.makeLine((pos[i].x, pos[i].y, pos[i].z), (pos[i].x, pos[i].y, pos[i].z - 9.81)) Part.show(line) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'Line' # Draw circles circle = Part.makeCircle(0.5, pos[i], Base.Vector(1.0, 0.0, 0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleX' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0, 1.0, 0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleY' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0, 0.0, 1.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleZ' # Draw annotation self.objects.append( DrawText(names[i] + 'Text', names[i], Base.Vector(pos[i].x + 1.0, pos[i].y, pos[i].z)))
def import_shape_from_file(cls): # Get shape from file path cls.fcd_shape = Part.Shape() cls.fcd_shape.read(cls._design_path)
def upper_tabletop_3(d, dressup=True): s = 35 x1 = d["length"] / 2.0 y1 = d["width"] / 2.0 x2 = x1 - 25 y2 = y1 - 25 p = [None] * 12 p[0] = Base.Vector(-x1, y2, 0) p[1] = Base.Vector(-x2, y1, 0) p[3] = Base.Vector(x2, y1, 0) p[4] = Base.Vector(x1, y2, 0) p[6] = Base.Vector(x1, -y2, 0) p[7] = Base.Vector(x2, -y1, 0) p[9] = Base.Vector(-x2, -y1, 0) p[10] = Base.Vector(-x1, -y2, 0) p[2] = dc.model.sagpoint(p[1], p[3], s) p[5] = dc.model.sagpoint(p[4], p[6], s) p[8] = dc.model.sagpoint(p[7], p[9], s) p[11] = dc.model.sagpoint(p[10], p[0], s) wire = [ Part.makeLine(p[0], p[1]), dc.model.makeArc(p[1:4]), Part.makeLine(p[3], p[4]), dc.model.makeArc(p[4:7]), Part.makeLine(p[6], p[7]), dc.model.makeArc(p[7:10]), Part.makeLine(p[9], p[10]), dc.model.makeArc([p[10], p[11], p[0]]) ] face = Part.Face(Part.Wire(wire)) m = face.extrude(Base.Vector(0, 0, d["upper_tabletop_t"])) m = dc.model.fillet_edges_by_length(m, 60, d["upper_tabletop_t"]) print("Upper tabletop length: ", d["length"]) print("Upper tabletop width: ", d["width"]) ccx = d["length"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) ccy = d["width"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) hx = ccx / 2.0 hy = ccy / 2.0 hole_points = [ Base.Vector(hx, hy, 0), Base.Vector(-hx, hy, 0), Base.Vector(-hx, -hy, 0), Base.Vector(hx, -hy, 0) ] a = 135 for p in hole_points: hole = Part.makeCylinder(d["hole_dia_tabletop"] / 2.0, d["upper_tabletop_t"] / 2.0, p, Base.Vector(0, 0, 1), 360) insert_1 = Part.makeBox(d["leg_t"], d["insertion_width_1"], d["insertion_length"]) insert_1 = dc.model.fillet_edges_by_length(insert_1, d["leg_edge_radii"], d["insertion_length"]) insert_1.translate(Base.Vector(-d["leg_t"] / 2, -d["cx"], 0)) insert_1.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), a) insert_1.translate(p) insert_2 = Part.makeBox(d["leg_t"], d["insertion_width_2"], d["insertion_length"]) insert_2 = dc.model.fillet_edges_by_length(insert_2, d["leg_edge_radii"], d["insertion_length"]) insert_2.translate( Base.Vector(-d["leg_t"] / 2, -d["insertion_width_3"] / 2.0, 0)) insert_2.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), a) insert_2.translate(p) m = m.cut(insert_1).cut(insert_2).cut(hole) a = a + 90 if dressup: m = dc.model.fillet_edges_longer_than(m, d["tabletop_edge_radii"], 300) m.translate(Base.Vector(0, 0, -d["upper_tabletop_t"])) return m
def lower_tabletop_3(d, dressup=True): ccx = d["length"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) ccy = d["width"] - 2 * math.sqrt( ((d["cx"] + d["leg_distance_from_corner"])**2) / 2.0) length = ccx + (2 * d["leg_distance_from_corner"] + d["insertion_width_3"]) / math.sqrt(2.0) width = ccy + (2 * d["leg_distance_from_corner"] + d["insertion_width_3"]) / math.sqrt(2.0) print("Lower tabletop length: ", length) print("Lower tabletop width: ", width) x1 = length / 2.0 y1 = width / 2.0 x2 = x1 - 25 y2 = y1 - 25 p = [None] * 12 p[0] = Base.Vector(-x1, y2, 0) p[1] = Base.Vector(-x2, y1, 0) p[3] = Base.Vector(x2, y1, 0) p[4] = Base.Vector(x1, y2, 0) p[6] = Base.Vector(x1, -y2, 0) p[7] = Base.Vector(x2, -y1, 0) p[9] = Base.Vector(-x2, -y1, 0) p[10] = Base.Vector(-x1, -y2, 0) p[2] = dc.model.sagpoint(p[1], p[3], -45) p[5] = dc.model.sagpoint(p[4], p[6], -45) p[8] = dc.model.sagpoint(p[7], p[9], -45) p[11] = dc.model.sagpoint(p[10], p[0], -45) wire = [ Part.makeLine(p[0], p[1]), dc.model.makeArc(p[1:4]), Part.makeLine(p[3], p[4]), dc.model.makeArc(p[4:7]), Part.makeLine(p[6], p[7]), dc.model.makeArc(p[7:10]), Part.makeLine(p[9], p[10]), dc.model.makeArc([p[10], p[11], p[0]]) ] face = Part.Face(Part.Wire(wire)) m = face.extrude(Base.Vector(0, 0, d["lower_tabletop_t"])) m = dc.model.fillet_edges_by_length(m, 20, d["lower_tabletop_t"]) hx = ccx / 2.0 hy = ccy / 2.0 hole_points = [ Base.Vector(hx, hy, 0), Base.Vector(-hx, hy, 0), Base.Vector(-hx, -hy, 0), Base.Vector(hx, -hy, 0) ] a = 45 for p in hole_points: hole = Part.makeCylinder(d["hole_dia_tabletop"] / 2.0, d["lower_tabletop_t"], p, Base.Vector(0, 0, 1), 360) insert = Part.makeBox(d["leg_t"], d["insertion_width_3"], d["insertion_length"]) insert = dc.model.fillet_edges_by_length(insert, d["leg_edge_radii"], d["insertion_length"]) insert.translate( Base.Vector(-d["leg_t"] / 2, -d["insertion_width_3"] / 2, 0)) insert.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), -a) insert.translate(p) m = m.cut(hole).cut(insert) a = a + 90 if dressup: m = dc.model.fillet_edges_longer_than(m, d["tabletop_edge_radii"], 150) m.translate(Base.Vector(0, 0, -d["lower_tabletop_t"])) return m
def update(self, names, pos): """ Update the 3D view printing annotations. @param names Weight names. @param pos Weight positions (FreeCAD::Base::Vector). """ # Destroy all previous entities self.clean() for i in range(0, len(names)): # Draw gravity line line = Part.makeLine((pos[i].x,pos[i].y,pos[i].z),(pos[i].x,pos[i].y,pos[i].z - 9.81)) Part.show(line) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'Line' # Draw circles circle = Part.makeCircle(0.5, pos[i], Base.Vector(1.0,0.0,0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleX' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,1.0,0.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleY' circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,0.0,1.0)) Part.show(circle) objs = FreeCAD.ActiveDocument.Objects self.objects.append(objs[-1]) objs[-1].Label = names[i] + 'CircleZ' # Draw annotation self.objects.append(DrawText(names[i] + 'Text', names[i], Base.Vector(pos[i].x+1.0,pos[i].y,pos[i].z)))
def update(self, L, B, T, sectionsL, sectionsB, sectionsT, shape): """ Update the 3D view printing annotations. @param L Ship Lpp. @param B Ship beam. @param T Ship draft. @param sectionsL Transversal sections. @param sectionsB Longitudinal sections. @param sectionsT Water lines. @param shape Ship surfaces shell @return Sections object. None if errors happens. """ FreeCAD.Console.PrintMessage(Translator.translate('Computing sections...\n')) # Destroy all previous entities self.clean() # Receive data nL = len(sectionsL) nB = len(sectionsB) nT = len(sectionsT) if not (nL or nB or nT): return None # Found sections sections = [] for i in range(0,nL): pos = sectionsL[i] section = shape.slice(Vector(1.0,0.0,0.0), pos) for j in range(0,len(section)): edges = section[j].Edges if pos == 0.0: section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges2 = section[j].Edges for k in range(0,len(edges2)): edges.append(edges2[k]) elif pos < 0: section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges = section[j].Edges for k in range(0,len(edges)): sections.append(edges[k]) for i in range(0,nB): pos = sectionsB[i] section = shape.slice(Vector(0.0,1.0,0.0), pos) for j in range(0,len(section)): edges = section[j].Edges section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges2 = section[j].Edges for k in range(0,len(edges2)): edges.append(edges2[k]) for k in range(0,len(edges)): sections.append(edges[k]) for i in range(0,nT): pos = sectionsT[i] section = shape.slice(Vector(0.0,0.0,1.0), pos) for j in range(0,len(section)): edges = section[j].Edges if pos == T: section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges2 = section[j].Edges for k in range(0,len(edges2)): edges.append(edges2[k]) elif pos > T: section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges = section[j].Edges for k in range(0,len(edges)): sections.append(edges[k]) # Convert all BSplines into a shape if not sections: msg = Translator.translate('Any valid ship section found\n') FreeCAD.Console.PrintWarning(msg) return obj = sections[0] for i in range(1,len(sections)): obj = obj.oldFuse(sections[i]) # Only group the edges, don't try to build more complex entities # Create the representable object Part.show(obj) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs)-1] self.obj.Label = 'OutlineDraw' return self.obj
def execute(self, obj): ''' Print a short message when doing a recomputation, this method is mandatory ''' # FreeCAD.Console.PrintMessage("Recompute Ship\n") obj.Shape = Part.makeShell(self.faces)
def areas(ship, draft, roll=0.0, trim=0.0, yaw=0.0, n=30): """ Compute ship transversal areas. @param ship Ship instance. @param draft Ship draft. @param roll Ship roll angle. @param trim Ship trim angle. @param yaw Ship yaw angle. Ussually you don't want to use this value. @param n Number of sections to perform. @return Transversal areas (every area value is composed by x coordinate and computed area) """ if n < 2: return [] # We will take a duplicate of ship shape in order to place it shape = ship.Shape.copy() shape.translate(Vector(0.0,0.0,-draft)) # Rotations composition is Roll->Trim->Yaw shape.rotate(Vector(0.0,0.0,0.0), Vector(1.0,0.0,0.0), roll) shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,-1.0,0.0), trim) shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,0.0,1.0), yaw) # Now we need to know the x range of values bbox = shape.BoundBox xmin = bbox.XMin xmax = bbox.XMax dx = (xmax - xmin) / (n-1.0) # First area is equal to zero. areas = [[xmin, 0.0]] # Since we need face entities, in order to compute sections we will # create boxes with front face at transversal area position, # compute solid common, divide by faces, and preserve only desired # ones. App.Console.PrintMessage("Computing transversal areas...\n") App.Console.PrintMessage("Some Inventor representation errors can be shown, ignore it please.\n") for i in range(1,n-1): App.Console.PrintMessage("%d / %d\n" % (i, n-2)) x = xmin + i*dx area = 0.0 # Create the box L = xmax - xmin B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(1.5*L + x, 3.0*B, - bbox.ZMin + 1.0, p) # Compute common part with ship for s in shape.Solids: # Get solids intersection try: common = box.common(s) except: continue if common.Volume == 0.0: continue # Recompute object adding it to the scene, when we have # computed desired data we can remove it. try: Part.show(common) except: continue # Divide by faces and compute only section placed ones faces = common.Faces for f in faces: faceBounds = f.BoundBox # Orientation filter if faceBounds.XMax - faceBounds.XMin > 0.00001: continue # Place filter if abs(faceBounds.XMax - x) > 0.00001: continue # Valid face, compute area area = area + f.Area # Destroy last object generated App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name) # Append transversal area areas.append([x, area]) # Last area is equal to zero areas.append([xmax, 0.0]) App.Console.PrintMessage("Done!\n") return areas
def Plot(scale, sections, shape): """ Creates the outline draw. @param scale Plane scale (format 1:scale) @param sections Sections computed. @param shape Ship surfaces shell @return plotted object (DocumentObject) """ msg = Translator.translate('Performing plot (Scale 1:%d)...\n' % (scale)) FreeCAD.Console.PrintMessage(msg) scale = 1000.0 / scale # Take positions bounds = [0.0, 0.0, 0.0] bbox = shape.BoundBox bounds[0] = bbox.XLength bounds[1] = bbox.YLength bounds[2] = bbox.ZLength xTot = scale*bounds[1] + 32.0 + scale*bounds[0] yTot = scale*bounds[2] + 32.0 + scale*bounds[1] xMid = 210.0 yMid = 185.0 x0 = xMid - 0.5*xTot y0 = 297.0 - yMid - 0.5*yTot # 297 = A3_width # Get border edges = Geometry.getEdges([shape]) border = edges[0] for i in range(0,len(edges)): border = border.oldFuse(edges[i]) # Only group objects, don't try to build more complex entities border = border.oldFuse(edges[i].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0))) # Fuse sections & borders # obj = sections.oldFuse(border) obj = border.oldFuse(sections) # Send to 3D view Part.show(obj) objs = FreeCAD.ActiveDocument.Objects obj = objs[len(objs)-1] # Create a new plane FreeCAD.ActiveDocument.addObject('Drawing::FeaturePage','OutlineDrawPlot') FreeCAD.ActiveDocument.OutlineDrawPlot.Template = FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg' # Side view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart','OutlineDrawSideView') FreeCAD.ActiveDocument.OutlineDrawSideView.Source = obj FreeCAD.ActiveDocument.OutlineDrawSideView.Direction = (1.0,0.0,0.0) FreeCAD.ActiveDocument.OutlineDrawSideView.Rotation = -90.0 FreeCAD.ActiveDocument.OutlineDrawSideView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawSideView.X = 420.0 - x0 - 0.5*scale*bounds[1] # 420 = A3_height FreeCAD.ActiveDocument.OutlineDrawSideView.Y = y0 + 0.5*scale*bounds[2] FreeCAD.ActiveDocument.OutlineDrawPlot.addObject(FreeCAD.ActiveDocument.OutlineDrawSideView) # Front view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart','OutlineDrawFrontView') FreeCAD.ActiveDocument.OutlineDrawFrontView.Source = obj FreeCAD.ActiveDocument.OutlineDrawFrontView.Direction = (0.0,1.0,0.0) FreeCAD.ActiveDocument.OutlineDrawFrontView.Rotation = -90.0 FreeCAD.ActiveDocument.OutlineDrawFrontView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawFrontView.X = 420.0 - x0 - scale*bounds[1] - 32 - 0.5*scale*bounds[0] FreeCAD.ActiveDocument.OutlineDrawFrontView.Y = y0 + 0.5*scale*bounds[2] FreeCAD.ActiveDocument.OutlineDrawPlot.addObject(FreeCAD.ActiveDocument.OutlineDrawFrontView) # Up view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart','OutlineDrawUpView') FreeCAD.ActiveDocument.OutlineDrawUpView.Source = obj FreeCAD.ActiveDocument.OutlineDrawUpView.Direction = (0.0,0.0,1.0) FreeCAD.ActiveDocument.OutlineDrawUpView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawUpView.X = 420.0 - x0 - scale*bounds[1] - 32 - 0.5*scale*bounds[0] FreeCAD.ActiveDocument.OutlineDrawUpView.Y = y0 + scale*bounds[2] + 32 FreeCAD.ActiveDocument.OutlineDrawPlot.addObject(FreeCAD.ActiveDocument.OutlineDrawUpView) FreeCAD.ActiveDocument.recompute() return obj
def displacement(ship, draft, roll=0.0, trim=0.0, yaw=0.0): """ Compute ship displacement. @param ship Ship instance. @param draft Ship draft. @param roll Ship roll angle. @param trim Ship trim angle. @param yaw Ship yaw angle. Ussually you don't want to use this value. @return [disp, B, Cb], \n disp = Ship displacement [ton]. B = Bouyance center [m]. Cb = Block coefficient. @note Bouyance center will returned as FreeCAD.Vector class. @note Returned Bouyance center is in non modified ship coordinates """ # We will take a duplicate of ship shape in order to place it shape = ship.Shape.copy() shape.translate(Vector(0.0,0.0,-draft)) # Rotations composition is Roll->Trim->Yaw shape.rotate(Vector(0.0,0.0,0.0), Vector(1.0,0.0,0.0), roll) shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,-1.0,0.0), trim) shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,0.0,1.0), yaw) # Now we need to know box dimensions bbox = shape.BoundBox xmin = bbox.XMin xmax = bbox.XMax # Create the box L = xmax - xmin B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) box = Part.makeBox(3.0*L, 3.0*B, -bbox.ZMin + 1.0, p) vol = 0.0 cog = Vector() for solid in shape.Solids: # Compute common part with ship try: common = box.common(solid) except: continue # Get data vol = vol + common.Volume for s in common.Solids: sCoG = s.CenterOfMass cog.x = cog.x + sCoG.x*s.Volume cog.y = cog.y + sCoG.y*s.Volume cog.z = cog.z + sCoG.z*s.Volume cog.x = cog.x / vol cog.y = cog.y / vol cog.z = cog.z / vol Vol = L*B*abs(bbox.ZMin) # Undo transformations B = Vector() B.x = cog.x*math.cos(math.radians(-yaw)) - cog.y*math.sin(math.radians(-yaw)) B.y = cog.x*math.sin(math.radians(-yaw)) + cog.y*math.cos(math.radians(-yaw)) B.z = cog.z cog.x = B.x*math.cos(math.radians(-trim)) - B.z*math.sin(math.radians(-trim)) cog.y = B.y cog.z = B.x*math.sin(math.radians(-trim)) + B.z*math.cos(math.radians(-trim)) B.x = cog.x B.y = cog.y*math.cos(math.radians(-roll)) - cog.z*math.sin(math.radians(-roll)) B.z = cog.y*math.sin(math.radians(-roll)) + cog.z*math.cos(math.radians(-roll)) B.z = B.z + draft # Return data dens = 1.025 # [tons/m3], salt water return [dens*vol, B, vol/Vol]
def discretize(self, nS, nP): """ Discretize the surface. @param nS Number of sections @param nP Number of points per section """ self.obj.addProperty( "App::PropertyInteger", "nSections", "Ship", str(Translator.translate("Number of sections"))).nSections = nS self.obj.addProperty( "App::PropertyIntegerList", "nPoints", "Ship", str( Translator.translate( "List of number of points per sections (accumulated histogram)" ))).nPoints = [0] self.obj.addProperty( "App::PropertyFloatList", "xSection", "Ship", str(Translator.translate( "List of sections x coordinate"))).xSection = [] self.obj.addProperty( "App::PropertyVectorList", "mSections", "Ship", str(Translator.translate( "List of sections points"))).mSections = [] nPoints = [0] xSection = [] mSections = [] # Get bounds shape = self.obj.Shape bbox = shape.BoundBox x0 = bbox.XMin x1 = bbox.XMax y0 = bbox.YMin y1 = bbox.YMax z0 = bbox.ZMin z1 = bbox.ZMax # Create a set of planes to perfom edges sections planes = [] dz = (z1 - z0) / (nP - 1) for j in range(0, nP): z = z0 + j * dz rX = x1 - x0 rY = max(y1 - y0, abs(y1), abs(y0)) planes.append( Part.makePlane(4 * rX, 4 * rY, Base.Vector(-2 * rX, -2 * rY, z), Base.Vector(0, 0, 1))) # Division are performed at x axis dx = (x1 - x0) / (nS - 1.0) for i in range(0, nS): section = [] x = x0 + i * dx xSection.append(x) percen = i * 100 / (nS - 1) FreeCAD.Console.PrintMessage('%d%%\n' % (percen)) # Slice the surface to get curves wires = shape.slice(Vector(1.0, 0.0, 0.0), x) if not wires: if (i != 0) or (i != nS - 1): msg = 'Found empty section at x=%g\n' % (x) msg = Translator.translate(msg) FreeCAD.Console.PrintWarning(msg) FreeCAD.Console.PrintWarning( '\tThis may happens if a bad defined (or really complex) surface has been provided.\n' ) FreeCAD.Console.PrintWarning( '\tPlease, ensure that this section is correct, or fix surfaces and create a new ship.\n' ) nPoints.append(0) continue # Desarrollate wires into edges list edges = [] for j in range(0, len(wires)): wire = wires[j].Edges for k in range(0, len(wire)): edges.append(wire[k]) # Slice curves to get points points = [] for k in range(0, nP): planePoints = [] for j in range(0, len(edges)): aux = self.lineFaceSection(edges[j], planes[k]) for l in range(0, len(aux)): planePoints.append(Vector(aux[l].X, aux[l].Y, aux[l].Z)) if not planePoints: # No section found, symmetry plane point will used planePoints.append(Vector(x, 0, z0 + k * dz)) # Get Y coordinates auxY = [] for l in range(0, len(planePoints)): auxY.append(planePoints[l].y) # Sort them auxY.sort() # And store for l in range(0, len(planePoints)): points.append( Vector(planePoints[l].x, auxY[l], planePoints[l].z)) # Store points section = points[:] nPoints.append(len(section)) for j in range(0, len(section)): mSections.append(section[j]) # Save data for i in range(1, len(nPoints)): nPoints[i] = nPoints[i] + nPoints[i - 1] self.obj.nPoints = nPoints[:] self.obj.xSection = xSection[:] self.obj.mSections = mSections[:] msg = '%d Discretization points performed\n' % (len(mSections)) msg = Translator.translate(msg) FreeCAD.Console.PrintMessage(msg)
def create_default_shape(cls): # Create default shape, a simple box cls.fcd_shape = Part.makeBox(cls.default_length, cls.default_width, cls.default_height)
def leg(d, dressup=True): s1 = d["leg_s1"] s2 = d["leg_s2"] s3 = d["leg_s3"] s4 = d["leg_s4"] s5 = d["leg_s5"] x0 = d["insertion_width_1"] x1 = 105 x2 = d["cx"] - d["insertion_width_3"] / 2.0 x3 = x2 + d["insertion_width_2"] x4 = d["cx"] + d["insertion_width_3"] / 2.0 x5 = x2 - 20 x6 = 100 x7 = x6 - 50 y0 = d["height"] - d["upper_tabletop_t"] + d["insertion_length"] y1 = d["height"] - d["upper_tabletop_t"] - 5 y2 = y0 - 10 y3 = d["height_1"] + 100 y4 = d["height_1"] - d["insertion_length"] y5 = y4 + 15 print("Leg length: ", y0) print("Leg width: ", x3) p = [None] * 21 p[0] = Base.Vector(0, y0, 0) p[1] = Base.Vector(x0, y0, 0) p[2] = Base.Vector(x0, y1, 0) p[4] = Base.Vector(x1, y3, 0) p[6] = Base.Vector(x2, y1, 0) p[7] = Base.Vector(x2, y0, 0) p[8] = Base.Vector(x3, y0, 0) p[9] = Base.Vector(x3, y1, 0) p[11] = Base.Vector(x4, y5, 0) p[12] = Base.Vector(x4, y4, 0) p[13] = Base.Vector(x2, y4, 0) p[14] = Base.Vector(x2, y5, 0) p[15] = Base.Vector(x5, y5, 0) p[17] = Base.Vector(x6, 0, 0) p[18] = Base.Vector(x7, 0, 0) p[20] = Base.Vector(0, y2, 0) p[3] = dc.model.sagpoint(p[2], p[4], s1) p[5] = dc.model.sagpoint(p[4], p[6], s2) p[10] = dc.model.sagpoint(p[9], p[11], s3) p[16] = dc.model.sagpoint(p[15], p[17], s4) p[19] = dc.model.sagpoint(p[18], p[20], s5) wire = [ Part.makeLine(p[0], p[1]), Part.makeLine(p[1], p[2]), dc.model.makeArc(p[2:5]), dc.model.makeArc(p[4:7]), Part.makeLine(p[6], p[7]), Part.makeLine(p[7], p[8]), Part.makeLine(p[8], p[9]), dc.model.makeArc(p[9:12]), Part.makeLine(p[11], p[12]), Part.makeLine(p[12], p[13]), Part.makeLine(p[13], p[14]), Part.makeLine(p[14], p[15]), dc.model.makeArc(p[15:18]), Part.makeLine(p[17], p[18]), dc.model.makeArc(p[18:]), Part.makeLine(p[20], p[0]) ] face = Part.Face(Part.Wire(wire)) m = face.extrude(Base.Vector(0, 0, d["leg_t"])) m = dc.model.fillet_edge_xy(m, 7, p[2]) m = dc.model.fillet_edge_xy(m, 12, p[4]) m = dc.model.fillet_edge_xy(m, 7, p[6]) m = dc.model.fillet_edge_xy(m, 7, p[9]) m = dc.model.fillet_edge_xy(m, 7, p[14]) m = dc.model.fillet_edge_xy(m, 12, p[15]) m = dc.model.fillet_edge_xy(m, 30, p[20]) m.rotate(Base.Vector(0, 0, 0), Base.Vector(1, 0, 0), 90) m.translate(Base.Vector(0, d["leg_t"] / 2.0, 0)) hole = Part.makeCylinder( d["hole_dia_leg"] / 2.0, d["height"], Base.Vector(d["cx"], 0, d["height_1"] - d["insertion_length"]), Base.Vector(0, 0, 1), 360) m = m.cut(hole) if dressup: m = dc.model.fillet_edges_longer_than(m, d["leg_edge_radii"], 95) return m
def execute(self, fp): """ Called when a recomputation is needed. @param fp Part::FeaturePython object. """ fp.Shape = Part.makeCompound(fp.Shape.Solids)
def Plot(scale, sections, shape): """ Creates the outline draw. @param scale Plane scale (format 1:scale) @param sections Sections computed. @param shape Ship surfaces shell @return plotted object (DocumentObject) """ msg = Translator.translate('Performing plot (Scale 1:%d)...\n' % (scale)) FreeCAD.Console.PrintMessage(msg) scale = 1000.0 / scale # Take positions bounds = [0.0, 0.0, 0.0] bbox = shape.BoundBox bounds[0] = bbox.XLength bounds[1] = bbox.YLength bounds[2] = bbox.ZLength xTot = scale * bounds[1] + 32.0 + scale * bounds[0] yTot = scale * bounds[2] + 32.0 + scale * bounds[1] xMid = 210.0 yMid = 185.0 x0 = xMid - 0.5 * xTot y0 = 297.0 - yMid - 0.5 * yTot # 297 = A3_width # Get border edges = Geometry.getEdges([shape]) border = edges[0] for i in range(0, len(edges)): border = border.oldFuse( edges[i] ) # Only group objects, don't try to build more complex entities border = border.oldFuse(edges[i].mirror(Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0))) # Fuse sections & borders # obj = sections.oldFuse(border) obj = border.oldFuse(sections) # Send to 3D view Part.show(obj) objs = FreeCAD.ActiveDocument.Objects obj = objs[len(objs) - 1] # Create a new plane FreeCAD.ActiveDocument.addObject('Drawing::FeaturePage', 'OutlineDrawPlot') FreeCAD.ActiveDocument.OutlineDrawPlot.Template = FreeCAD.getResourceDir( ) + 'Mod/Drawing/Templates/A3_Landscape.svg' # Side view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart', 'OutlineDrawSideView') FreeCAD.ActiveDocument.OutlineDrawSideView.Source = obj FreeCAD.ActiveDocument.OutlineDrawSideView.Direction = (1.0, 0.0, 0.0) FreeCAD.ActiveDocument.OutlineDrawSideView.Rotation = -90.0 FreeCAD.ActiveDocument.OutlineDrawSideView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawSideView.X = 420.0 - x0 - 0.5 * scale * bounds[ 1] # 420 = A3_height FreeCAD.ActiveDocument.OutlineDrawSideView.Y = y0 + 0.5 * scale * bounds[2] FreeCAD.ActiveDocument.OutlineDrawPlot.addObject( FreeCAD.ActiveDocument.OutlineDrawSideView) # Front view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart', 'OutlineDrawFrontView') FreeCAD.ActiveDocument.OutlineDrawFrontView.Source = obj FreeCAD.ActiveDocument.OutlineDrawFrontView.Direction = (0.0, 1.0, 0.0) FreeCAD.ActiveDocument.OutlineDrawFrontView.Rotation = -90.0 FreeCAD.ActiveDocument.OutlineDrawFrontView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawFrontView.X = 420.0 - x0 - scale * bounds[ 1] - 32 - 0.5 * scale * bounds[0] FreeCAD.ActiveDocument.OutlineDrawFrontView.Y = y0 + 0.5 * scale * bounds[2] FreeCAD.ActiveDocument.OutlineDrawPlot.addObject( FreeCAD.ActiveDocument.OutlineDrawFrontView) # Up view FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart', 'OutlineDrawUpView') FreeCAD.ActiveDocument.OutlineDrawUpView.Source = obj FreeCAD.ActiveDocument.OutlineDrawUpView.Direction = (0.0, 0.0, 1.0) FreeCAD.ActiveDocument.OutlineDrawUpView.Scale = scale FreeCAD.ActiveDocument.OutlineDrawUpView.X = 420.0 - x0 - scale * bounds[ 1] - 32 - 0.5 * scale * bounds[0] FreeCAD.ActiveDocument.OutlineDrawUpView.Y = y0 + scale * bounds[2] + 32 FreeCAD.ActiveDocument.OutlineDrawPlot.addObject( FreeCAD.ActiveDocument.OutlineDrawUpView) FreeCAD.ActiveDocument.recompute() return obj
def update(self, L, B, T, sectionsL, sectionsB, sectionsT, shape): """ Update the 3D view printing annotations. @param L Ship Lpp. @param B Ship beam. @param T Ship draft. @param sectionsL Transversal sections. @param sectionsB Longitudinal sections. @param sectionsT Water lines. @param shape Ship surfaces shell @return Sections object. None if errors happens. """ FreeCAD.Console.PrintMessage(Translator.translate('Computing sections...\n')) # Destroy all previous entities self.clean() # Receive data nL = len(sectionsL) nB = len(sectionsB) nT = len(sectionsT) if not (nL or nB or nT): return None # Found sections sections = [] for i in range(0,nL): pos = sectionsL[i] # Cut ship section = shape.slice(Vector(1.0,0.0,0.0), pos) for j in range(0,len(section)): edges = section[j].Edges # We have 3 cases, # * when section is before midship, then only starboard section will be considered # * When section is midship, then all section must be preserved # * When section is after midship, then only board will be considered if pos > 0.01: # Look for edges at the wrong side and delete it for k in range(len(edges)-1,-1,-1): edge = edges[k] bbox = edge.BoundBox if bbox.YMin < -0.001: del edges[k] elif pos < -0.01: # Look for edges at the wrong side and delete it for k in range(len(edges)-1,-1,-1): edge = edges[k] bbox = edge.BoundBox if bbox.YMax > 0.001: del edges[k] sections.extend(edges) for i in range(0,nB): pos = sectionsB[i] section = shape.slice(Vector(0.0,1.0,0.0), pos) for j in range(0,len(section)): edges = section[j].Edges # Longitudinal sections will preserve board and starboard ever. Since we take from one side, # we nned to mirror it. section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)) edges2 = section[j].Edges sections.extend(edges) sections.extend(edges2) for i in range(0,nT): pos = sectionsT[i] section = shape.slice(Vector(0.0,0.0,1.0), pos) for j in range(0,len(section)): edges = section[j].Edges # We have 3 cases, # * when section is below draft, then only board section will be considered # * When section is draft, then all section must be preserved # * When section is above draft, then only starboard will be considered if pos > T + 0.01: # Look for edges at the wrong side and delete it for k in range(len(edges)-1,-1,-1): edge = edges[k] bbox = edge.BoundBox if bbox.YMax > 0.001: del edges[k] elif pos < T - 0.01: # Look for edges at the wrong side and delete it for k in range(len(edges)-1,-1,-1): edge = edges[k] bbox = edge.BoundBox if bbox.YMin < -0.001: del edges[k] sections.extend(edges) # Convert all BSplines into a shape if not sections: msg = Translator.translate('Any valid ship section found') FreeCAD.Console.PrintWarning(msg) return obj = sections[0] for i in range(1,len(sections)): obj = obj.oldFuse(sections[i]) # Only group the edges, don't try to build more complex entities # Create the representable object Part.show(obj) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs)-1] self.obj.Label = 'OutlineDraw' return self.obj