//--------------------------------------------------------------------------------------------------

        bool _MakeBendSection(MakeContext context)
        {
            if (_Angle <= 0)
            {
                return(true);
            }

            // Make face for revolving
            var bendFace = _MakeBendSectionFace(context);

            if (bendFace == null)
            {
                return(false);
            }

            // Build bend section
            var makeRevol = new BRepPrimAPI_MakeRevol(bendFace, context.BendAxis, _Angle.Clamp(0.0, 180.0).ToRad());

            if (!makeRevol.IsDone())
            {
                Messages.Error("Failed building bending edge.");
                return(false);
            }

            context.BendSectionShape = makeRevol.Shape();
            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _BuildResultShape(MakeContext context)
        {
            context.Sewer = new BRepBuilderAPI_Sewing(1.0e-06);
            if (!_AddSectionToResult(context, context.RootSection, Trsf.Identity))
            {
                return(false);
            }

            context.Sewer.Perform();
            var sewedShape = context.Sewer.SewedShape();

            if (sewedShape.ShapeType() == TopAbs_ShapeEnum.TopAbs_SHELL)
            {
                var makeSolid = new BRepBuilderAPI_MakeSolid(sewedShape.ToShell());
                if (makeSolid.IsDone())
                {
                    context.ResultShape = makeSolid.Solid();
                    return(true);
                }
            }

            Messages.Error("Resulting faces could not be sewn to a solid.");
            context.ResultShape = sewedShape;
            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        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);
        }
示例#4
0
        //--------------------------------------------------------------------------------------------------

        protected override bool MakeInternal(MakeFlags flags)
        {
            ClearSubshapeLists();
            var context = new MakeContext();

            if (!_DoInitContext(context))
            {
                return(false);
            }

            if (!_DoBuildWireList(context))
            {
                return(false);
            }

            if (!_DoThruSections(context))
            {
                return(false);
            }

            if (!_DoThicken(context))
            {
                return(false);
            }

            BRep = context.Result;

            return(base.MakeInternal(flags));
        }
示例#5
0
        //--------------------------------------------------------------------------------------------------

        protected override bool MakeInternal(MakeFlags flags)
        {
            ClearSubshapeLists();
            var context = new MakeContext();

            if (!_DoInitContext(context))
            {
                return(false);
            }

            if (!_DoComputeArguments(context))
            {
                return(false);
            }

            _DoOffset(context); // Offset can fail

            if (!_DoDraft(context))
            {
                return(false);
            }

            BRep = context.Result;

            return(base.MakeInternal(flags));
        }
