0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / BRepProj / BRepProj_Projection.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15
16 #include <Bnd_Box.hxx>
17 #include <BRep_Builder.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepAlgoAPI_Section.hxx>
20 #include <BRepBndLib.hxx>
21 #include <BRepFill_Generator.hxx>
22 #include <BRepLib_MakeEdge.hxx>
23 #include <BRepLib_MakeVertex.hxx>
24 #include <BRepLib_MakeWire.hxx>
25 #include <BRepProj_Projection.hxx>
26 #include <BRepSweep_Prism.hxx>
27 #include <BRepTools_Modifier.hxx>
28 #include <BRepTools_TrsfModification.hxx>
29 #include <gp_Dir.hxx>
30 #include <gp_Pnt.hxx>
31 #include <gp_Trsf.hxx>
32 #include <gp_Vec.hxx>
33 #include <Precision.hxx>
34 #include <ShapeAnalysis_FreeBounds.hxx>
35 #include <Standard_ConstructionError.hxx>
36 #include <Standard_NoSuchObject.hxx>
37 #include <Standard_NullObject.hxx>
38 #include <TopExp.hxx>
39 #include <TopExp_Explorer.hxx>
40 #include <TopLoc_Location.hxx>
41 #include <TopoDS.hxx>
42 #include <TopoDS_Shape.hxx>
43 #include <TopTools_ListIteratorOfListOfShape.hxx>
44 #include <TopTools_ListOfShape.hxx>
45
46 //=======================================================================
47 //function : DistanceOut
48 //purpose  : Compute the minimum distance between input shapes 
49 //           (using Bounding Boxes of each Shape)
50 //=======================================================================
51 static Standard_Real DistanceOut (const TopoDS_Shape& S1, const TopoDS_Shape& S2) 
52 {
53   Bnd_Box BBox1, BBox2;
54   BRepBndLib::Add(S1,BBox1);
55   BRepBndLib::Add(S2,BBox2);
56   return BBox1.Distance(BBox2);
57 }
58   
59 //=======================================================================
60 //function : DistanceIn
61 //purpose  : Compute the maximum distance between input Shapes
62 //           we compute the maximum dimension of each Bounding Box and then
63 //           add each other with the minimum distance of shapes.
64 //=======================================================================
65
66 static Standard_Real DistanceIn (const TopoDS_Shape& S1, const TopoDS_Shape& S2) 
67 {
68   Bnd_Box LBBox,SBBox;
69   BRepBndLib::Add(S1,SBBox);
70   BRepBndLib::Add(S2,LBBox);
71
72   Standard_Real LXmin, LYmin, LZmin, LXmax, LYmax, LZmax, 
73                 SXmin, SYmin, SZmin, SXmax, SYmax, SZmax; 
74   SBBox.Get(SXmin, SYmin, SZmin, 
75             SXmax, SYmax, SZmax);
76   LBBox.Get(LXmin, LYmin, LZmin, 
77             LXmax, LYmax, LZmax);
78
79   //Compute the max distance between input shapes------------//
80   gp_XYZ Lmin(LXmin, LYmin, LZmin), 
81          Lmax(LXmax, LYmax, LZmax);
82   gp_XYZ Smin(SXmin, SYmin, SZmin), 
83          Smax(SXmax, SYmax, SZmax);
84   Lmax.Subtract(Lmin);
85   Smax.Subtract(Smin);
86   return Lmax.Modulus() + Smax.Modulus() + DistanceOut(S1, S2);
87 }
88
89 //=======================================================================
90 //function : BuildSection
91 //purpose  : Cuts theShape by theTool using BRepAlgoAPI_Section and 
92 //           stores result as set of connected wires and compound
93 //=======================================================================
94
95 void BRepProj_Projection::BuildSection (const TopoDS_Shape& theShape,
96                                         const TopoDS_Shape& theTool)
97 {
98   myIsDone = Standard_False;
99   mySection.Nullify();
100   myShape.Nullify();
101   myItr = 0;
102
103   // if theShape is compound, extract only faces -- section algorithm 
104   // may refuse to work if e.g. vertex is present
105   TopoDS_Shape aShape;
106   if (theShape.ShapeType() == TopAbs_FACE ||
107       theShape.ShapeType() == TopAbs_SHELL ||
108       theShape.ShapeType() == TopAbs_SOLID ||
109       theShape.ShapeType() == TopAbs_COMPSOLID)
110     aShape = theShape;
111   else if (theShape.ShapeType() == TopAbs_COMPOUND)
112   {
113     TopoDS_Compound C;
114     BRep_Builder B;
115     TopExp_Explorer exp (theShape, TopAbs_FACE);
116     for (; exp.More(); exp.Next())
117     {
118       if ( C.IsNull() )
119         B.MakeCompound (C);
120       B.Add (C, exp.Current());
121     }
122     aShape = C;
123   }
124   if ( aShape.IsNull() )
125     throw Standard_ConstructionError(__FILE__": target shape has no faces");
126
127   // build section computing p-curves on both shapes to get higher precision
128   BRepAlgoAPI_Section aSectionTool(aShape, theTool, Standard_False);
129   aSectionTool.Approximation(Standard_True);
130   aSectionTool.ComputePCurveOn1(Standard_True);
131   aSectionTool.ComputePCurveOn2(Standard_True);
132   // Use Oriented Bounding Boxes inside Booleans to speed up calculation of the section
133   aSectionTool.SetUseOBB(Standard_True);
134   aSectionTool.Build();
135
136   // check for successful work of the section tool
137   if (!aSectionTool.IsDone())
138     return;
139
140   // get edges of the result
141   Handle(TopTools_HSequenceOfShape) anEdges = new TopTools_HSequenceOfShape;
142   TopExp_Explorer exp(aSectionTool.Shape(), TopAbs_EDGE);
143   for (; exp.More(); exp.Next())
144     anEdges->Append (exp.Current());
145
146   // if no edges are found, this means that this section yields no result
147   if (anEdges->Length() <= 0) 
148     return;
149
150   // connect edges to wires using ShapeAnalysis functionality
151   ShapeAnalysis_FreeBounds::ConnectEdgesToWires (anEdges, Precision::Confusion(), 
152                                                  Standard_True, mySection);
153   myIsDone = (! mySection.IsNull() && mySection->Length() > 0);
154
155   // collect all resulting wires to compound
156   if ( myIsDone )
157   {
158     BRep_Builder B;
159     B.MakeCompound (myShape);
160     for (Standard_Integer i=1; i <= mySection->Length(); i++)
161       B.Add (myShape, mySection->Value(i));
162
163     // initialize iteration (for compatibility with previous versions)
164     myItr = 1;
165   }
166 }
167
168 //=======================================================================
169 //function : BRepProj_Projection    
170 //purpose  : Cylindrical Projection
171 //=======================================================================
172
173 BRepProj_Projection::BRepProj_Projection(const TopoDS_Shape& Wire,
174                                          const TopoDS_Shape& Shape,
175                                          const gp_Dir& D)
176 : myIsDone(Standard_False), myItr(0) 
177 {
178   // Check the input
179   Standard_NullObject_Raise_if((Wire.IsNull() || Shape.IsNull()),__FILE__": null input shape");
180   if (Wire.ShapeType() != TopAbs_EDGE && 
181       Wire.ShapeType() != TopAbs_WIRE ) 
182     throw Standard_ConstructionError(__FILE__": projected shape is neither wire nor edge");
183
184   // compute the "length" of the cylindrical surface to build
185   Standard_Real mdis = DistanceIn(Wire, Shape);
186   gp_Vec Vsup (D.XYZ() * 2 * mdis);
187   gp_Vec Vinf (D.XYZ() * -mdis);
188
189   // move the base of the cylindrical surface by translating it by -mdis
190   gp_Trsf T;
191   T.SetTranslation(Vinf);
192   // Note: it is necessary to create copy of wire to avoid adding new pcurves into it
193   Handle(BRepTools_TrsfModification) Trsf = new BRepTools_TrsfModification(T);
194   BRepTools_Modifier Modif (Wire, Trsf);
195   TopoDS_Shape WireBase = Modif.ModifiedShape(Wire);
196
197   // Creation of a cylindrical surface
198   BRepSweep_Prism CylSurf (WireBase, Vsup, Standard_False);
199
200   // Perform section
201   BuildSection (Shape, CylSurf.Shape());
202 }
203
204 //=======================================================================
205 //function : BRepProj_Projection
206 //purpose  : Conical projection
207 //=======================================================================
208
209 BRepProj_Projection::BRepProj_Projection (const TopoDS_Shape& Wire,
210                                           const TopoDS_Shape& Shape,
211                                           const gp_Pnt& P)
212 : myIsDone(Standard_False), myItr(0)
213 {
214   // Check the input
215   Standard_NullObject_Raise_if((Wire.IsNull() || Shape.IsNull()),__FILE__": null input shape");
216   if (Wire.ShapeType() != TopAbs_EDGE && 
217       Wire.ShapeType() != TopAbs_WIRE ) 
218     throw Standard_ConstructionError(__FILE__": projected shape is neither wire nor edge");
219
220   // if Wire is only an edge, transform it into a Wire
221   TopoDS_Wire aWire;
222   if (Wire.ShapeType() == TopAbs_EDGE) 
223   {
224     BRep_Builder BB;
225     BB.MakeWire(aWire);
226     BB.Add(aWire, Wire);
227   }
228   else 
229     aWire = TopoDS::Wire(Wire);
230   
231   // compute the "length" of the conical surface to build
232   Standard_Real mdis = DistanceIn(Wire, Shape);
233
234   // Initialize iterator to get first sub-shape of Wire
235   TopExp_Explorer ExpWire; 
236   ExpWire.Init (aWire, TopAbs_VERTEX);
237   
238   // get the first Point of the first sub-shape os the Wire
239   gp_Pnt PC = BRep_Tool::Pnt(TopoDS::Vertex(ExpWire.Current()));
240   
241   // compute the ratio of the scale transformation
242   Standard_Real Scale = PC.Distance(P);
243   if ( Abs (Scale) < Precision::Confusion() ) 
244     throw Standard_ConstructionError("Projection");
245   Scale = 1. + mdis / Scale;
246   
247   // move the base of the conical surface by scaling it with ratio Scale
248   gp_Trsf T;
249   T.SetScale(P, Scale);
250   Handle(BRepTools_TrsfModification) Tsca = new BRepTools_TrsfModification(T);
251   BRepTools_Modifier ModifScale(aWire,Tsca);
252   TopoDS_Shape ShapeGen1 = ModifScale.ModifiedShape(aWire);
253
254   TopoDS_Vertex aVertex = BRepLib_MakeVertex(P);
255   TopoDS_Edge DegEdge;
256   BRep_Builder BB;
257   BB.MakeEdge( DegEdge );
258   BB.Add( DegEdge, aVertex.Oriented(TopAbs_FORWARD) );
259   BB.Add( DegEdge, aVertex.Oriented(TopAbs_REVERSED) );
260   BB.Degenerated( DegEdge, Standard_True );
261
262   TopoDS_Wire DegWire;
263   BB.MakeWire( DegWire );
264   BB.Add( DegWire, DegEdge );
265   DegWire.Closed( Standard_True );
266
267   // Build the Ruled surface based shape
268   BRepFill_Generator RuledSurf;
269   RuledSurf.AddWire(DegWire);
270   RuledSurf.AddWire(TopoDS::Wire(ShapeGen1));
271   RuledSurf.Perform();
272   TopoDS_Shell SurfShell = RuledSurf.Shell();
273
274   // Perform section
275   BuildSection (Shape, SurfShell);
276 }