| 1 | // Created on: 1995-09-18 |
| 2 | // Created by: Bruno DUMORTIER |
| 3 | // Copyright (c) 1995-1999 Matra Datavision |
| 4 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
| 5 | // |
| 6 | // This file is part of Open CASCADE Technology software library. |
| 7 | // |
| 8 | // This library is free software; you can redistribute it and/or modify it under |
| 9 | // the terms of the GNU Lesser General Public License version 2.1 as published |
| 10 | // by the Free Software Foundation, with special exception defined in the file |
| 11 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
| 12 | // distribution for complete text of the license and disclaimer of any warranty. |
| 13 | // |
| 14 | // Alternatively, this file may be used under the terms of Open CASCADE |
| 15 | // commercial license or contractual agreement. |
| 16 | |
| 17 | |
| 18 | #include <BRep_Builder.hxx> |
| 19 | #include <BRep_Tool.hxx> |
| 20 | #include <BRepAdaptor_Surface.hxx> |
| 21 | #include <BRepAlgo_FaceRestrictor.hxx> |
| 22 | #include <BRepBuilderAPI_MakeFace.hxx> |
| 23 | #include <BRepFill_ListIteratorOfListOfOffsetWire.hxx> |
| 24 | #include <BRepFill_OffsetWire.hxx> |
| 25 | #include <BRepOffsetAPI_MakeOffset.hxx> |
| 26 | #include <BRepTopAdaptor_FClass2d.hxx> |
| 27 | #include <Extrema_ExtPS.hxx> |
| 28 | #include <gp_Pnt.hxx> |
| 29 | #include <gp_Pnt2d.hxx> |
| 30 | #include <Precision.hxx> |
| 31 | #include <StdFail_NotDone.hxx> |
| 32 | #include <TopExp.hxx> |
| 33 | #include <TopExp_Explorer.hxx> |
| 34 | #include <TopoDS.hxx> |
| 35 | #include <TopoDS_Compound.hxx> |
| 36 | #include <TopoDS_Face.hxx> |
| 37 | #include <TopoDS_Shape.hxx> |
| 38 | #include <TopoDS_Vertex.hxx> |
| 39 | #include <TopoDS_Wire.hxx> |
| 40 | #include <TopTools_ListIteratorOfListOfShape.hxx> |
| 41 | |
| 42 | #ifdef OCCT_DEBUG |
| 43 | #include <BRepTools.hxx> |
| 44 | static Standard_Boolean AffichSpine = Standard_False; |
| 45 | #endif |
| 46 | |
| 47 | //======================================================================= |
| 48 | //function : BRepOffsetAPI_MakeOffset |
| 49 | //purpose : |
| 50 | //======================================================================= |
| 51 | |
| 52 | BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset() |
| 53 | : myIsInitialized( Standard_False), |
| 54 | myJoin(GeomAbs_Arc), |
| 55 | myIsOpenResult(Standard_False) |
| 56 | { |
| 57 | } |
| 58 | |
| 59 | |
| 60 | //======================================================================= |
| 61 | //function : BRepOffsetAPI_MakeOffset |
| 62 | //purpose : |
| 63 | //======================================================================= |
| 64 | |
| 65 | BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset(const TopoDS_Face& Spine, |
| 66 | const GeomAbs_JoinType Join, |
| 67 | const Standard_Boolean IsOpenResult) |
| 68 | { |
| 69 | Init(Spine, Join, IsOpenResult); |
| 70 | } |
| 71 | |
| 72 | |
| 73 | //======================================================================= |
| 74 | //function : Init |
| 75 | //purpose : |
| 76 | //======================================================================= |
| 77 | |
| 78 | void BRepOffsetAPI_MakeOffset::Init(const TopoDS_Face& Spine, |
| 79 | const GeomAbs_JoinType Join, |
| 80 | const Standard_Boolean IsOpenResult) |
| 81 | { |
| 82 | myFace = Spine; |
| 83 | myIsInitialized = Standard_True; |
| 84 | myJoin = Join; |
| 85 | myIsOpenResult = IsOpenResult; |
| 86 | TopExp_Explorer exp; |
| 87 | for (exp.Init(myFace,TopAbs_WIRE); exp.More();exp.Next()) { |
| 88 | myWires.Append(exp.Current()); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | //======================================================================= |
| 93 | //function : BRepOffsetAPI_MakeOffset |
| 94 | //purpose : |
| 95 | //======================================================================= |
| 96 | |
| 97 | BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset(const TopoDS_Wire& Spine, |
| 98 | const GeomAbs_JoinType Join, |
| 99 | const Standard_Boolean IsOpenResult) |
| 100 | { |
| 101 | myWires.Append(Spine); |
| 102 | myIsInitialized = Standard_True; |
| 103 | myJoin = Join; |
| 104 | myIsOpenResult = IsOpenResult; |
| 105 | } |
| 106 | |
| 107 | //======================================================================= |
| 108 | //function : Init |
| 109 | //purpose : |
| 110 | //======================================================================= |
| 111 | |
| 112 | void BRepOffsetAPI_MakeOffset::Init(const GeomAbs_JoinType Join, |
| 113 | const Standard_Boolean IsOpenResult) |
| 114 | { |
| 115 | myJoin = Join; |
| 116 | myIsOpenResult = IsOpenResult; |
| 117 | } |
| 118 | |
| 119 | //======================================================================= |
| 120 | //function : BRepOffsetAPI_MakeOffset |
| 121 | //purpose : |
| 122 | //======================================================================= |
| 123 | |
| 124 | void BRepOffsetAPI_MakeOffset::AddWire(const TopoDS_Wire& Spine) |
| 125 | |
| 126 | { |
| 127 | myIsInitialized = Standard_True; |
| 128 | myWires.Append(Spine); |
| 129 | } |
| 130 | |
| 131 | //======================================================================= |
| 132 | //function : BuildDomain |
| 133 | //purpose : |
| 134 | //======================================================================= |
| 135 | |
| 136 | static void BuildDomains(TopoDS_Face& myFace, |
| 137 | TopTools_ListOfShape& WorkWires, |
| 138 | BRepFill_ListOfOffsetWire& myAlgos, |
| 139 | GeomAbs_JoinType myJoin, |
| 140 | Standard_Boolean myIsOpenResult, |
| 141 | Standard_Boolean isPositive) |
| 142 | { |
| 143 | BRepAlgo_FaceRestrictor FR; |
| 144 | TopoDS_Vertex VF,VL; |
| 145 | TopTools_ListOfShape LOW; |
| 146 | BRep_Builder B; |
| 147 | |
| 148 | if (myFace.IsNull()) { |
| 149 | myFace = BRepBuilderAPI_MakeFace(TopoDS::Wire(WorkWires.First()),Standard_True); |
| 150 | if (myFace.IsNull()) |
| 151 | StdFail_NotDone::Raise ("BRepOffsetAPI_MakeOffset : the wire is not planar"); |
| 152 | } |
| 153 | // Modified by Sergey KHROMOV - Thu Apr 26 16:04:43 2001 Begin |
| 154 | TopExp_Explorer anExp(myFace, TopAbs_WIRE); |
| 155 | TopoDS_Shape aWire1 = WorkWires.First(); |
| 156 | TopoDS_Shape aWire2; |
| 157 | if (anExp.More()) { |
| 158 | aWire2 = anExp.Current(); |
| 159 | if ((aWire1.Orientation() == aWire2.Orientation() && isPositive) || |
| 160 | (aWire1.Orientation() == TopAbs::Complement(aWire2.Orientation()) && !isPositive)) { |
| 161 | TopTools_ListOfShape LWires; |
| 162 | TopTools_ListIteratorOfListOfShape itl; |
| 163 | for (itl.Initialize(WorkWires); itl.More(); itl.Next()) { |
| 164 | const TopoDS_Shape& W = itl.Value(); |
| 165 | LWires.Append(W.Reversed()); |
| 166 | } |
| 167 | WorkWires = LWires; |
| 168 | } |
| 169 | } |
| 170 | // Modified by Sergey KHROMOV - Thu Apr 26 16:04:44 2001 End |
| 171 | FR.Init(myFace,Standard_True); |
| 172 | //==================================================== |
| 173 | // Construction of faces limited by closed wires. |
| 174 | //==================================================== |
| 175 | TopTools_ListIteratorOfListOfShape itl(WorkWires); |
| 176 | for (; itl.More(); itl.Next()) { |
| 177 | TopoDS_Wire& W = TopoDS::Wire(itl.Value()); |
| 178 | if (W.Closed()){ |
| 179 | FR.Add(W); |
| 180 | continue; |
| 181 | } |
| 182 | TopExp::Vertices (W,VF,VL); |
| 183 | if (VF.IsSame(VL)) { |
| 184 | FR.Add(W); |
| 185 | } |
| 186 | else { |
| 187 | LOW.Append(W); |
| 188 | } |
| 189 | } |
| 190 | FR.Perform(); |
| 191 | if (!FR.IsDone()) { |
| 192 | StdFail_NotDone::Raise ("BRepOffsetAPI_MakeOffset : Build Domains"); |
| 193 | } |
| 194 | TopTools_ListOfShape Faces; |
| 195 | #ifdef OCCT_DEBUG |
| 196 | Standard_Integer ns = 0; |
| 197 | #endif |
| 198 | for (; FR.More(); FR.Next()) { |
| 199 | Faces.Append(FR.Current()); |
| 200 | #ifdef OCCT_DEBUG |
| 201 | if(AffichSpine) |
| 202 | { |
| 203 | char name[32]; |
| 204 | ns++; |
| 205 | sprintf(name, "FR%d",ns); |
| 206 | BRepTools::Write(FR.Current(), name); |
| 207 | } |
| 208 | #endif |
| 209 | } |
| 210 | |
| 211 | //=========================================== |
| 212 | // No closed wire => only one domain |
| 213 | //=========================================== |
| 214 | if (Faces.IsEmpty()) { |
| 215 | TopoDS_Shape aLocalShape = myFace.EmptyCopied(); |
| 216 | TopoDS_Face F = TopoDS::Face(aLocalShape); |
| 217 | // TopoDS_Face F = TopoDS::Face(myFace.EmptyCopied()); |
| 218 | TopTools_ListIteratorOfListOfShape itW(LOW); |
| 219 | for ( ; itW.More(); itW.Next()) { |
| 220 | B.Add(F,itW.Value()); |
| 221 | } |
| 222 | BRepFill_OffsetWire Algo(F, myJoin, myIsOpenResult); |
| 223 | myAlgos.Append(Algo); |
| 224 | return; |
| 225 | } |
| 226 | |
| 227 | //==================================================== |
| 228 | // Classification of open wires. |
| 229 | //==================================================== |
| 230 | // for (TopTools_ListIteratorOfListOfShape itF(Faces); itF.More(); itF.Next()) { |
| 231 | TopTools_ListIteratorOfListOfShape itF; |
| 232 | for (itF.Initialize(Faces) ; itF.More(); itF.Next()) { |
| 233 | TopoDS_Face& F = TopoDS::Face(itF.Value()); |
| 234 | BRepAdaptor_Surface S(F,0); |
| 235 | Standard_Real Tol = BRep_Tool::Tolerance(F); |
| 236 | |
| 237 | BRepTopAdaptor_FClass2d CL(F,Precision::Confusion()); |
| 238 | |
| 239 | TopTools_ListIteratorOfListOfShape itW(LOW); |
| 240 | while (itW.More()) { |
| 241 | TopoDS_Wire& W = TopoDS::Wire(itW.Value()); |
| 242 | //======================================================= |
| 243 | // Choice of a point on the wire. + projection on the face. |
| 244 | //======================================================= |
| 245 | TopExp_Explorer exp(W,TopAbs_VERTEX); |
| 246 | TopoDS_Vertex V = TopoDS::Vertex(exp.Current()); |
| 247 | gp_Pnt2d PV; |
| 248 | gp_Pnt P3d = BRep_Tool::Pnt(V); |
| 249 | Extrema_ExtPS ExtPS (P3d,S,Tol,Tol); |
| 250 | Standard_Real Dist2Min = Precision::Infinite(); |
| 251 | Standard_Real Found = Standard_False; |
| 252 | for (Standard_Integer ie = 1; ie <= ExtPS.NbExt(); ie++) { |
| 253 | Standard_Real X,Y; |
| 254 | if (ExtPS.SquareDistance(ie) < Dist2Min) { |
| 255 | Dist2Min = ExtPS.SquareDistance(ie); |
| 256 | Found = Standard_True; |
| 257 | ExtPS.Point(ie).Parameter(X,Y); |
| 258 | PV.SetCoord(X,Y); |
| 259 | } |
| 260 | } |
| 261 | if ( Found && (CL.Perform(PV) == TopAbs_IN)) { |
| 262 | // The face that contains a wire is found and it is removed from the list |
| 263 | B.Add(F,W); |
| 264 | LOW.Remove(itW); |
| 265 | } |
| 266 | else { |
| 267 | itW.Next(); |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | //======================================== |
| 272 | // Creation of algorithms on each domain. |
| 273 | //======================================== |
| 274 | for (itF.Initialize(Faces); itF.More(); itF.Next()) { |
| 275 | BRepFill_OffsetWire Algo(TopoDS::Face(itF.Value()), myJoin, myIsOpenResult); |
| 276 | myAlgos.Append(Algo); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | //======================================================================= |
| 281 | //function : Perform |
| 282 | //purpose : |
| 283 | //======================================================================= |
| 284 | |
| 285 | void BRepOffsetAPI_MakeOffset::Perform(const Standard_Real Offset, |
| 286 | const Standard_Real Alt) |
| 287 | { |
| 288 | StdFail_NotDone_Raise_if ( !myIsInitialized, |
| 289 | "BRepOffsetAPI_MakeOffset : Perform without Init"); |
| 290 | |
| 291 | try |
| 292 | { |
| 293 | Standard_Integer i = 1; |
| 294 | BRepFill_ListIteratorOfListOfOffsetWire itOW; |
| 295 | TopoDS_Compound Res; |
| 296 | BRep_Builder B; |
| 297 | B.MakeCompound (Res); |
| 298 | myLastIsLeft = (Offset <= 0); |
| 299 | |
| 300 | if( Offset <= 0. ) |
| 301 | { |
| 302 | if( myLeft.IsEmpty() ) |
| 303 | { |
| 304 | // Modified by Sergey KHROMOV - Fri Apr 27 14:35:26 2001 Begin |
| 305 | BuildDomains(myFace,myWires,myLeft,myJoin,myIsOpenResult, Standard_False); |
| 306 | // Modified by Sergey KHROMOV - Fri Apr 27 14:35:26 2001 End |
| 307 | } |
| 308 | |
| 309 | for (itOW.Initialize(myLeft); itOW.More(); itOW.Next()) |
| 310 | { |
| 311 | BRepFill_OffsetWire& Algo = itOW.Value(); |
| 312 | Algo.Perform(Abs(Offset),Alt); |
| 313 | if (Algo.IsDone() && !Algo.Shape().IsNull()) |
| 314 | { |
| 315 | B.Add(Res,Algo.Shape()); |
| 316 | if (i == 1) |
| 317 | myShape = Algo.Shape(); |
| 318 | |
| 319 | i++; |
| 320 | } |
| 321 | } |
| 322 | } |
| 323 | else |
| 324 | { |
| 325 | if (myRight.IsEmpty()) |
| 326 | { |
| 327 | // Modified by Sergey KHROMOV - Fri Apr 27 14:35:28 2001 Begin |
| 328 | BuildDomains(myFace,myWires,myRight,myJoin,myIsOpenResult, Standard_True); |
| 329 | // Modified by Sergey KHROMOV - Fri Apr 27 14:35:35 2001 End |
| 330 | } |
| 331 | |
| 332 | for(itOW.Initialize(myRight); itOW.More(); itOW.Next()) |
| 333 | { |
| 334 | BRepFill_OffsetWire& Algo = itOW.Value(); |
| 335 | Algo.Perform(Offset,Alt); |
| 336 | |
| 337 | if (Algo.IsDone() && !Algo.Shape().IsNull()) |
| 338 | { |
| 339 | B.Add(Res,Algo.Shape()); |
| 340 | |
| 341 | if (i == 1) |
| 342 | myShape = Algo.Shape(); |
| 343 | |
| 344 | i++; |
| 345 | } |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | if( i > 2 ) |
| 350 | myShape = Res; |
| 351 | |
| 352 | if(myShape.IsNull()) |
| 353 | NotDone(); |
| 354 | else |
| 355 | Done(); |
| 356 | } |
| 357 | catch(Standard_Failure) //Every exception was caught. |
| 358 | { |
| 359 | #ifdef OCCT_DEBUG |
| 360 | cout<<"An exception was caught in BRepOffsetAPI_MakeOffset::Perform : "; |
| 361 | Standard_ConstructionError::Caught()->Print(cout); |
| 362 | cout<<endl; |
| 363 | #endif |
| 364 | NotDone(); |
| 365 | myShape.Nullify(); |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | //======================================================================= |
| 370 | //function : Build |
| 371 | //purpose : |
| 372 | //======================================================================= |
| 373 | |
| 374 | void BRepOffsetAPI_MakeOffset::Build() |
| 375 | { |
| 376 | Done(); |
| 377 | } |
| 378 | |
| 379 | |
| 380 | //======================================================================= |
| 381 | //function : ShapesFromShape |
| 382 | //purpose : |
| 383 | //======================================================================= |
| 384 | |
| 385 | const TopTools_ListOfShape& BRepOffsetAPI_MakeOffset::Generated |
| 386 | (const TopoDS_Shape& S) |
| 387 | { |
| 388 | myGenerated.Clear(); |
| 389 | BRepFill_ListIteratorOfListOfOffsetWire itOW; |
| 390 | BRepFill_ListOfOffsetWire* Algos; |
| 391 | Algos= &myLeft; |
| 392 | if (!myLastIsLeft) { |
| 393 | Algos = &myRight; |
| 394 | } |
| 395 | for (itOW.Initialize(*Algos); itOW.More(); itOW.Next()) { |
| 396 | BRepFill_OffsetWire& OW = itOW.Value(); |
| 397 | TopTools_ListOfShape L; |
| 398 | L = OW.GeneratedShapes(S.Oriented(TopAbs_FORWARD)); |
| 399 | myGenerated.Append(L); |
| 400 | L = OW.GeneratedShapes(S.Oriented(TopAbs_REVERSED)); |
| 401 | myGenerated.Append(L); |
| 402 | } |
| 403 | return myGenerated; |
| 404 | } |