def angle(f0, f1, v0, e0): """f0 - передня поверхня, f1 - задня поверхня, v0 - вершина на різальній кромці, e0 - гвинтова кромка""" plane0 = f0.Surface curve0 = e0.Curve res = plane0.intersect(curve0) # або common, distToShape print "к-ть точок перетину: ", len(res[0]) #p1=res[0][0] # точка Part.Point перетину # але може бути кілька точок перетину, тому використовуйте: elt.Placement.Base isEqual distanceToPoint for resi in res[0]: if v0.Point.isEqual(resi.toShape().Point, d.P): # близька до v0 p1 = resi Part.show(p1.toShape()) vec1 = App.Vector(p1.X, p1.Y, p1.Z) vec = curve0.tangent(curve0.parameter(vec1))[0] # дотична в точці vec = vec + vec1 # перемістити в положення plane = Part.Plane(vec1, v0.Point, vec) # площина різання Part.show(Part.makeLine(vec1, vec)) Part.show(Part.makeLine(vec1, (vec - vec1).negative() + vec1)) uv = plane.parameter(vec1) vec2 = plane.normal(uv[0], uv[1]) # нормаль до площини різання uv = f1.Surface.parameter(vec1) vec3 = f1.Surface.normal(uv[0], uv[1]) # нормаль до задньої поверхні a = vec2.getAngle(vec3) # кінематичний задній кут vec2 = vec2 + vec1 # перемістити в положення plane = Part.Plane(vec1, v0.Point, vec2) # основна площина Part.show(Part.makeLine(vec1, vec2)) Part.show(Part.makeLine(vec1, (vec2 - vec1).negative() + vec1)) uv = plane.parameter(vec1) vec4 = plane.normal(uv[0], uv[1]) # нормаль до основної площини uv = f0.Surface.parameter(vec1) vec5 = f0.Surface.normal(uv[0], uv[1]) # нормаль до передньої поверхні g = vec4.getAngle(vec5) # кінематичний передній кут return np.degrees(a), np.degrees(g)
def StarDiag4_3Sub(self, fp, Sub_prev_i, Sub_i, Sub_next_i): # apply index and get Poles list from instance. Sub_prev = getattr(fp, 'Poles_%d' % Sub_prev_i) Sub = getattr(fp, 'Poles_%d' % Sub_i) Sub_next = getattr(fp, 'Poles_%d' % Sub_next_i) # do the thing # parallelogram diagonal Sub_28_raw = Sub[27] + (Sub[22]-Sub[21]) # scaled down 75% to spread out center Sub_28_scaled = Sub[21] + 0.75 * (Sub_28_raw - Sub[21]) Plane_prev = Part.Plane(Sub[33],Sub[23],Sub_prev[33]) Plane_next = Part.Plane(Sub[33],Sub[23],Sub_next[23]) Sub_28_prev_param = Plane_prev.parameter(Sub_28_scaled) Sub_28_prev_proj = Plane_prev.value(Sub_28_prev_param[0],Sub_28_prev_param[1]) Sub_28_next_param = Plane_next.parameter(Sub_28_scaled) Sub_28_next_proj = Plane_next.value(Sub_28_next_param[0],Sub_28_next_param[1]) Sub[28] = 0.5 * Sub_28_scaled + 0.25 * (Sub_28_prev_proj + Sub_28_next_proj) # update instance properties using setattr() and string manipulation to set index setattr(fp, 'Poles_%d' % Sub_i, Sub) # control leg visualization Legs_Diag4 = [0,0] Legs_Diag4[0] = Part.LineSegment(Sub[22],Sub[28]) Legs_Diag4[1] = Part.LineSegment(Sub[27],Sub[28]) # update instance property. direct assignment Legs = fp.Legs fp.Legs = Legs + Legs_Diag4 return 0
def get_relative_placement(shape1, shape2): """returns the placement that must be applied to shape1 to move it to shape_2""" # https://forum.freecadweb.org/viewtopic.php?f=22&t=44880 # Assuming that the first 3 vertices of the shape # correctly define a plane (not coincident, nor colinear) plane1 = Part.Plane(*[v.Point for v in shape1.Vertexes[0:3]]) plane2 = Part.Plane(*[v.Point for v in shape2.Vertexes[0:3]]) pl1 = FreeCAD.Placement(plane1.Position, plane1.Rotation) pl2 = FreeCAD.Placement(plane2.Position, plane2.Rotation) return pl2.multiply(pl1.inverse())
def Activated(self): sel = FreeCADGui.Selection.getSelection() if not len(sel) == 2: FreeCAD.Console.PrintError("Select 2 objects !\n") for selobj in sel: selobj.ViewObject.Visibility = False pl = Part.Plane() pl.transform(sel[0].Placement.toMatrix()) d1 = pl.Axis pl = Part.Plane() pl.transform(sel[1].Placement.toMatrix()) d2 = pl.Axis self.makeCPCFeature(sel[0], sel[1], d1, d2)
def test_issue_4456(self): """ 0004456: Regression : Part.Plane.Intersect do not accept plane as argument """ p1 = Part.Plane() p2 = Part.Plane(Vector(0, 0, 0), Vector(1, 0, 0)) result = p1.intersect(p2) line = result.pop() self.assertEqual(line.Location, Vector(0, 0, 0)) self.assertEqual(line.Direction, Vector(0, 1, 0)) # We should now have empty list... with self.assertRaises(IndexError): result.pop()
def testChFi2d_AnaFilletAlgo(self): v = FreeCAD.Vector edge1 = Part.makeLine(v(0,0,0), v(0,10,0)) edge2 = Part.makeLine(v(0,10,0), v(10,10,0)) wire = Part.Wire([edge1, edge2]) pln = Part.Plane() with self.assertRaises(TypeError): alg = Part.ChFi2d.AnaFilletAlgo(pln) alg = Part.ChFi2d.AnaFilletAlgo() with self.assertRaises(TypeError): alg.init() print (alg) # Test without shape self.assertFalse(alg.perform(1)) with self.assertRaises(TypeError): alg.perform() alg = Part.ChFi2d.AnaFilletAlgo(wire, pln) alg.init(edge1, edge2, pln) alg.init(wire, pln) alg = Part.ChFi2d.AnaFilletAlgo(edge1, edge2, pln) alg.perform(1.0) with self.assertRaises(TypeError): alg.result(1) result = alg.result() curve = result[0].Curve self.assertEqual(type(curve), Part.Circle) self.assertEqual(curve.Radius, 1.0)
def ensure_external_earth_is_set(space: "SpaceFeature", doc=FreeCAD.ActiveDocument): sites: List["ContainerFeature"] = list( utils.get_elements_by_ifctype("IfcSite", doc)) ground_bound_box = get_ground_bound_box(sites) if space.Shape.BoundBox.ZMin - ground_bound_box.ZMax > 1000: return ground_shape = Part.Compound([]) for site in sites: ground_shape.add(site.Shape) if not ground_shape.BoundBox.isValid(): ground_shape = Part.Plane().toShape() for boundary in space.SecondLevel.Group: if boundary.InternalOrExternalBoundary in ( "INTERNAL", "EXTERNAL_EARTH", "EXTERNAL_WATER", "EXTERNAL_FIRE", ): continue if boundary.InnerBoundaries: continue if not is_underground(boundary, ground_shape): continue boundary.InternalOrExternalBoundary = "EXTERNAL_EARTH"
def compute_tangents(self): tans = list() flags = list() for i in range(len(self.points)): if isinstance(self.points[i].shape,Part.Face): for vec in self.points[i].points: u,v = self.points[i].shape.Surface.parameter(FreeCAD.Vector(vec)) norm = self.points[i].shape.normalAt(u,v) cp = self.curve.parameter(FreeCAD.Vector(vec)) t = self.curve.tangent(cp)[0] pl = Part.Plane(FreeCAD.Vector(),norm) ci = Part.Geom2d.Circle2d() ci.Radius = t.Length * 2 w = Part.Wire([ci.toShape(pl)]) f = Part.Face(w) #proj = f.project([Part.Vertex(t)]) proj = Part.Vertex(t).distToShape(f)[1][0][1] #pt = proj.Vertexes[0].Point #FreeCAD.Console.PrintMessage("Projection %s -> %s\n"%(t,proj)) if proj.Length > 1e-7: tans.append(proj) flags.append(True) else: tans.append(FreeCAD.Vector(1,0,0)) flags.append(False) else: for vec in self.points[i].points: tans.append(FreeCAD.Vector(1,0,0)) flags.append(False) return(tans,flags)
def build_param_ortho(self, num=20): #surf = ruled_surface(self.rail1.edge, self.rail2.edge).Surface mid = self.surf.vIso(0.5) #c0 = surf.vIso(0.0) #c1 = surf.vIso(1.0) #v0 = c0.toShape() #v1 = c1.toShape() self.inter = interp() self.inter.add(0, (self.rail1.edge.Curve.FirstParameter, self.rail2.edge.Curve.FirstParameter)) pl = Part.Plane() for i in range(1, num): v = float(i) / (num) pt = mid.value(v) tan = mid.tangent(v)[0] pl.Position = pt pl.Axis = tan pts0 = self.rail1.edge.Curve.intersectCS(pl)[0] pts1 = self.rail2.edge.Curve.intersectCS(pl)[0] pt0 = closest_point(pts0, pt) pt1 = closest_point(pts1, pt) if isinstance(pt0, FreeCAD.Vector) and isinstance( pt1, FreeCAD.Vector): p1 = nurbs_tools.nearest_parameter(self.rail1.edge.Curve, pt0) p2 = nurbs_tools.nearest_parameter(self.rail2.edge.Curve, pt1) self.inter.add( v, (p1, p2) ) # (self.rail1.edge.Curve.parameter(pt0), self.rail2.edge.Curve.parameter(pt1))) else: FreeCAD.Console.PrintError( "Failed to compute points at %f.\n" % v) self.inter.add(1, (self.rail1.edge.Curve.LastParameter, self.rail2.edge.Curve.LastParameter))
def CreateSpiral(self, fp, a): m = fp.Profile.Shape.BoundBox.Center # Center of the profile myNumRot = fp.Rotations myRadius = m.distanceToLine(fp.Center, fp.Center + fp.Axis) myGrowth = Growth myPitch = 1.0 myHeight = myNumRot * myPitch myAngle = atan(myGrowth / myPitch) assert myGrowth > 0, u"Growth too small" assert myNumRot > 0, u"Number of rotations too small" aPnt = VEC(0.0, 0.0, 0.0) aDir = VEC(2.0 * pi, myPitch, 0.0) surf = Part.Cone(aPnt, DIR_Z, 1.0, 0.0) line = Part.LineSegment(aPnt, aDir) beg = line.value(0) end = line.value(aDir.Length * myNumRot) # calculate end point for conical helix v = myHeight / cos(myAngle) u = myNumRot * 2.0 * pi segm = Part.LineSegment(beg, VEC(u, v, 0)) edgeOnSurf = surf.project(segm) wire = edgeOnSurf.toShape() aPlane = Part.Plane(aPnt, DIR_Z) range = (myNumRot + 1) * myGrowth + 1 + myRadius aPlane.toShape().project(wire) return spiral
def getMidPlane(fp, fraction): midvec = CurvedShapes.vectorMiddle(fp.Shape1.Shape.BoundBox.Center, fp.Shape2.Shape.BoundBox.Center, fraction) midnorm = CurvedShapes.vectorMiddle(fp.NormalShape1, fp.NormalShape2, fraction) return Part.Plane(midvec, midnorm)
def StarDiag4_squish(self, fp, N): # we are going to average all poles [28] around the loop to define the squish center # sum all poles [28] Poles_28_total = Base.Vector(0, 0, 0) for i in range(N): Poles_28_total = Poles_28_total + fp.StarGrid[i][28][0] SquishCenter = (1.0 / N) * Poles_28_total # do cross products in pairs around the loops to get a list of normal direction approximations cross_total = Base.Vector(0, 0, 0) for i in range(N - 1): cross_total = cross_total + ( fp.StarGrid[i][28][0] - SquishCenter).cross(fp.StarGrid[i + 1][28][0] - SquishCenter) # close sequence by looping back cross_total = cross_total + ( fp.StarGrid[N - 1][28][0] - SquishCenter).cross(fp.StarGrid[0][28][0] - SquishCenter) # define squish plane from squish center and squish normal Squish_Plane = Part.Plane(SquishCenter, cross_total) # project all diag4 points to this plane. projections = [0] * N for i in range(N): param = Squish_Plane.parameter(fp.StarGrid[i][28][0]) fp.StarGrid[i][28][0] = Squish_Plane.value(param[0], param[1])
def testShapeFix_Shell(self): surface = Part.Plane() face = surface.toShape(-1, 1, -1, 1) shell = Part.Shell([face]) Part.ShapeFix.Shell() with self.assertRaises(TypeError): Part.ShapeFix.Face([]) fix = Part.ShapeFix.Shell(shell) fix.init(shell) print (fix) fix.perform() fix.shell() fix.shape() fix.fixFaceTool() fix.setNonManifoldFlag(True) fix.fixFaceOrientation(shell) self.assertEqual(len(fix.errorFaces().Faces), 0) self.assertEqual(fix.numberOfShells(), 1) fix.FixFaceMode = True self.assertEqual(fix.FixFaceMode, True) fix.FixOrientationMode = True self.assertEqual(fix.FixOrientationMode, True)
def StarDiag4_3Sub(self, fp, Sub_prev_i, Sub_i, Sub_next_i): # parallelogram diagonal Sub_28_raw = fp.StarGrid[Sub_i][27][0] + (fp.StarGrid[Sub_i][22][0] - fp.StarGrid[Sub_i][21][0]) # scaling factor. based on N? # no. need to fix this. the scaling factor needs to achieve alignment between neighboring subgrids if they align, # and a smooth rotation if they do not align. # something...something...angle in the normal or maybe tangent plane. something...(1-cos()) factor. if fp.N == 3: scale = 0.75 # scaled down 75% to spread out center this works quite well for triangles actually if fp.N == 5: scale = 1.25 # this is a mess. a single factor doesn't do it. oh well, moving on. Sub_28_scaled = fp.StarGrid[Sub_i][21][0] + scale * ( Sub_28_raw - fp.StarGrid[Sub_i][21][0]) Plane_prev = Part.Plane(fp.StarGrid[Sub_i][33][0], fp.StarGrid[Sub_i][23][0], fp.StarGrid[Sub_prev_i][33][0]) Plane_next = Part.Plane(fp.StarGrid[Sub_i][33][0], fp.StarGrid[Sub_i][23][0], fp.StarGrid[Sub_next_i][23][0]) Sub_28_prev_param = Plane_prev.parameter(Sub_28_scaled) Sub_28_prev_proj = Plane_prev.value(Sub_28_prev_param[0], Sub_28_prev_param[1]) Sub_28_next_param = Plane_next.parameter(Sub_28_scaled) Sub_28_next_proj = Plane_next.value(Sub_28_next_param[0], Sub_28_next_param[1]) fp.StarGrid[Sub_i][28][0] = 0.5 * Sub_28_scaled + 0.25 * ( Sub_28_prev_proj + Sub_28_next_proj) # control leg visualization Legs_Diag4 = [0, 0] Legs_Diag4[0] = Part.LineSegment(fp.StarGrid[Sub_i][22][0], fp.StarGrid[Sub_i][28][0]) Legs_Diag4[1] = Part.LineSegment(fp.StarGrid[Sub_i][27][0], fp.StarGrid[Sub_i][28][0]) # update instance property. direct assignment Legs = fp.Legs fp.Legs = Legs + Legs_Diag4 return 0
def compute_space_area(space: Part.Feature): """Compute both gross and net area""" z_min = space.Shape.BoundBox.ZMin z_sre = z_min + 1000 # 1 m above ground. See SIA 380:2015 &3.2.3 p.26-27 sre_plane = Part.Plane(FreeCAD.Vector(0, 0, z_sre), FreeCAD.Vector(0, 0, 1)) space.Area = space.Shape.common(sre_plane.toShape()).Area # TODO: Not valid yet as it return net area. Find a way to get gross space volume space.AreaAE = space.Area
def boundbox_from_intersect(curves, pos, normal, doScaleXYZ): if len(curves) == 0: return None plane = Part.Plane(pos, normal) xmin = float("inf") xmax = float("-inf") ymin = float("inf") ymax = float("-inf") zmin = float("inf") zmax = float("-inf") found = False for n in range(0, len(curves)): curve = curves[n] ipoints = [] for edge in curve.Shape.Edges: i = plane.intersect(edge.Curve) if i: for p in i[0]: vert = Part.Vertex(p) if vert.distToShape(edge)[0] < epsilon: ipoints.append(p) found = True if found == False: return None use_x = True use_y = True use_z = True if len(ipoints) > 1: use_x = doScaleXYZ[n][0] use_y = doScaleXYZ[n][1] use_z = doScaleXYZ[n][2] for p in ipoints: if use_x and p.X > xmax: xmax = p.X if use_x and p.X < xmin: xmin = p.X if use_y and p.Y > ymax: ymax = p.Y if use_y and p.Y < ymin: ymin = p.Y if use_z and p.Z > zmax: zmax = p.Z if use_z and p.Z < zmin: zmin = p.Z if xmin == float("inf") or xmax == float("-inf"): xmin = 0 xmax = 0 if ymin == float("inf") or ymax == float("-inf"): ymin = 0 ymax = 0 if zmin == float("inf") or zmax == float("-inf"): zmin = 0 zmax = 0 return FreeCAD.BoundBox(xmin, ymin, zmin, xmax, ymax, zmax)
def __init__(self): self._plane = Part.Plane() self.nb_of_turns = 2.5 self.lead = 10.0 self.cylinder = Part.Cylinder() self.cylinder.transform( FreeCAD.Placement(FreeCAD.Vector(), FreeCAD.Vector(1, 0, 0), -90).toMatrix()) self.rational_approx = True self.check_splines = False self.max_radius = 0 self._placement = FreeCAD.Placement()
def vectorMiddlePlaneNormal1(vec1, vec2, normalShape1, normalShape2): rota90 = FreeCAD.Rotation(normalShape1.cross(normalShape2), 90) normal90 = rota90.multVec(normalShape1) plane1 = Part.Plane(vec1, normal90) line2 = Part.makeLine(vec2, vec2 + normalShape2) p1 = vec1 isec = plane1.intersect(line2.Curve) if isec and len(isec[0]) == 1: p1 = CurvedShapes.PointVec(isec[0][0]) return p1
def build_faces(self, surf=None): faces = [] surf = surf or Part.Plane() #bs = BoundarySorter(wl) for wirelist in self.sort(): #print(wirelist) f = Part.Face(surf, wirelist[0]) f.validate() if len(wirelist) > 1: f.cutHoles(wirelist[1:]) f.validate() faces.append(f) return faces
def tangentTo(self, t, pt): v = self.valueAt(t) n = self.normalAt(t) tanPlane = Part.Plane(v, n) line = Part.Line(pt, pt.add(n)) ptOnPlane = tanPlane.intersect(line) res = [] if isinstance(ptOnPlane, tuple): for el in ptOnPlane: if isinstance(el, (tuple, list)): for e in el: if isinstance(e, Part.Point): res.append(FreeCAD.Vector(e.X, e.Y, e.Z).sub(v)) return (res)
def addFaceWireToSketch(fa, w, sk): curves = list() const = list() pl = Part.Plane() for idx in range(len(w.Edges)): e, fp, lp = fa.curveOnSurface(w.Edges[idx]) e3d = e.toShape(pl) tc = e3d.Curve.trim(fp, lp) curves.append(tc) o = int(sk.GeometryCount) sk.addGeometry(curves, False) for idx in range(len(curves)): const.append(Sketcher.Constraint('Block', o + idx)) sk.addConstraint(const)
def main(): obj1 = FreeCAD.ActiveDocument.getObject('CV_BAMB_ELEC_SING_Face25') f1 = obj1.Shape.Face1 surf = f1.Surface mid = surf.vIso(0.5) c0 = surf.vIso(0.0) c1 = surf.vIso(1.0) v0 = c0.toShape() v1 = c1.toShape() num = 200 inter = interp() inter.add(0, (c0.FirstParameter, c1.FirstParameter)) pl = Part.Plane() for i in range(1, num): v = float(i) / num pt = mid.value(v) tan = mid.tangent(v)[0] pl.Position = pt pl.Axis = tan pts0 = c0.intersectCS(pl)[0] pts1 = c1.intersectCS(pl)[0] pt0 = closest_point(pts0, pt) pt1 = closest_point(pts1, pt) print(pt0, pt1) inter.add(v, (c0.parameter(pt0), c1.parameter(pt1))) inter.add(1, (c0.LastParameter, c1.LastParameter)) # c = Part.makeCircle(0.3,pt,tan) # inf0 = c.distToShape(v0)[2][0] # inf1 = c.distToShape(v1)[2][0] # #print(inf0) # #print(inf1) # if inf0[3] == 'Edge' and inf1[3] == 'Edge': # inter.add(v,(inf0[5],inf1[5])) edges = list() for tu in zip(inter.param, inter.value): print(tu) l = Part.makeLine(v0.valueAt(tu[1][0]), v1.valueAt(tu[1][1])) edges.append(l) newc0 = Part.BSplineCurve() pts_0 = [v0.valueAt(v[0]) for v in inter.value] newc0.interpolate(Points=pts_0, Parameters=inter.param) Part.show(newc0.toShape()) newc1 = Part.BSplineCurve() pts_1 = [v1.valueAt(v[1]) for v in inter.value] newc1.interpolate(Points=pts_1, Parameters=inter.param) Part.show(newc1.toShape()) Part.show(Part.Compound(edges))
def addFaceWireToSketch(fa, w, sk): curves = list() const = list() pl = Part.Plane() for idx in range(len(w.Edges)): e = fa.curveOnSurface(w.Edges[idx]) e3d = e[0].toShape(pl) tc = e3d.Curve.trim(e[1], e[2]) curves.append(tc) o = int(sk.GeometryCount) sk.addGeometry(curves, False) # Coincident constraints #ar = range(len(curves))+[0] #for idx in range(len(curves)): #const.append(Sketcher.Constraint('Coincident',o+idx,2,o+ar[idx+1],1)) for idx in range(len(curves)): const.append(Sketcher.Constraint('Block', o + idx)) sk.addConstraint(const)
def testChFi2d_FilletAlgo(self): v = FreeCAD.Vector edge1 = Part.makeLine(v(0,0,0), v(0,10,0)) edge2 = Part.makeLine(v(0,10,0), v(10,10,0)) wire = Part.Wire([edge1, edge2]) pln = Part.Plane() with self.assertRaises(TypeError): alg = Part.ChFi2d.FilletAlgo(pln) alg = Part.ChFi2d.FilletAlgo() with self.assertRaises(TypeError): alg.init() print (alg) # Test without shape with self.assertRaises(Base.CADKernelError): alg.perform(1) with self.assertRaises(TypeError): alg.perform() alg = Part.ChFi2d.FilletAlgo(wire, pln) alg.init(edge1, edge2, pln) alg.init(wire, pln) alg = Part.ChFi2d.FilletAlgo(edge1, edge2, pln) alg.perform(1.0) with self.assertRaises(TypeError): alg.numberOfResults() with self.assertRaises(TypeError): alg.result(1) self.assertEqual(alg.numberOfResults(Base.Vector(0,10,0)), 1) result = alg.result(Base.Vector(0,10,0)) curve = result[0].Curve self.assertEqual(type(curve), Part.Circle) self.assertEqual(curve.Axis, pln.Axis) self.assertEqual(curve.Radius, 1.0)
def testShapeFix_Shape(self): surface = Part.Plane() face = surface.toShape(-1, 1, -1, 1) with self.assertRaises(TypeError): Part.ShapeFix.Shape([]) fix = Part.ShapeFix.Shape(face) fix.init(face) print (fix) fix.shape() fix.fixSolidTool() fix.fixShellTool() fix.fixFaceTool() fix.fixWireTool() fix.fixEdgeTool() fix.FixSolidMode = True self.assertEqual(fix.FixSolidMode, True) fix.FixFreeShellMode = True self.assertEqual(fix.FixFreeShellMode, True) fix.FixFreeFaceMode = True self.assertEqual(fix.FixFreeFaceMode, True) fix.FixFreeWireMode = True self.assertEqual(fix.FixFreeWireMode, True) fix.FixSameParameterMode = True self.assertEqual(fix.FixSameParameterMode, True) fix.FixVertexPositionMode = True self.assertEqual(fix.FixVertexPositionMode, True) fix.FixVertexTolMode = True self.assertEqual(fix.FixVertexTolMode, True) fix.perform()
def get_chord_normal_params(e1, e2, n): params = list() fp, lp = e1.ParameterRange chord = Part.makeLine(e1.valueAt(fp), e1.valueAt(lp)) pts = chord.discretize(n) plane = Part.Plane(pts[0], chord.tangentAt(chord.FirstParameter)) for pt in pts: plane.Position = pt p1 = e1.Curve.intersect(plane) p2 = e2.Curve.intersect(plane) print("{} - {}".format(p1, p2)) try: params.append([ e1.Curve.parameter( FreeCAD.Vector(p1[0][0].X, p1[0][0].Y, p1[0][0].Z)), e2.Curve.parameter( FreeCAD.Vector(p2[0][0].X, p2[0][0].Y, p2[0][0].Z)) ]) print("{}".format(params[-1])) except: _utils.warn("chord_normal compute error") return params
def angle__(): v, e1 = FreeCADGui.Selection.getSelectionEx( )[0].SubObjects # вибрати вершину і гвинтову кромку e2, f = FreeCADGui.Selection.getSelectionEx( )[1].SubObjects # вибрати різальну кромку і задню поверхню v1, v2 = e2.Vertexes v3 = v1 if not v.Point.isEqual(v1.Point, 1e-3) else v2 # v3 не v vec = e1.tangentAt(e1.parameterAt(v)) # дотична в точці vec = vec + v.Point # перемістити в положення Part.show(Part.Point(vec).toShape()) pl = Part.Plane(v.Point, v3.Point, vec) # площина різання uv = pl.parameter(v.Point) vec2 = pl.normal(uv[0], uv[1]) # нормаль до площини різання (0,0 або uv[0],uv[1]) #vec2=vec2+v.Point # перемістити в положення #Part.show(Part.Point(vec2).toShape()) # кут між площинами - це кут між їх нормалями !!! uv = f.Surface.parameter(v.Point) vec3 = f.Surface.normal( uv[0], uv[1]) # нормаль до задньої поверхні (0,0 або uv[0],uv[1]) a = vec2.getAngle(vec3) # кінематичний задній кут print np.degrees(a)
def testShapeFix_Edge(self): surface = Part.Plane() face = surface.toShape(-1, 1, -1, 1) with self.assertRaises(TypeError): Part.ShapeFix.Edge([]) wirefix = Part.ShapeFix.Wire(face.OuterWire, face, 1e-7) fix = wirefix.fixEdgeTool() print (fix) fix.fixRemovePCurve(face.Edge1, face) fix.fixRemovePCurve(face.Edge1, face.Surface, face.Placement) with self.assertRaises(TypeError): fix.fixRemovePCurve(face) fix.fixRemoveCurve3d(face.Edge1) fix.fixAddCurve3d(face.Edge1) fix.fixAddPCurve(face.Edge1, face, False) fix.fixAddPCurve(face.Edge1, face.Surface, face.Placement, False) with self.assertRaises(TypeError): fix.fixAddPCurve(face) fix.fixVertexTolerance(face.Edge1) fix.fixVertexTolerance(face.Edge1, face) fix.fixReversed2d(face.Edge1, face) fix.fixReversed2d(face.Edge1, face.Surface, face.Placement) with self.assertRaises(TypeError): fix.fixReversed2d(face) fix.fixSameParameter(face.Edge1) fix.fixSameParameter(face.Edge1, face) with self.assertRaises(TypeError): fix.fixSameParameter(face)
def make_sketch(objectslist, autoconstraints=False, addTo=None, delete=False, name="Sketch", radiusPrecision=-1): """makeSketch(objectslist,[autoconstraints],[addTo],[delete],[name],[radiusPrecision]) Makes a Sketch objectslist with the given Draft objects. Parameters ---------- objectlist: can be single or list of objects of Draft type objects, Part::Feature, Part.Shape, or mix of them. autoconstraints(False): if True, constraints will be automatically added to wire nodes, rectangles and circles. addTo(None) : if set to an existing sketch, geometry will be added to it instead of creating a new one. delete(False): if True, the original object will be deleted. If set to a string 'all' the object and all its linked object will be deleted name('Sketch'): the name for the new sketch object radiusPrecision(-1): If <0, disable radius constraint. If =0, add indiviaul radius constraint. If >0, the radius will be rounded according to this precision, and 'Equal' constraint will be added to curve with equal radius within precision. """ if not App.ActiveDocument: App.Console.PrintError("No active document. Aborting\n") return import Part from Sketcher import Constraint import Sketcher StartPoint = 1 EndPoint = 2 MiddlePoint = 3 deletable = None if not isinstance(objectslist, (list, tuple)): objectslist = [objectslist] for obj in objectslist: if isinstance(obj, Part.Shape): shape = obj elif not hasattr(obj, 'Shape'): App.Console.PrintError(translate("draft", "not shape found")) return None else: shape = obj.Shape if not DraftGeomUtils.isPlanar(shape): App.Console.PrintError( translate("draft", "All Shapes must be co-planar")) return None if addTo: nobj = addTo else: nobj = App.ActiveDocument.addObject("Sketcher::SketchObject", name) deletable = nobj if App.GuiUp: nobj.ViewObject.Autoconstraints = False # Collect constraints and add in one go to improve performance constraints = [] radiuses = {} def addRadiusConstraint(edge): try: if radiusPrecision < 0: return if radiusPrecision == 0: constraints.append( Constraint('Radius', nobj.GeometryCount - 1, edge.Curve.Radius)) return r = round(edge.Curve.Radius, radiusPrecision) constraints.append( Constraint('Equal', radiuses[r], nobj.GeometryCount - 1)) except KeyError: radiuses[r] = nobj.GeometryCount - 1 constraints.append(Constraint('Radius', nobj.GeometryCount - 1, r)) except AttributeError: pass def convertBezier(edge): if DraftGeomUtils.geomType(edge) == "BezierCurve": return (edge.Curve.toBSpline(edge.FirstParameter, edge.LastParameter).toShape()) else: return (edge) rotation = None for obj in objectslist: ok = False tp = utils.get_type(obj) if tp in ["Circle", "Ellipse"]: if obj.Shape.Edges: if rotation is None: rotation = obj.Placement.Rotation edge = obj.Shape.Edges[0] if len(edge.Vertexes) == 1: newEdge = DraftGeomUtils.orientEdge(edge) nobj.addGeometry(newEdge) else: # make new ArcOfCircle circle = DraftGeomUtils.orientEdge(edge) angle = edge.Placement.Rotation.Angle axis = edge.Placement.Rotation.Axis circle.Center = DraftVecUtils.rotate( edge.Curve.Center, -angle, axis) first = math.radians(obj.FirstAngle) last = math.radians(obj.LastAngle) arc = Part.ArcOfCircle(circle, first, last) nobj.addGeometry(arc) addRadiusConstraint(edge) ok = True elif tp == "Rectangle": if rotation is None: rotation = obj.Placement.Rotation if obj.FilletRadius.Value == 0: for edge in obj.Shape.Edges: nobj.addGeometry(DraftGeomUtils.orientEdge(edge)) if autoconstraints: last = nobj.GeometryCount - 1 segs = [last - 3, last - 2, last - 1, last] if obj.Placement.Rotation.Q == (0, 0, 0, 1): constraints.append( Constraint("Coincident", last - 3, EndPoint, last - 2, StartPoint)) constraints.append( Constraint("Coincident", last - 2, EndPoint, last - 1, StartPoint)) constraints.append( Constraint("Coincident", last - 1, EndPoint, last, StartPoint)) constraints.append( Constraint("Coincident", last, EndPoint, last - 3, StartPoint)) constraints.append(Constraint("Horizontal", last - 3)) constraints.append(Constraint("Vertical", last - 2)) constraints.append(Constraint("Horizontal", last - 1)) constraints.append(Constraint("Vertical", last)) ok = True elif tp in ["Wire", "Polygon"]: if obj.FilletRadius.Value == 0: closed = False if tp == "Polygon": closed = True elif hasattr(obj, "Closed"): closed = obj.Closed if obj.Shape.Edges: if (len(obj.Shape.Vertexes) < 3): e = obj.Shape.Edges[0] nobj.addGeometry( Part.LineSegment(e.Curve, e.FirstParameter, e.LastParameter)) else: # Use the first three points to make a working plane. We've already # checked to make sure everything is coplanar plane = Part.Plane( *[i.Point for i in obj.Shape.Vertexes[:3]]) normal = plane.Axis if rotation is None: axis = App.Vector(0, 0, 1).cross(normal) angle = DraftVecUtils.angle( normal, App.Vector(0, 0, 1)) * App.Units.Radian rotation = App.Rotation(axis, angle) for edge in obj.Shape.Edges: # edge.rotate(App.Vector(0,0,0), rotAxis, rotAngle) edge = DraftGeomUtils.orientEdge(edge, normal) nobj.addGeometry(edge) if autoconstraints: last = nobj.GeometryCount segs = list( range(last - len(obj.Shape.Edges), last - 1)) for seg in segs: constraints.append( Constraint("Coincident", seg, EndPoint, seg + 1, StartPoint)) if DraftGeomUtils.isAligned( nobj.Geometry[seg], "x"): constraints.append( Constraint("Vertical", seg)) elif DraftGeomUtils.isAligned( nobj.Geometry[seg], "y"): constraints.append( Constraint("Horizontal", seg)) if closed: constraints.append( Constraint("Coincident", last - 1, EndPoint, segs[0], StartPoint)) ok = True elif tp == "BSpline": if obj.Shape.Edges: nobj.addGeometry(obj.Shape.Edges[0].Curve) nobj.exposeInternalGeometry(nobj.GeometryCount - 1) ok = True elif tp == "BezCurve": if obj.Shape.Edges: bez = obj.Shape.Edges[0].Curve bsp = bez.toBSpline(bez.FirstParameter, bez.LastParameter) nobj.addGeometry(bsp) nobj.exposeInternalGeometry(nobj.GeometryCount - 1) ok = True elif tp == 'Shape' or hasattr(obj, 'Shape'): shape = obj if tp == 'Shape' else obj.Shape if not DraftGeomUtils.isPlanar(shape): App.Console.PrintError( translate( "draft", "The given object is not planar and cannot be converted into a sketch." )) return None if rotation is None: #rotation = obj.Placement.Rotation norm = DraftGeomUtils.getNormal(shape) if norm: rotation = App.Rotation(App.Vector(0, 0, 1), norm) else: App.Console.PrintWarning( translate( "draft", "Unable to guess the normal direction of this object" )) rotation = App.Rotation() norm = obj.Placement.Rotation.Axis if not shape.Wires: for e in shape.Edges: # unconnected edges newedge = convertBezier(e) nobj.addGeometry( DraftGeomUtils.orientEdge(newedge, norm, make_arc=True)) addRadiusConstraint(newedge) # if not addTo: # nobj.Placement.Rotation = DraftGeomUtils.calculatePlacement(shape).Rotation if autoconstraints: for wire in shape.Wires: last_count = nobj.GeometryCount edges = wire.OrderedEdges for edge in edges: newedge = convertBezier(edge) nobj.addGeometry( DraftGeomUtils.orientEdge(newedge, norm, make_arc=True)) addRadiusConstraint(newedge) for i, g in enumerate(nobj.Geometry[last_count:]): if edges[i].Closed: continue seg = last_count + i if DraftGeomUtils.isAligned(g, "x"): constraints.append(Constraint("Vertical", seg)) elif DraftGeomUtils.isAligned(g, "y"): constraints.append(Constraint("Horizontal", seg)) if seg == nobj.GeometryCount - 1: if not wire.isClosed(): break g2 = nobj.Geometry[last_count] seg2 = last_count else: seg2 = seg + 1 g2 = nobj.Geometry[seg2] end1 = g.value(g.LastParameter) start2 = g2.value(g2.FirstParameter) if DraftVecUtils.equals(end1, start2): constraints.append( Constraint("Coincident", seg, EndPoint, seg2, StartPoint)) continue end2 = g2.value(g2.LastParameter) start1 = g.value(g.FirstParameter) if DraftVecUtils.equals(end2, start1): constraints.append( Constraint("Coincident", seg, StartPoint, seg2, EndPoint)) elif DraftVecUtils.equals(start1, start2): constraints.append( Constraint("Coincident", seg, StartPoint, seg2, StartPoint)) elif DraftVecUtils.equals(end1, end2): constraints.append( Constraint("Coincident", seg, EndPoint, seg2, EndPoint)) else: for wire in shape.Wires: for edge in wire.OrderedEdges: newedge = convertBezier(edge) nobj.addGeometry( DraftGeomUtils.orientEdge(newedge, norm, make_arc=True)) ok = True gui_utils.format_object(nobj, obj) if ok and delete and hasattr(obj, 'Shape'): doc = obj.Document def delObj(obj): if obj.InList: App.Console.PrintWarning( translate( "draft", "Cannot delete object {} with dependency". format(obj.Label)) + "\n") else: doc.removeObject(obj.Name) try: if delete == 'all': objs = [obj] while objs: obj = objs[0] objs = objs[1:] + obj.OutList delObj(obj) else: delObj(obj) except Exception as ex: App.Console.PrintWarning( translate( "draft", "Failed to delete object {}: {}".format( obj.Label, ex)) + "\n") if rotation: nobj.Placement.Rotation = rotation else: print("-----error!!! rotation is still None...") nobj.addConstraint(constraints) return nobj
def getElementShape(obj, tp=None, transform=False, noElementMap=True): if not isinstance(obj, (tuple, list)): shape = obj else: sub = obj[1] shape, mat, sobj = Part.getShape(obj[0], subname=sub, needSubElement=True, retType=2, transform=transform, noElementMap=noElementMap) if not sobj: logger.trace('no sub object {}', obj, frame=1) return if sobj.isDerivedFrom('App::Line'): if tp not in (None, Part.Shape, Part.Edge): logger.trace('wrong type of shape {}', obj) return size = sobj.ViewObject.Size shape = Part.makeLine(FreeCAD.Vector(-size, 0, 0), FreeCAD.Vector(size, 0, 0)) shape.transformShape(mat, False, True) elif sobj.isDerivedFrom('App::Plane'): if tp not in (None, Part.Shape, Part.Face): logger.trace('wrong type of shape {}', obj) return size = sobj.ViewObject.Size shape = Part.makePlane(size * 2, size * 2, FreeCAD.Vector(-size, -size, 0)) shape.transformShape(mat, False, True) elif sobj.isDerivedFrom('App::Placement'): sub = sub.split('.')[-1] dmap = { '': (0, 0, 1), 'Origin': (0, 0, 1), 'Z-Axis': (0, 0, 1), 'XY-Plane': (0, 0, -1), 'X-Axis': (1, 0, 0), 'YZ-Plane': (-1, 0, 0), 'Y-Axis': (0, 1, 0), 'XZ-Plane': (0, -1, 0) } shape = Part.Face( Part.Plane(FreeCAD.Vector(), FreeCAD.Vector(*dmap[sub]))) shape.transformShape(mat, False, True) elif shape.isNull(): logger.trace('no shape {}', obj) return if not isinstance(shape, Part.Shape) or shape.isNull(): logger.trace('null shape {}', obj) return if not tp or isinstance(shape, tp): return shape elif isinstance(shape, (Part.Vertex, Part.Edge, Part.Face)): logger.trace('wrong shape type {}', obj) return elif tp is Part.Vertex: if shape.countElement('Edge'): return if shape.countElement('Vertex') == 1: return shape.Vertex1 elif tp is Part.Edge: if shape.countElement('Face'): return if shape.countElement('Edge') == 1: return shape.Edge1 elif tp is Part.Face: if shape.countElement('Face') == 1: return shape.Face1 else: logger.trace('wrong shape type {}', obj)