// Copyright (c) 1998-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= // function : DistanceOut // purpose : Compute the minimum distance between input shapes // (using Bounding Boxes of each Shape) //======================================================================= static double DistanceOut(const TopoDS_Shape& S1, const TopoDS_Shape& S2) { Bnd_Box BBox1, BBox2; BRepBndLib::Add(S1, BBox1); BRepBndLib::Add(S2, BBox2); return BBox1.Distance(BBox2); } //======================================================================= // function : DistanceIn // purpose : Compute the maximum distance between input Shapes // we compute the maximum dimension of each Bounding Box and then // add each other with the minimum distance of shapes. //======================================================================= static double DistanceIn(const TopoDS_Shape& S1, const TopoDS_Shape& S2) { Bnd_Box LBBox, SBBox; BRepBndLib::Add(S1, SBBox); BRepBndLib::Add(S2, LBBox); double LXmin, LYmin, LZmin, LXmax, LYmax, LZmax, SXmin, SYmin, SZmin, SXmax, SYmax, SZmax; SBBox.Get(SXmin, SYmin, SZmin, SXmax, SYmax, SZmax); LBBox.Get(LXmin, LYmin, LZmin, LXmax, LYmax, LZmax); // Compute the max distance between input shapes------------// gp_XYZ Lmin(LXmin, LYmin, LZmin), Lmax(LXmax, LYmax, LZmax); gp_XYZ Smin(SXmin, SYmin, SZmin), Smax(SXmax, SYmax, SZmax); Lmax.Subtract(Lmin); Smax.Subtract(Smin); return Lmax.Modulus() + Smax.Modulus() + DistanceOut(S1, S2); } //======================================================================= // function : BuildSection // purpose : Cuts theShape by theTool using BRepAlgoAPI_Section and // stores result as set of connected wires and compound //======================================================================= void BRepProj_Projection::BuildSection(const TopoDS_Shape& theShape, const TopoDS_Shape& theTool) { myIsDone = false; mySection.Nullify(); myShape.Nullify(); myItr = 0; // if theShape is compound, extract only faces -- section algorithm // may refuse to work if e.g. vertex is present TopoDS_Shape aShape; if (theShape.ShapeType() == TopAbs_FACE || theShape.ShapeType() == TopAbs_SHELL || theShape.ShapeType() == TopAbs_SOLID || theShape.ShapeType() == TopAbs_COMPSOLID) aShape = theShape; else if (theShape.ShapeType() == TopAbs_COMPOUND) { TopoDS_Compound C; BRep_Builder B; TopExp_Explorer exp(theShape, TopAbs_FACE); for (; exp.More(); exp.Next()) { if (C.IsNull()) B.MakeCompound(C); B.Add(C, exp.Current()); } aShape = C; } if (aShape.IsNull()) throw Standard_ConstructionError(__FILE__ ": target shape has no faces"); // build section computing p-curves on both shapes to get higher precision BRepAlgoAPI_Section aSectionTool(aShape, theTool, false); aSectionTool.Approximation(true); aSectionTool.ComputePCurveOn1(true); aSectionTool.ComputePCurveOn2(true); // Use Oriented Bounding Boxes inside Booleans to speed up calculation of the section aSectionTool.SetUseOBB(true); aSectionTool.Build(); // check for successful work of the section tool if (!aSectionTool.IsDone()) return; // get edges of the result occ::handle> anEdges = new NCollection_HSequence; TopExp_Explorer exp(aSectionTool.Shape(), TopAbs_EDGE); for (; exp.More(); exp.Next()) anEdges->Append(exp.Current()); // if no edges are found, this means that this section yields no result if (anEdges->Length() <= 0) return; // connect edges to wires using ShapeAnalysis functionality mySection = ShapeAnalysis_FreeBounds::ConnectEdgesToWires(anEdges, Precision::Confusion(), true); myIsDone = (!mySection.IsNull() && mySection->Length() > 0); // collect all resulting wires to compound if (myIsDone) { BRep_Builder B; B.MakeCompound(myShape); for (int i = 1; i <= mySection->Length(); i++) B.Add(myShape, mySection->Value(i)); // initialize iteration (for compatibility with previous versions) myItr = 1; } } //================================================================================================= BRepProj_Projection::BRepProj_Projection(const TopoDS_Shape& Wire, const TopoDS_Shape& Shape, const gp_Dir& D) : myIsDone(false), myItr(0) { // Check the input Standard_NullObject_Raise_if((Wire.IsNull() || Shape.IsNull()), __FILE__ ": null input shape"); if (Wire.ShapeType() != TopAbs_EDGE && Wire.ShapeType() != TopAbs_WIRE) throw Standard_ConstructionError(__FILE__ ": projected shape is neither wire nor edge"); // compute the "length" of the cylindrical surface to build double mdis = DistanceIn(Wire, Shape); gp_Vec Vsup(D.XYZ() * 2 * mdis); gp_Vec Vinf(D.XYZ() * -mdis); // move the base of the cylindrical surface by translating it by -mdis gp_Trsf T; T.SetTranslation(Vinf); // Note: it is necessary to create copy of wire to avoid adding new pcurves into it occ::handle Trsf = new BRepTools_TrsfModification(T); BRepTools_Modifier Modif(Wire, Trsf); const TopoDS_Shape& WireBase = Modif.ModifiedShape(Wire); // Creation of a cylindrical surface BRepSweep_Prism CylSurf(WireBase, Vsup, false); // Perform section BuildSection(Shape, CylSurf.Shape()); } //================================================================================================= BRepProj_Projection::BRepProj_Projection(const TopoDS_Shape& Wire, const TopoDS_Shape& Shape, const gp_Pnt& P) : myIsDone(false), myItr(0) { // Check the input Standard_NullObject_Raise_if((Wire.IsNull() || Shape.IsNull()), __FILE__ ": null input shape"); if (Wire.ShapeType() != TopAbs_EDGE && Wire.ShapeType() != TopAbs_WIRE) throw Standard_ConstructionError(__FILE__ ": projected shape is neither wire nor edge"); // if Wire is only an edge, transform it into a Wire TopoDS_Wire aWire; if (Wire.ShapeType() == TopAbs_EDGE) { BRep_Builder BB; BB.MakeWire(aWire); BB.Add(aWire, Wire); } else aWire = TopoDS::Wire(Wire); // compute the "length" of the conical surface to build double mdis = DistanceIn(Wire, Shape); // Initialize iterator to get first sub-shape of Wire TopExp_Explorer ExpWire; ExpWire.Init(aWire, TopAbs_VERTEX); // get the first Point of the first sub-shape os the Wire gp_Pnt PC = BRep_Tool::Pnt(TopoDS::Vertex(ExpWire.Current())); // compute the ratio of the scale transformation double Scale = PC.Distance(P); if (std::abs(Scale) < Precision::Confusion()) throw Standard_ConstructionError("Projection"); Scale = 1. + mdis / Scale; // move the base of the conical surface by scaling it with ratio Scale gp_Trsf T; T.SetScale(P, Scale); occ::handle Tsca = new BRepTools_TrsfModification(T); BRepTools_Modifier ModifScale(aWire, Tsca); TopoDS_Shape ShapeGen1 = ModifScale.ModifiedShape(aWire); TopoDS_Vertex aVertex = BRepLib_MakeVertex(P); TopoDS_Edge DegEdge; BRep_Builder BB; BB.MakeEdge(DegEdge); BB.Add(DegEdge, aVertex.Oriented(TopAbs_FORWARD)); BB.Add(DegEdge, aVertex.Oriented(TopAbs_REVERSED)); BB.Degenerated(DegEdge, true); TopoDS_Wire DegWire; BB.MakeWire(DegWire); BB.Add(DegWire, DegEdge); DegWire.Closed(true); // Build the Ruled surface based shape BRepFill_Generator RuledSurf; RuledSurf.AddWire(DegWire); RuledSurf.AddWire(TopoDS::Wire(ShapeGen1)); RuledSurf.Perform(); TopoDS_Shell SurfShell = RuledSurf.Shell(); // Perform section BuildSection(Shape, SurfShell); }