//-------------------------------------------------------------------------------------------------- bool _FindBendAxis(MakeContext context) { // Find the longest edge to revolve around var foundEdges = EdgeAlgo.FindLongestEdge(context.TargetFace); if (!foundEdges.axis.HasValue || !foundEdges.opAxis.HasValue) { Messages.Error("No linear edge found to bend around."); return(false); } context.BendEdge = _Reverse ? foundEdges.opEdge : foundEdges.edge; context.OppositeEdge = _Reverse ? foundEdges.edge : foundEdges.opEdge; context.BendAxis = _Reverse ? foundEdges.opAxis.Value : foundEdges.axis.Value; // Direction of the inner: Get face plane, get cross vector of edge axis and plane normal if (!FaceAlgo.GetCenteredPlaneFromFace(context.TargetFace, out var facePlane)) { Messages.Error("Face must be of planar type."); return(false); } context.TopDirection = context.BendAxis.Direction.Crossed(facePlane.Axis.Direction); // Move axis by radius to the center of the revolve var radius = Math.Max(0.001, _Radius); context.BendAxis.Translate(context.TopDirection.ToVec().Multiplied(radius)); return(true); }
public void FindMinMaxAdjacentFaces() { var box = Box.Create(10.0, 10.0, 1.0); var edge = box.GetBRep().Edges()[1]; var faces = box.GetBRep().Faces(); var result = EdgeAlgo.FindSmallestAndLargestAdjacentFaces(box.GetBRep(), edge); Assert.NotNull(result.smallestFace); Assert.NotNull(result.largestFace); Assert.AreEqual(faces[0], result.smallestFace); Assert.AreEqual(faces[5], result.largestFace); }
public void FindAdjacentFaces() { var box = Box.Create(10.0, 10.0, 1.0); var edge = box.GetBRep().Edges()[1]; var faces = box.GetBRep().Faces(); var(face1, face2) = EdgeAlgo.FindAdjacentFaces(box.GetBRep(), edge); Assert.NotNull(face1); Assert.NotNull(face2); Assert.AreEqual(faces[0], face1); Assert.AreEqual(faces[5], face2); }
public void FindLongestEdge() { var box = Box.Create(10.0, 10.0, 1.0); var face = box.GetBRep().Faces()[1]; var edges = face.Edges(); var result = EdgeAlgo.FindLongestEdge(face); Assert.NotNull(result.edge); Assert.NotNull(result.axis); Assert.NotNull(result.opEdge); Assert.NotNull(result.opAxis); Assert.AreEqual(edges[1], result.edge); Assert.AreEqual(edges[3], result.opEdge); Assert.IsTrue(result.axis.Value.IsParallel(result.opAxis.Value, Double.Epsilon)); }
//-------------------------------------------------------------------------------------------------- void _AddEdgeProperties(TopoDS_Edge edge) { const string edgecat = "Edge"; const string curvecat = "Curve"; if (Shape != null) { var subshapeRef = Shape.GetSubshapeReference(_TopLevelShape, edge); _AddProperty(edgecat, "SubshapeRef", subshapeRef?.ToString() ?? "null"); } var flags = ""; if (BRep_Tool.Degenerated(edge)) { flags += "Degenerated "; } if (BRep_Tool.SameParameter(edge)) { flags += "SameParameter "; } if (BRep_Tool.SameRange(edge)) { flags += "SameRange "; } _AddProperty(edgecat, "Is Closed", $"{(BRep_Tool.IsClosed(edge) ? "Yes" : "No")}"); _AddProperty(edgecat, "Curve Type", $"{(BRep_Tool.IsGeometric(edge) ? "Geometric Curve" : "Curve on Surface")}"); var props = new GProp_GProps(); BRepGProp.LinearProperties(BrepShape, props); _AddProperty(edgecat, "Length", $"{props.Mass()}"); _AddProperty(edgecat, "Tolerance", $"{BRep_Tool.Tolerance(edge)}"); if (!flags.IsEmpty()) { _AddProperty(edgecat, "Flags", flags); } if (BRep_Tool.IsGeometric(edge)) { // 3D curve double first = 0, last = 0; var curve = BRep_Tool.Curve(edge, ref first, ref last); if (curve != null) { _AddProperty(edgecat, "Parameter", $"({first}, {last})"); _AddProperty(curvecat, "Class", curve.GetType().Name.Replace("Geom_", "")); _AddProperty(curvecat, "Is Closed", $"{(curve.IsClosed() ? "Yes" : "No")}"); if (curve.IsPeriodic()) { _AddProperty(curvecat, "Period", $"{curve.Period()}"); } _AddProperty(curvecat, "Continuity", curve.Continuity().ToString().Replace("GeomAbs_", "")); switch (curve) { case Geom_Line line: const string linecat = "Line"; var lineLoc = line.Position().Location; _AddProperty(linecat, "Location", $"({lineLoc.X.ToRoundedString()}, {lineLoc.Y.ToRoundedString()}, {lineLoc.Z.ToRoundedString()})"); var lineDir = line.Position().Direction; _AddProperty(linecat, "Direction", $"({lineDir.X.ToRoundedString()}, {lineDir.Y.ToRoundedString()}, {lineDir.Z.ToRoundedString()})"); break; case Geom_Circle circle: const string circlecat = "Circle"; _AddProperty(circlecat, "Radius", $"{circle.Radius().ToRoundedString()}"); var circleLoc = circle.Position().Location; _AddProperty(circlecat, "Location", $"({circleLoc.X.ToRoundedString()}, {circleLoc.Y.ToRoundedString()}, {circleLoc.Z.ToRoundedString()})"); var circleDir = circle.Position().Direction; _AddProperty(circlecat, "Direction", $"({circleDir.X.ToRoundedString()}, {circleDir.Y.ToRoundedString()}, {circleDir.Z.ToRoundedString()})"); var circleXDir = circle.Position().XDirection; _AddProperty(circlecat, "X-Direction", $"({circleXDir.X.ToRoundedString()}, {circleXDir.Y.ToRoundedString()}, {circleXDir.Z.ToRoundedString()})"); var circleYDir = circle.Position().YDirection; _AddProperty(circlecat, "Y-Direction", $"({circleYDir.X.ToRoundedString()}, {circleYDir.Y.ToRoundedString()}, {circleYDir.Z.ToRoundedString()})"); break; case Geom_Ellipse ellipse: const string ellipsecat = "Ellipse"; _AddProperty(ellipsecat, "Major Radius", $"{ellipse.MajorRadius().ToRoundedString()}"); _AddProperty(ellipsecat, "Minor Radius", $"{ellipse.MinorRadius().ToRoundedString()}"); _AddProperty(ellipsecat, "Eccentricity", $"{ellipse.Eccentricity().ToRoundedString()}"); _AddProperty(ellipsecat, "Focal", $"{ellipse.Focal().ToRoundedString()}"); var ellipseFocus = ellipse.Focus1(); _AddProperty(ellipsecat, "Focus 1", $"({ellipseFocus.X.ToRoundedString()}, {ellipseFocus.Y.ToRoundedString()}, {ellipseFocus.Z.ToRoundedString()})"); ellipseFocus = ellipse.Focus2(); _AddProperty(ellipsecat, "Focus 2", $"({ellipseFocus.X.ToRoundedString()}, {ellipseFocus.Y.ToRoundedString()}, {ellipseFocus.Z.ToRoundedString()})"); var ellipseLoc = ellipse.Position().Location; _AddProperty(ellipsecat, "Location", $"({ellipseLoc.X.ToRoundedString()}, {ellipseLoc.Y.ToRoundedString()}, {ellipseLoc.Z.ToRoundedString()})"); var ellipseDir = ellipse.Position().Direction; _AddProperty(ellipsecat, "Direction", $"({ellipseDir.X.ToRoundedString()}, {ellipseDir.Y.ToRoundedString()}, {ellipseDir.Z.ToRoundedString()})"); var ellipseXDir = ellipse.Position().XDirection; _AddProperty(ellipsecat, "X-Direction", $"({ellipseXDir.X.ToRoundedString()}, {ellipseXDir.Y.ToRoundedString()}, {ellipseXDir.Z.ToRoundedString()})"); var ellipseYDir = ellipse.Position().YDirection; _AddProperty(ellipsecat, "Y-Direction", $"({ellipseYDir.X.ToRoundedString()}, {ellipseYDir.Y.ToRoundedString()}, {ellipseYDir.Z.ToRoundedString()})"); break; case Geom_BezierCurve bezier: const string beziercat = "Bézier Curve"; _AddProperty(beziercat, "Degree", $"{bezier.Degree()}"); _AddProperty(beziercat, "Pole Count", $"{bezier.NbPoles()}"); _AddProperty(beziercat, "Is Rational", $"{(bezier.IsRational() ? "Yes" : "No")}"); break; case Geom_BSplineCurve bspline: const string bsplinecat = "B-Spline Curve"; _AddProperty(bsplinecat, "Degree", $"{bspline.Degree()}"); _AddProperty(bsplinecat, "Pole Count", $"{bspline.NbPoles()}"); _AddProperty(bsplinecat, "Knoe Count", $"{bspline.NbKnots()}"); _AddProperty(bsplinecat, "Knot Distrib.", bspline.KnotDistribution().ToString().Replace("GeomAbs_", "")); _AddProperty(bsplinecat, "Is Rational", $"{(bspline.IsRational() ? "Yes" : "No")}"); break; } } } else { // Curve on surface, currently not supported } // Get continuity information var(face1, face2) = EdgeAlgo.FindAdjacentFaces(_TopLevelShape, edge); if (face1 != null && face2 != null) { _AddProperty(edgecat, "Face Contin.", BRep_Tool.Continuity(edge, face1, face2).ToString().Replace("GeomAbs_", "")); } }
//-------------------------------------------------------------------------------------------------- void _FindFacesConnectedToBendSection(MakeContext context, TopoDS_Edge sharedEdge, BendParameter bendParams) { // Find connected section faces bendParams.ConnectedInSharedEdges[0] = sharedEdge; bendParams.ConnectedInFaces[0] = FaceAlgo.FindConnectedFace(context.SourceShape, bendParams.Faces[0], sharedEdge); var opEdge = bendParams.Faces[0].Edges().Find(e => !e.IsSame(sharedEdge) && !e.IsSame(bendParams.Edges[0]) && !e.IsSame(bendParams.Edges[1])); if (opEdge != null) { bendParams.ConnectedOutSharedEdges[0] = opEdge; bendParams.ConnectedOutFaces[0] = FaceAlgo.FindConnectedFace(context.SourceShape, bendParams.Faces[0], opEdge); } // Find the other connection edge TopoDS_Vertex sharedVtx1 = null; foreach (var edge in bendParams.Faces[1].Edges()) { var vtx = EdgeAlgo.FindSharedVertex(edge, sharedEdge); if (vtx != null) { // Get the other (not shared) vertex sharedVtx1 = edge.Vertices().Find(v => !v.IsSame(vtx)); break; } } TopoDS_Vertex sharedVtx2 = null; foreach (var edge in bendParams.Faces[2].Edges()) { var vtx = EdgeAlgo.FindSharedVertex(edge, sharedEdge); if (vtx != null) { // Get the other (not shared) vertex sharedVtx2 = edge.Vertices().Find(v => !v.IsSame(vtx)); break; } } TopoDS_Edge otherSharedEdge = null; foreach (var edge in bendParams.Faces[3].Edges()) { var vertices = edge.Vertices(); if (vertices.ContainsSame(sharedVtx1) && vertices.ContainsSame(sharedVtx2)) { otherSharedEdge = edge; break; } } if (otherSharedEdge == null) { return; } // Find connected section faces for the other edge bendParams.ConnectedOutSharedEdges[1] = otherSharedEdge; bendParams.ConnectedInFaces[1] = FaceAlgo.FindConnectedFace(context.SourceShape, bendParams.Faces[3], otherSharedEdge); var otherOpEdge = bendParams.Faces[3].Edges().Find(e => !e.IsSame(otherSharedEdge) && !e.IsSame(bendParams.Edges[2]) && !e.IsSame(bendParams.Edges[3])); if (otherOpEdge != null) { bendParams.ConnectedOutSharedEdges[1] = otherOpEdge; bendParams.ConnectedOutFaces[1] = FaceAlgo.FindConnectedFace(context.SourceShape, bendParams.Faces[3], otherOpEdge); } }
//-------------------------------------------------------------------------------------------------- /* * Determine if a face belongs to a bend section. To recognise a bend section, it must have the * following structure: * - Four faces, two of them planar (side faces) and two of them cylinder (top/bottom) * - All edges connecting these four faces must be circular * - All circles must have coaxial axes with only two different positions * - All circles must have one of two radii * * If a side face is detected, the iteration of faces should stop, but no section is built. * If a top/bottom face is detected, the whole section is recovered and all parameters are * determined. The faces are found by searching for faces which share the circular edges. * * This function is called recursively if one of the out-faces is also recognized * as part of a connected bend section. */ bool _AnalyzeBendSection(MakeContext context, TopoDS_Face baseFace, TopoDS_Edge sharedEdge, out Section section) { section = null; var bendParams = new BendParameter(); bendParams.Faces[0] = baseFace; if (!_IsFaceOfBendSection(baseFace, bendParams)) { return(false); } var faceAdaptor = new BRepAdaptor_Surface(baseFace); // Surface is flat, but two edges are of circle and coplanar if (faceAdaptor.GetGeomType() == GeomAbs_SurfaceType.GeomAbs_Plane) { // Ignore them for the moment, but sign them as bend section face return(true); } if (faceAdaptor.GetGeomType() != GeomAbs_SurfaceType.GeomAbs_Cylinder) { // Surface must be of type Cylinder, other are not supported currently return(false); } // Find side faces var facesForEdge0 = EdgeAlgo.FindAdjacentFaces(context.SourceShape, bendParams.Edges[0]); bendParams.Faces[1] = facesForEdge0.face1.IsSame(baseFace) ? facesForEdge0.face2 : facesForEdge0.face1; if (!_IsFaceOfBendSection(bendParams.Faces[1], bendParams)) { return(false); } var facesForEdge1 = EdgeAlgo.FindAdjacentFaces(context.SourceShape, bendParams.Edges[1]); bendParams.Faces[2] = facesForEdge1.face1.IsSame(baseFace) ? facesForEdge1.face2 : facesForEdge1.face1; if (!_IsFaceOfBendSection(bendParams.Faces[2], bendParams)) { return(false); } // Find fourth face var facesForEdge2 = EdgeAlgo.FindAdjacentFaces(context.SourceShape, bendParams.Edges[2]); var facesForEdge3 = EdgeAlgo.FindAdjacentFaces(context.SourceShape, bendParams.Edges[3]); if (facesForEdge2.face1.IsSame(facesForEdge3.face1) || facesForEdge2.face1.IsSame(facesForEdge3.face2)) { bendParams.Faces[3] = facesForEdge2.face1; } else if (facesForEdge2.face2.IsSame(facesForEdge3.face1) || facesForEdge2.face2.IsSame(facesForEdge3.face2)) { bendParams.Faces[3] = facesForEdge2.face2; } else { return(false); // fourth face not found } if (!_IsFaceOfBendSection(bendParams.Faces[3], bendParams)) { return(false); } // Create Section section = new Section(); section.Faces.AddRange(bendParams.Faces.Where(face => face != null)); section.BendParameter = bendParams; // Find connected faces _FindFacesConnectedToBendSection(context, sharedEdge, bendParams); // Check if the connected section is also an bend section if (bendParams.ConnectedOutFaces[0] != null && _AnalyzeBendSection(context, bendParams.ConnectedOutFaces[0], bendParams.ConnectedOutSharedEdges[0], out var connectedBendSection)) { if (connectedBendSection == null) { Messages.Error("A bend section is connected to another bend section with an perpendicular direction.", "To fix this, you need to add a small flange between these two bend sections."); } section.Children.Add(connectedBendSection); } else { section.Children.Add(new Section()); // Bend sections have exactly one connected section } return(true); }
//-------------------------------------------------------------------------------------------------- bool _DoOffset(MakeContext context) { if (_Offset <= 0) { return(false); } // Move neutral plane var newPlane = context.NeutralPlane.Translated(context.Direction.ToVec().Multiplied(_Offset)); // Create section edge var faceOfPlane = new BRepBuilderAPI_MakeFace(new Geom_Plane(newPlane), Precision.Confusion()).Shape(); var section = new BRepAlgoAPI_Section(context.Face, faceOfPlane); section.Build(); if (!section.IsDone()) { Messages.Warning("The offset can not be performed, section operation failed."); return(false); } var newEdge = section.Shape().Edges().FirstOrDefault(); if (!section.IsDone() || newEdge == null) { Messages.Warning("The offset value seems to be out of range."); return(false); } if (context.ReversedFaceSense) { newEdge.Orientation(TopAbs_Orientation.TopAbs_REVERSED); } // Split face with section edge var splitShape = new BRepFeat_SplitShape(context.Source); splitShape.Add(newEdge, context.Face); splitShape.Build(); if (!splitShape.IsDone()) { Messages.Warning("The offset can not be performed, the face split operation failed."); return(false); } var newShape = splitShape.Shape(); var newFace = splitShape.DirectLeft().First().ToFace(); // Reduce continuity of new edge to C0 to allow the draft algo to make a sharp corner var(face1, face2) = EdgeAlgo.FindAdjacentFaces(newShape, newEdge); if (face1 == null || face2 == null) { Messages.Warning("The offset can not be performed, invalid face count after split operation."); return(false); } var builder = new BRep_Builder(); builder.Continuity(newEdge, face1, face2, GeomAbs_Shape.GeomAbs_C0); // Set results context.NeutralPlane = newPlane; context.Source = newShape; context.Face = newFace; UpdateModifiedSubshapes(context.Source, splitShape); return(true); }