示例#6
0
        //--------------------------------------------------------------------------------------------------

        bool _DoInitContext(MakeContext context)
        {
            // We take only one source shapes
            if (Operands.Count != 1)
            {
                Messages.Error("This modifier needs exactly one source shape.");
                return(false);
            }

            context.Source = GetOperandBRep(0);
            if (context.Source == null)
            {
                Messages.Error("The preceeding shape does not provide a valid geometry.");
                return(false);
            }

            context.Face = GetOperandFace(0, _Face);
            if (context.Face == null)
            {
                Messages.Error("The face is not valid, check source shape or re-select face.");
                return(false);
            }

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _DoCutoutBoxes(MakeContext context)
        {
            var listOfTools = new TopTools_ListOfShape();

            foreach (var boxes in context.Boxes)
            {
                for (int boxIndex = _ReverseOrder == _IsFirst ? 0 : 1; boxIndex < boxes.Count; boxIndex += 2)
                {
                    listOfTools.Append(boxes[boxIndex]);
                }
            }

            var listOfArguments = new TopTools_ListOfShape();

            listOfArguments.Append(context.OwnBrep);

            var cutter = new BRepAlgoAPI_Cut();

            cutter.SetArguments(listOfArguments);
            cutter.SetTools(listOfTools);
            cutter.Build();
            if (!cutter.IsDone())
            {
                Messages.Error("Cannot cut boxes out of shape.");
                return(false);
            }

            context.Result = cutter.Shape();
            UpdateModifiedSubshapes(context.OwnBrep, cutter);

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _DoMakeCommon(MakeContext context)
        {
            // Make common
            var makeCommon = _IsFirst
                    ? new BRepAlgoAPI_Common(context.OwnBrep, context.OtherBrep)
                    : new BRepAlgoAPI_Common(context.OtherBrep, context.OwnBrep);

            if (!makeCommon.IsDone())
            {
                Messages.Error("Cannot find a common between both shapes.");
                return(false);
            }

            var commonBrep = makeCommon.Shape();
            var solids     = commonBrep.Solids();

            if (solids.Count == 0)
            {
                // Nothing in common
                return(true);
            }

            context.Common = solids;

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _BuildResult(MakeContext context)
        {
            var shapeListArgs = new TopTools_ListOfShape();

            shapeListArgs.Append(context.ModifiedTargetShape ?? context.TargetShape);

            var shapeListTools = new TopTools_ListOfShape();

            if (context.BendSectionShape != null)
            {
                shapeListTools.Append(context.BendSectionShape);
            }
            if (context.FlangeShape != null)
            {
                shapeListTools.Append(context.FlangeShape);
            }

            var fuseOp = new BRepAlgoAPI_Fuse();

            fuseOp.SetArguments(shapeListArgs);
            fuseOp.SetTools(shapeListTools);
            fuseOp.SetGlue(BOPAlgo_GlueEnum.BOPAlgo_GlueShift);
            fuseOp.Build();
            if (!fuseOp.IsDone())
            {
                Messages.Error("Failed fusing generated geometry.");
                return(false);
            }

            context.ResultShape = fuseOp.Shape();

            if (context.BendSectionShape != null)
            {
                AddNamedSubshapes("Bend", context.BendSectionShape, fuseOp);
            }
            if (context.FlangeShape != null)
            {
                AddNamedSubshapes("Flange", context.FlangeShape, fuseOp);
            }
            if (context.StartGapFace != null)
            {
                AddNamedSubshapes("StartGap", context.StartGapFace, fuseOp);
                if (context.EndGapFace == null)
                {
                    AddNamedSubshapes("EndGap", context.StartGapFace, fuseOp);
                }
            }
            if (context.EndGapFace != null)
            {
                AddNamedSubshapes("EndGap", context.EndGapFace, fuseOp);
                if (context.StartGapFace == null)
                {
                    AddNamedSubshapes("StartGap", context.EndGapFace, fuseOp);
                }
            }

            UpdateModifiedSubshapes(context.ModifiedTargetShape ?? context.TargetShape, fuseOp);

            return(true);
        }
示例#10
0
        //--------------------------------------------------------------------------------------------------

        bool _DoCutoffExcess(MakeContext context)
        {
            var listOfArguments = new TopTools_ListOfShape();

            listOfArguments.Append(context.OwnBrep);

            // Cutout Commons
            var listOfTools = new TopTools_ListOfShape();

            foreach (var commonSolid in context.Common)
            {
                listOfTools.Append(commonSolid);
            }

            var cutter = new BRepAlgoAPI_Cut();

            cutter.SetArguments(listOfArguments);
            cutter.SetTools(listOfTools);
            cutter.Build();
            if (!cutter.IsDone())
            {
                Messages.Error("Cannot determine excess of instrusion.");
                return(false);
            }

            // Check if we have more solids than before
            var originalSolidCount = context.OwnBrep.Solids().Count;
            var solids             = cutter.Shape().Solids();
            var excessCount        = solids.Count - originalSolidCount;

            if (excessCount <= 0)
            {
                return(true); // No excess found
            }
            // Cutout additional solids
            listOfTools = new TopTools_ListOfShape();
            var orderedSolids = solids.OrderBy(solid => solid.Volume()).Take(excessCount);

            foreach (var solid in orderedSolids)
            {
                listOfTools.Append(solid);
            }

            cutter = new BRepAlgoAPI_Cut();
            cutter.SetArguments(listOfArguments);
            cutter.SetTools(listOfTools);
            cutter.Build();
            if (!cutter.IsDone())
            {
                Messages.Error("Cannot remove excess of instrusion from shape.");
                return(false);
            }

            UpdateModifiedSubshapes(context.OwnBrep, cutter);
            context.OwnBrep = cutter.Shape();
            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        protected override bool MakeInternal(MakeFlags flags)
        {
            ClearSubshapeLists();

            // Currently we work with 1 source shape only
            if (Operands.Count != 1 || _Face == null)
            {
                return(false);
            }

            // Get Targets
            var context = new MakeContext
            {
                TargetShape = GetOperandBRep(0),
                TargetFace  = GetOperandFace(0, Face)
            };

            // Check targets
            if (context.TargetShape == null)
            {
                return(false);
            }
            if (context.TargetFace == null)
            {
                Messages.Error("Face for adding flange cannot be found in shape and needs to be reselected.");
                return(false);
            }

            // Skip if we have nothing to do
            if (_Angle == 0 && _Length <= 0)
            {
                return(Skip());
            }

            // Make it!
            if (!(_FindBendAxis(context) &&
                  _MakeFlangeFace(context) &&
                  _MakeBendSection(context) &&
                  _MakeFlangeSection(context) &&
                  _BuildResult(context)))
            {
                return(false);
            }

            if (context.ResultShape == null)
            {
                return(Skip());
            }

            BRep = context.ResultShape;

            return(base.MakeInternal(flags));
        }
示例#12
0
        //--------------------------------------------------------------------------------------------------

        protected override bool MakeInternal(MakeFlags flags)
        {
            ClearSubshapeLists();

            // Check if connection is valid
            if (AssociatedShape == null)
            {
                return(Skip());
            }

            var context = new MakeContext();

            if (!_DoInitContext(context))
            {
                return(false);
            }

            // Build common Solid
            if (!_DoMakeCommon(context))
            {
                return(false);
            }

            // Nothing in Common
            if (context.Common == null)
            {
                return(Skip());
            }

            // Create box pieces
            if (!_DoCreateBoxes(context))
            {
                return(false);
            }

            // Cutoff Excess
            if (_RemoveExcess && !_DoCutoffExcess(context))
            {
                return(false);
            }

            // Cut box pieces out of the shape
            if (!_DoCutoutBoxes(context))
            {
                return(false);
            }

            BRep = context.Result;

            return(base.MakeInternal(flags));
        }
        //--------------------------------------------------------------------------------------------------

        TopoDS_Face _MakeBendSectionFace(MakeContext context)
        {
            if (_Relief == ReliefFlags.None)
            {
                return(context.FlangeFace);
            }

            if (context.OppositeEdge == null)
            {
                Messages.Error("No opposite edge found for building relief.");
                return(null);
            }

            if (_Relief.HasFlag(Relief & ReliefFlags.Rectangular))
            {
                // Get notch depth = half distance between both bend and op edge
                var distTool    = new BRepExtrema_DistShapeShape(context.BendEdge, context.OppositeEdge);
                var notchDepth  = distTool.Value() * 0.5;
                var notchVector = context.TopDirection.ToVec().Multiplied(-notchDepth);

                // Get edge points
                var points = new Pnt[4];

                var bendEdgeAdaptor = new BRepAdaptor_Curve(context.BendEdge);
                points[0] = bendEdgeAdaptor.Value(bendEdgeAdaptor.FirstParameter());
                points[1] = bendEdgeAdaptor.Value(bendEdgeAdaptor.LastParameter());

                var opEdgeAdaptor = new BRepAdaptor_Curve(context.OppositeEdge);
                points[2] = opEdgeAdaptor.Value(opEdgeAdaptor.LastParameter());
                points[3] = opEdgeAdaptor.Value(opEdgeAdaptor.FirstParameter());

                // Move
                if (_Relief.HasFlag(ReliefFlags.OppositeSide))
                {
                    notchVector.Reverse();
                    points[2].Translate(notchVector);
                    points[3].Translate(notchVector);
                }
                else
                {
                    points[0].Translate(notchVector);
                    points[1].Translate(notchVector);
                }

                // Make face
                return(TopoUtils.MakeFace(points));
            }

            return(null);
        }
示例#14
0
        //--------------------------------------------------------------------------------------------------

        bool _DoComputeArguments(MakeContext context)
        {
            switch (_BaseEdgeOrVertex.Type)
            {
            case SubshapeType.Edge:
                return(_DoComputeArgumentsByEdge(context));

            case SubshapeType.Vertex:
                return(_DoComputeArgumentsByVertex(context));

            default:
                Messages.Error("The base subshape is not an edge or a vertex.");
                return(false);
            }
        }
        //--------------------------------------------------------------------------------------------------

        bool _InitMake(out MakeContext context)
        {
            var body = Owner as Body;

            context = new MakeContext();

            var shape = GetShape();

            if (shape == null)
            {
                Messages.Error("The source shape cannot be found. Please reselect the shape or use top shape.");
                return(false);
            }

            context.SourceShape = shape?.GetBRep();

            if (context.SourceShape == null)
            {
                Messages.Error("The shape does not generate valid data.");
                return(false);
            }

            // Get Reference Face
            if (ReferenceFace == null)
            {
                // Find biggest face
                var(face1, plane1, face2, plane2) = FaceAlgo.FindFaceByAreaSize(context.SourceShape, (area1, area2) => area1 > area2);
                if (plane1 == null || plane2 == null)
                {
                    Messages.Error("Reference face cannot be automatically detected.");
                    return(false);
                }

                // Find the face which is nearer to the XoY-Plane
                context.ReferenceFace = plane1.Value.Distance(Pln.XOY) > plane2.Value.Distance(Pln.XOY) ? face2 : face1;
            }
            else
            {
                context.ReferenceFace = shape.FindSubshape(ReferenceFace, null).FirstOrDefault()?.ToFace();
                if (context.ReferenceFace == null)
                {
                    Messages.Error("Manual reference face cannot be found and needs to be reselected.");
                    return(false);
                }
            }

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _Slice(MakeContext context)
        {
            context.Slicer = new SliceByPlanes(context.SourceShape, context.ReferenceFace, LayerCount);
            if (!context.Slicer.CreateSlices(false))
            {
                return(false);
            }

            _Layers = new SliceByPlanes.Slice[context.Slicer.Slices.Length];
            for (int index = 0; index < context.Slicer.Slices.Length; index++)
            {
                Layers[index] = context.Slicer.Slices[index];
            }

            return(true);
        }
示例#17
0
        //--------------------------------------------------------------------------------------------------

        bool _DoInitContext(MakeContext context)
        {
            // We need a minimum of 2 source shapes
            if (Operands.Count < 2)
            {
                Messages.Error("This modifier needs at least two sketches defining the loft start and end sections.");
                return(false);
            }

            if (Operands.Any(op => op.GetShapeType() != ShapeType.Sketch))
            {
                Messages.Error("This modifier does only take sketches defining the loft sections as operands.");
                return(false);
            }

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _InitContext(MakeContext context)
        {
            // Currently we work with 1 source shape only
            if (Operands.Count != 1)
            {
                return(false);
            }

            // Get Targets
            context.SourceShape = GetOperandBRep(0);

            if (context.SourceShape == null)
            {
                return(false);
            }

            if (_StartFace == null)
            {
                context.StartFace = FaceAlgo.FindFaceNearestToPlane(context.SourceShape, Pln.XOY);
                if (context.StartFace == null)
                {
                    Messages.Error("Reference face cannot be automatically detected needs to be manually selected.");
                    return(false);
                }

                if (context.DebugOutput)
                {
                    Messages.Trace($"Automatically detected reference face has index {context.SourceShape.Faces().IndexOf(context.StartFace)}");
                }
            }
            else
            {
                context.StartFace = GetOperandFace(0, _StartFace);
                if (context.StartFace == null)
                {
                    Messages.Error("Manual reference face cannot be found and needs to be reselected.");
                    return(false);
                }
            }


            return(true);
        }
示例#19
0
        //--------------------------------------------------------------------------------------------------

        bool _DoComputeArgumentsByEdge(MakeContext context)
        {
            var edge = GetOperandEdge(0, _BaseEdgeOrVertex, context.Face);

            if (edge == null)
            {
                Messages.Error("The face is not valid, check source shape or re-select face.");
                return(false);
            }

            if (!ComputeAxisFromEdge(context.Face, edge, _BaseParameter, out var axis))
            {
                Messages.Error("The axis can not be computed by the base edge. Please re-select edge.");
            }

            context.Direction         = axis.Direction;
            context.NeutralPlane      = new Pln(axis.Location, axis.Direction);
            context.ReversedFaceSense = edge.Orientation() == TopAbs_Orientation.TopAbs_REVERSED;
            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        bool _MakeFlangeSection(MakeContext context)
        {
            if (_Length <= 0)
            {
                return(true);
            }

            var brepAdaptor = new BRepAdaptor_Surface(context.FlangeFace);

            if (brepAdaptor.GetGeomType() != GeomAbs_SurfaceType.GeomAbs_Plane)
            {
                Messages.Error("Flanges can only be added to planar faces.");
                return(false);
            }
            var direction = brepAdaptor.Plane().Position.Direction;

            if (context.FlangeFace.Orientation() == TopAbs_Orientation.TopAbs_REVERSED)
            {
                direction.Reverse();
            }

            // Extrude
            var makePrism = new BRepPrimAPI_MakePrism(context.FlangeFace, direction.ToVec().Multiplied(_Length));

            if (!makePrism.IsDone())
            {
                Messages.Error("Failed building flange.");
                return(false);
            }
            var flangeShape = makePrism.Shape();

            // Rotate if bended
            if (_Angle > 0)
            {
                var trsf = new Trsf(context.BendAxis, _Angle.Clamp(0.0, 180.0).ToRad());
                flangeShape.Location(new TopLoc_Location(trsf));
            }

            context.FlangeShape = flangeShape;
            return(true);
        }
示例#21
0
        //--------------------------------------------------------------------------------------------------

        bool _DoInitContext(MakeContext context)
        {
            // Currently we work with 2 source shape only
            if (Operands.Count != 2)
            {
                Messages.Error("This modifier needs exactly two operands.");
                return(false);
            }

            // The second operand must be a body
            var op1Body = GetOperand(1) as BodyShapeOperand;

            if (op1Body == null)
            {
                Messages.Error("The associated operand is not a valid body.");
                return(false);
            }

            if (AssociatedShape.Body != op1Body.Body)
            {
                Messages.Error("The associated shape is not found on the operand body.");
                return(false);
            }

            // Get BReps
            context.OwnBrep = GetOperandBRep(0);
            if (context.OwnBrep == null)
            {
                Messages.Error("The predecessor shape is not valid.");
                return(false);
            }

            context.OtherBrep = AssociatedShape.GetSourceBRep(GetCoordinateSystem());
            if (context.OtherBrep == null)
            {
                Messages.Error("The associated shape is not valid.");
                return(false);
            }

            return(true);
        }
示例#22
0
        //--------------------------------------------------------------------------------------------------

        bool _DoComputeArgumentsByVertex(MakeContext context)
        {
            var vertex = GetOperandVertex(0, _BaseEdgeOrVertex);

            if (vertex == null)
            {
                Messages.Error("The vertex is not valid, check source shape or re-select vertex.");
                return(false);
            }

            if (!ComputeAxisFromVertex(context.Face, vertex, out var axis))
            {
                Messages.Error("The axis can not be computed by the base vertex. Please re-select vertex.");
            }

            // Calc Direction and NeutralPlane
            context.Direction         = axis.Direction;
            context.NeutralPlane      = new Pln(axis.Location, axis.Direction);
            context.ReversedFaceSense = context.Face.Orientation() != TopAbs_Orientation.TopAbs_REVERSED;
            return(true);
        }
示例#23
0
        //--------------------------------------------------------------------------------------------------

        bool _DoThruSections(MakeContext context)
        {
            var maker = new BRepOffsetAPI_ThruSections(context.AllWiresClosed);

            maker.CheckCompatibility(true);
            foreach (var wireInfo in context.Wires)
            {
                maker.AddWire(wireInfo.Wire);
            }

            maker.Build();
            if (!maker.IsDone())
            {
                Messages.Error("Make thru sections failed.");
                return(false);
            }

            context.Result    = maker.Shape();
            context.StartFace = maker.FirstShape().ToFace();
            context.EndFace   = maker.LastShape().ToFace();

            return(true);
        }
示例#24
0
        //--------------------------------------------------------------------------------------------------

        bool _DoDraft(MakeContext context)
        {
            var draftAngle = new BRepOffsetAPI_DraftAngle(context.Source);

            draftAngle.Add(context.Face, context.Direction, _Angle.ToRad(), context.NeutralPlane);
            if (!draftAngle.AddDone())
            {
                Messages.Error("The tapering has failed due to invalid input data. Please review your inputs.");
                return(false);
            }

            draftAngle.Build();
            if (!draftAngle.IsDone())
            {
                Messages.Error("Make draft angle failed.");
                return(false);
            }

            context.Result = draftAngle.Shape();
            UpdateModifiedSubshapes(context.Source, draftAngle);

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        protected override bool MakeInternal(MakeFlags flags)
        {
            ClearSubshapeLists();

            // Make it!
            var context = new MakeContext
            {
                DebugOutput = flags.HasFlag(MakeFlags.DebugOutput)
            };

            if (!(_InitContext(context) &&
                  _AnalyzeTopology(context)))
            {
                return(false);
            }

            // Skip if we have only one section
            if (!context.RootSection.Children.Any())
            {
                return(Skip());
            }

            if (!_BuildResultShape(context))
            {
                return(false);
            }

            if (context.ResultShape == null)
            {
                return(Skip());
            }

            BRep = context.ResultShape;

            return(base.MakeInternal(flags));
        }
        //--------------------------------------------------------------------------------------------------

        bool _AddSectionToResult(MakeContext context, Section section, Trsf transformation)
        {
            if (section.IsBendSection)
            {
                // Calculate k-factor and bend allowance
                // k = 0.65 + 0.5 * log(r/s)
                // This is DIN/ISO value range of 0..2
                var thickness     = section.BendParameter.Radii[0].Distance(section.BendParameter.Radii[1]).Abs();
                var radius        = Math.Min(section.BendParameter.Radii[0], section.BendParameter.Radii[1]);
                var kfac          = (0.65 + 0.5 * Math.Log10(radius / thickness)).Clamp(0.0, 1.0);
                var bendAllowance = (radius + thickness * 0.5 * kfac) * section.BendParameter.AngleRad;
                if (context.DebugOutput)
                {
                    Messages.Trace($"The bend section has following parameters: thickness {thickness} radius {radius} kfactor {kfac} angle {section.BendParameter.AngleRad} bend allowance {bendAllowance}.");
                }

                var axes = new []
                {
                    section.BendParameter.Axes[0],
                    section.BendParameter.Axes[1]
                };

                // Which side of the bend section is our in-side?
                // A point translated along the XDirection of the axis using one of the radii must be on the edge.
                var swapSign    = 1.0;
                var edgeAdaptor = new BRepAdaptor_Curve(section.BendParameter.ConnectedInSharedEdges[0]);
                var pnt0        = axes[0].Location.Translated(axes[0].XDirection.ToVec() * section.BendParameter.Radii[0]);
                var pnt1        = axes[0].Location.Translated(axes[0].XDirection.ToVec() * section.BendParameter.Radii[1]);
                if (!(edgeAdaptor.Line().Contains(pnt0, 0.000001) || edgeAdaptor.Line().Contains(pnt1, 0.000001)))
                {
                    swapSign = -1.0;
                    axes[0].Rotate(section.BendParameter.Axes[0].Axis, section.BendParameter.AngleRad);
                    axes[1].Rotate(section.BendParameter.Axes[1].Axis, section.BendParameter.AngleRad);
                }
                axes[0].Transform(transformation);
                axes[1].Transform(transformation);

                // Create no bend section, if kfac==0
                if (kfac > 0.0)
                {
                    // Reconstruct faces
                    var pnts = new Pnt[4]; // Corner points of one section
                    pnts[0] = axes[0].Location.Translated(axes[0].XDirection.ToVec() * section.BendParameter.Radii[0]);
                    pnts[1] = axes[1].Location.Translated(axes[1].XDirection.ToVec() * section.BendParameter.Radii[0]);
                    pnts[2] = axes[0].Location.Translated(axes[0].XDirection.ToVec() * section.BendParameter.Radii[1]);
                    pnts[3] = axes[1].Location.Translated(axes[1].XDirection.ToVec() * section.BendParameter.Radii[1]);
                    var extrudeVec = axes[0].YDirection.ToVec() * swapSign * bendAllowance; // Vector to extrude to the other section

                    // Top/Bottom
                    context.Sewer.Add(TopoUtils.MakeFace(new[] { pnts[0], pnts[0].Translated(extrudeVec), pnts[1].Translated(extrudeVec), pnts[1] }));
                    context.Sewer.Add(TopoUtils.MakeFace(new[] { pnts[2], pnts[2].Translated(extrudeVec), pnts[3].Translated(extrudeVec), pnts[3] }));
                    // Sides
                    context.Sewer.Add(TopoUtils.MakeFace(new[] { pnts[0], pnts[0].Translated(extrudeVec), pnts[2].Translated(extrudeVec), pnts[2] }));
                    context.Sewer.Add(TopoUtils.MakeFace(new[] { pnts[1], pnts[1].Translated(extrudeVec), pnts[3].Translated(extrudeVec), pnts[3] }));
                }

                // Create transform for connected sections
                var rotTrsf = new Trsf(axes[0].Axis, swapSign * -section.BendParameter.AngleRad);
                transformation.PreMultiply(rotTrsf);
                var dispTrsf = new Trsf(axes[0].YDirection.ToVec() * swapSign * bendAllowance);
                transformation.PreMultiply(dispTrsf);

                //section.Faces.ForEach(f => context.Sewer.Add(f));
            }
            else
            {
                // Copy all faces to the result
                foreach (var face in section.Faces)
                {
                    var transformedFace = face.Moved(new TopLoc_Location(transformation));
                    context.Sewer.Add(transformedFace);
                    //context.Sewer.Add(face);
                }
            }

            // Process children
            foreach (var child in section.Children)
            {
                _AddSectionToResult(context, child, transformation);
            }

            return(true);
        }
        //--------------------------------------------------------------------------------------------------

        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);
        }
        //--------------------------------------------------------------------------------------------------

        /*
         * Division of the shape in different sections. Sections contain all faces of a flange, and
         * are connected with bend sections.
         * Start with the start face and examine all connected faces. If an face is part of a bend section,
         * stop here. If not, add it to the current section and add it to the queue of faces whose connected
         * faces are to examined.
         * Don't process any face twice.
         * If a bend section is determined, add it to the list of connected sections and to the queue of
         * sections to process.
         * If a bend section is processed, all connected faces, which are part of the bend section or
         * the parent section, are sorted out by the processedFaces list, so they must be part of the then
         * current section.
         */
        bool _AnalyzeTopology(MakeContext context)
        {
            var queuedSections = new Queue <Section>();
            var queuedFaces    = new Queue <TopoDS_Face>();
            var processedFaces = new List <TopoDS_Face>();
            var abandonedFaces = new List <TopoDS_Face>(); // Faces that are falsely detected as side faces of a bend section

            // Init algorithm with root section and reference face
            context.RootSection = new Section();
            context.RootSection.Faces.Add(context.StartFace);
            processedFaces.Add(context.StartFace);
            queuedSections.Enqueue(context.RootSection);

            // Iterate
            while (queuedSections.Any())
            {
                var currentSection = queuedSections.Dequeue();
                queuedFaces.Clear();
                queuedFaces.EnqueueMany(currentSection.Faces);

                while (queuedFaces.Any())
                {
                    var currentFace = queuedFaces.Dequeue();

                    // Enumerate connected faces
                    var connectedFaces = FaceAlgo.FindConnectedFaces(context.SourceShape, currentFace);
                    foreach (var connectedFace in connectedFaces.Keys)
                    {
                        if (processedFaces.ContainsSame(connectedFace))
                        {
                            continue;
                        }
                        processedFaces.Add(connectedFace);

                        if (currentSection.IsBendSection)
                        {
                            if (currentSection.Faces.ContainsSame(connectedFace))
                            {
                                continue;
                            }
                            if (_IsFaceOfBendSection(connectedFace, null))
                            {
                                continue;
                            }

                            // Add to following section
                            currentSection.Children.First().Faces.Add(connectedFace);
                        }
                        else
                        {
                            // Bend section detection
                            if (_AnalyzeBendSection(context, connectedFace, connectedFaces[connectedFace], out var bendSection))
                            {
                                if (bendSection == null)
                                {
                                    // No section was created, face is suspect, but not convicted
                                    // Keep it as abandoned until it is clearly part of a bend section
                                    abandonedFaces.Add(connectedFace);
                                }
                                else
                                {
                                    currentSection.Children.Add(bendSection);
                                    processedFaces.AddRange(bendSection.Faces);

                                    // Add the opposite face to the processing list,for the case that it is connected only to bend sections
                                    var connectedOpFace = bendSection.BendParameter.ConnectedInFaces[1];
                                    if (connectedOpFace != null && !currentSection.Faces.ContainsSame(connectedOpFace))
                                    {
                                        currentSection.Faces.Add(connectedOpFace);
                                        processedFaces.Add(connectedOpFace);
                                        queuedFaces.Enqueue(connectedOpFace);
                                    }

                                    // Clear all detected faces out of the abandoned list
                                    foreach (var sectionFace in bendSection.Faces)
                                    {
                                        var sameFaceId = abandonedFaces.IndexOfSame(sectionFace);
                                        if (sameFaceId >= 0)
                                        {
                                            abandonedFaces.RemoveAt(sameFaceId);
                                        }
                                    }
                                }
                                continue;
                            }

                            // No bend section detected, take it into this node
                            currentSection.Faces.Add(connectedFace);
                            queuedFaces.Enqueue(connectedFace);
                        }
                    }
                }

                // Abandoned faces should now put to the current section
                foreach (var abandonedFace in abandonedFaces)
                {
                    if (!currentSection.Faces.ContainsSame(abandonedFace))
                    {
                        currentSection.Faces.Add(abandonedFace);
                    }
                }
                abandonedFaces.Clear();

                // Add next sections
                queuedSections.EnqueueMany(currentSection.Children);
            }

            // Debug output
            void _PrintSectionInfo(Section section, string id)
            {
                if (section.IsBendSection)
                {
                    Messages.Trace($"Analyze: {id} BendSection with {section.Faces.Count} faces, Radii {section.BendParameter.Radii[0]} and {section.BendParameter.Radii[1]} .");
                }
                else
                {
                    Messages.Trace($"Analyze: {id} Section with {section.Faces.Count} faces and {section.Children.Count} children.");
                }

                for (var sectionIndex = 0; sectionIndex < section.Children.Count; sectionIndex++)
                {
                    _PrintSectionInfo(section.Children[sectionIndex], id + ":" + sectionIndex);
                }
            }

            if (context.DebugOutput)
            {
                _PrintSectionInfo(context.RootSection, "0");
            }

            return(true);
        }
示例#30
0
        //--------------------------------------------------------------------------------------------------

        bool _DoThicken(MakeContext context)
        {
            // Do we need to thicken?
            if (context.AllWiresClosed &&
                _StartCapping != CappingMode.None &&
                _EndCapping != CappingMode.None)
            {
                return(true);
            }

            // Get tolerance
            var anaTolerance = new ShapeAnalysis_ShapeTolerance();
            var tolerance    = anaTolerance.Tolerance(context.Result, 1, TopAbs_ShapeEnum.TopAbs_SHAPE); // Get max of all

            var joinType = _ThickenCornerType == CornerType.Round ? GeomAbs_JoinType.GeomAbs_Arc : GeomAbs_JoinType.GeomAbs_Intersection;

            if (context.AllWiresClosed)
            {
                // Thicken Solid and remove Caps
                var removeFaceList = new TopTools_ListOfShape();
                if (_StartCapping == CappingMode.None)
                {
                    removeFaceList.Append(context.StartFace);
                }

                if (_EndCapping == CappingMode.None)
                {
                    removeFaceList.Append(context.EndFace);
                }

                // Build thicken solid
                var makeThick     = new BRepOffsetAPI_MakeThickSolid();
                var thicknessSign = ThickenDirection == Direction.Inwards ? -1 : 1;
                makeThick.MakeThickSolidByJoin(context.Result, removeFaceList, Thickness * thicknessSign, tolerance,
                                               BRepOffset_Mode.BRepOffset_Skin, true, false, joinType);

                if (!makeThick.IsDone())
                {
                    Messages.Error($"Failed to thicken solid: {makeThick.MakeOffset().Error().ToString()}.");
                    return(false);
                }

                context.Result = makeThick.Shape();
            }
            else
            {
                // Thicken shell
                var shell = context.Result.Shells()[0];
                if (shell == null)
                {
                    Messages.Error("Generated shell is invalid.");
                    return(false);
                }

                var makeThick     = new BRepOffset_MakeOffset();
                var thicknessSign = ThickenDirection == Direction.Inwards ? -1 : 1;
                makeThick.Initialize(shell, Thickness * thicknessSign, tolerance,
                                     BRepOffset_Mode.BRepOffset_Skin, true, false, joinType, true);
                makeThick.MakeOffsetShape();

                if (!makeThick.IsDone())
                {
                    Messages.Error($"Failed converting shell to thick solid: {makeThick.Error().ToString()}.");
                    return(false);
                }

                context.Result = makeThick.Shape();
                TopoUtils.UpdateSolidOrientation(context.Result);
            }

            return(true);
        }