summaryrefslogtreecommitdiff
path: root/src/BRepProj/BRepProj_Projection.cxx
blob: b25b1399a6c638029bcc7de57f4ebe81c055c8d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include <BRepProj_Projection.ixx>

#include <BRepAlgo_Section.hxx>

#include <Precision.hxx>
#include <BRepBndLib.hxx>
#include <BRepTools_TrsfModification.hxx>
#include <BRepTools_Modifier.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRep_Tool.hxx>
#include <Bnd_Box.hxx>

#include <BRepSweep_Prism.hxx>
#include <BRepFill_Generator.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <gp_Dir.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <gp_Trsf.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <BRep_Builder.hxx>
#include <ShapeAnalysis_FreeBounds.hxx>

#include <Standard_NullObject.hxx>
#include <Standard_ConstructionError.hxx>

//=======================================================================
//function : DistanceOut
//purpose  : Compute the minimum distance between input shapes 
//           (using Bounding Boxes of each Shape)
//=======================================================================

static Standard_Real 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 Standard_Real DistanceIn (const TopoDS_Shape& S1, const TopoDS_Shape& S2) 
{
  Bnd_Box LBBox,SBBox;
  BRepBndLib::Add(S1,SBBox);
  BRepBndLib::Add(S2,LBBox);

  Standard_Real 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 = Standard_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() )
    Standard_ConstructionError::Raise(__FILE__": target shape has no faces");

  // build section computing pcurves on the shape
//  BRepAlgoAPI_Section aSectionTool (aShape, theTool, Standard_False);
  BRepAlgo_Section aSectionTool (aShape, theTool, Standard_False);
  aSectionTool.Approximation (Standard_True);
  aSectionTool.ComputePCurveOn1 (Standard_True);
  aSectionTool.Build();

  // check for successful work of the section tool
  if (! aSectionTool.IsDone()) 
    return;

  // get edges of the result
  Handle(TopTools_HSequenceOfShape) anEdges = new TopTools_HSequenceOfShape;
  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
  ShapeAnalysis_FreeBounds::ConnectEdgesToWires (anEdges, Precision::Confusion(), 
                                                 Standard_True, mySection);
  myIsDone = (! mySection.IsNull() && mySection->Length() > 0);

  // collect all resulting wires to compound
  if ( myIsDone )
  {
    BRep_Builder B;
    B.MakeCompound (myShape);
    for (Standard_Integer i=1; i <= mySection->Length(); i++)
      B.Add (myShape, mySection->Value(i));

    // initialize iteration (for compatibility with previous versions)
    myItr = 1;
  }
}

//=======================================================================
//function : BRepProj_Projection    
//purpose  : Cylindrical Projection
//=======================================================================

BRepProj_Projection::BRepProj_Projection(const TopoDS_Shape& Wire,
                                         const TopoDS_Shape& Shape,
                                         const gp_Dir& D)
: myIsDone(Standard_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 ) 
    Standard_ConstructionError::Raise(__FILE__": projected shape is neither wire nor edge");

  // compute the "length" of the cylindrical surface to build
  Standard_Real 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
  Handle(BRepTools_TrsfModification) Trsf = new BRepTools_TrsfModification(T);
  BRepTools_Modifier Modif (Wire, Trsf);
  TopoDS_Shape WireBase = Modif.ModifiedShape(Wire);

  // Creation of a cylindrical surface
  BRepSweep_Prism CylSurf (WireBase, Vsup, Standard_False);

  // Perform section
  BuildSection (Shape, CylSurf.Shape());
}

//=======================================================================
//function : BRepProj_Projection
//purpose  : Conical projection
//=======================================================================

BRepProj_Projection::BRepProj_Projection (const TopoDS_Shape& Wire,
                                          const TopoDS_Shape& Shape,
                                          const gp_Pnt& P)
: myIsDone(Standard_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 ) 
    Standard_ConstructionError::Raise(__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
  Standard_Real 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
  Standard_Real Scale = PC.Distance(P);
  if ( Abs (Scale) < Precision::Confusion() ) 
    Standard_ConstructionError::Raise("Projection");
  Scale = 1. + mdis / Scale;
  
  // move the base of the conical surface by scaling it with ratio Scale
  // then we do a symmetric relative to a point. So we have two generators
  // for building a "semi-infinite" conic surface
  gp_Trsf T;
  T.SetScale(P, Scale);
  Handle(BRepTools_TrsfModification) Tsca = new BRepTools_TrsfModification(T);
  BRepTools_Modifier ModifScale(aWire,Tsca);
  TopoDS_Shape ShapeGen1 = ModifScale.ModifiedShape(aWire);

  T.SetMirror(P);
  Handle(BRepTools_TrsfModification) Tmir = new BRepTools_TrsfModification(T);
  BRepTools_Modifier ModifMirror(ShapeGen1,Tmir);
  TopoDS_Shape ShapeGen2 = ModifMirror.ModifiedShape(ShapeGen1);

  // Build the Ruled surface based shape
  BRepFill_Generator RuledSurf;
  RuledSurf.AddWire(TopoDS::Wire(ShapeGen1));
  RuledSurf.AddWire(TopoDS::Wire(ShapeGen2));
  RuledSurf.Perform();
  TopoDS_Shell SurfShell = RuledSurf.Shell();

  // Perform section
  BuildSection (Shape, SurfShell);
}