FeatureFace.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <Bnd_Box.hxx>
00027 # include <gp_Pln.hxx>
00028 # include <BRep_Builder.hxx>
00029 # include <BRepBndLib.hxx>
00030 # include <BRepBuilderAPI_Copy.hxx>
00031 # include <BRepBuilderAPI_MakeFace.hxx>
00032 # include <BRepAdaptor_Surface.hxx>
00033 # include <Geom_Plane.hxx>
00034 # include <Handle_Geom_Surface.hxx>
00035 # include <TopoDS.hxx>
00036 # include <TopoDS_Compound.hxx>
00037 # include <TopoDS_Face.hxx>
00038 # include <TopoDS_Wire.hxx>
00039 # include <TopExp_Explorer.hxx>
00040 # include <BRepAlgoAPI_Fuse.hxx>
00041 # include <gp_Pln.hxx>
00042 #endif
00043 
00044 #include <Base/Placement.h>
00045 #include <Mod/Part/App/Part2DObject.h>
00046 
00047 #include "FeatureFace.h"
00048 
00049 
00050 using namespace PartDesign;
00051 
00052 
00053 PROPERTY_SOURCE(PartDesign::Face, Part::Part2DObject)
00054 
00055 Face::Face()
00056 {
00057     ADD_PROPERTY(Sources,(0));
00058     Sources.setSize(0);
00059 }
00060 
00061 short Face::mustExecute() const
00062 {
00063     if (Sources.isTouched())
00064         return 1;
00065     return 0;
00066 }
00067 
00068 App::DocumentObjectExecReturn *Face::execute(void)
00069 {
00070     std::vector<App::DocumentObject*> links = Sources.getValues();
00071     if (links.empty())
00072         return new App::DocumentObjectExecReturn("No shapes linked");
00073 
00074     std::vector<TopoDS_Wire> wires;
00075     for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
00076         if (!(*it && (*it)->isDerivedFrom(Part::Part2DObject::getClassTypeId())))
00077             return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject");
00078         TopoDS_Shape shape = static_cast<Part::Part2DObject*>(*it)->Shape.getShape()._Shape;
00079         if (shape.IsNull())
00080             return new App::DocumentObjectExecReturn("Linked shape object is empty");
00081 
00082         // this is a workaround for an obscure OCC bug which leads to empty tessellations
00083         // for some faces. Making an explicit copy of the linked shape seems to fix it.
00084         // The error only happens when re-computing the shape.
00085         if (!this->Shape.getValue().IsNull()) {
00086             BRepBuilderAPI_Copy copy(shape);
00087             shape = copy.Shape();
00088             if (shape.IsNull())
00089                 return new App::DocumentObjectExecReturn("Linked shape object is empty");
00090         }
00091 
00092         TopExp_Explorer ex;
00093         for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
00094             wires.push_back(TopoDS::Wire(ex.Current()));
00095         }
00096     }
00097 
00098     if (wires.empty()) // there can be several wires
00099         return new App::DocumentObjectExecReturn("Linked shape object is not a wire");
00100 
00101     TopoDS_Shape aFace = makeFace(wires);
00102     if (aFace.IsNull())
00103         return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
00104     this->Shape.setValue(aFace);
00105 
00106     return App::DocumentObject::StdReturn;
00107 }
00108 
00109 namespace PartDesign {
00110 
00111 // sort bounding boxes according to diagonal length
00112 struct Wire_Compare {
00113     bool operator() (const TopoDS_Wire& w1, const TopoDS_Wire& w2)
00114     {
00115         Bnd_Box box1, box2;
00116         BRepBndLib::Add(w1, box1);
00117         box1.SetGap(0.0);
00118 
00119         BRepBndLib::Add(w2, box2);
00120         box2.SetGap(0.0);
00121 
00122         return box1.SquareExtent() < box2.SquareExtent();
00123     }
00124 };
00125 }
00126 
00127 TopoDS_Shape Face::makeFace(std::list<TopoDS_Wire>& wires) const
00128 {
00129     BRepBuilderAPI_MakeFace mkFace(wires.front());
00130     const TopoDS_Face& face = mkFace.Face();
00131     if (face.IsNull())
00132         return face;
00133     gp_Dir axis(0,0,1);
00134     BRepAdaptor_Surface adapt(face);
00135     if (adapt.GetType() == GeomAbs_Plane) {
00136         axis = adapt.Plane().Axis().Direction();
00137     }
00138 
00139     wires.pop_front();
00140     for (std::list<TopoDS_Wire>::iterator it = wires.begin(); it != wires.end(); ++it) {
00141         BRepBuilderAPI_MakeFace mkInnerFace(*it);
00142         const TopoDS_Face& inner_face = mkInnerFace.Face();
00143         gp_Dir inner_axis(0,0,1);
00144         BRepAdaptor_Surface adapt(inner_face);
00145         if (adapt.GetType() == GeomAbs_Plane) {
00146             inner_axis = adapt.Plane().Axis().Direction();
00147         }
00148         // It seems that orientation is always 'Forward' and we only have to reverse
00149         // if the underlying plane have opposite normals. 
00150         if (axis.Dot(inner_axis) < 0)
00151             it->Reverse();
00152         mkFace.Add(*it);
00153     }
00154     return mkFace.Face();
00155 }
00156 
00157 TopoDS_Shape Face::makeFace(const std::vector<TopoDS_Wire>& w) const
00158 {
00159     if (w.empty())
00160         return TopoDS_Shape();
00161 
00162     //FIXME: Need a safe method to sort wire that the outermost one comes last
00163     // Currently it's done with the diagonal lengths of the bounding boxes
00164     std::vector<TopoDS_Wire> wires = w;
00165     std::sort(wires.begin(), wires.end(), Wire_Compare());
00166     std::list<TopoDS_Wire> wire_list;
00167     wire_list.insert(wire_list.begin(), wires.rbegin(), wires.rend());
00168 
00169     // separate the wires into several independent faces
00170     std::list< std::list<TopoDS_Wire> > sep_wire_list;
00171     while (!wire_list.empty()) {
00172         std::list<TopoDS_Wire> sep_list;
00173         TopoDS_Wire wire = wire_list.front();
00174         wire_list.pop_front();
00175         sep_list.push_back(wire);
00176 
00177         Bnd_Box box;
00178         BRepBndLib::Add(wire, box);
00179         box.SetGap(0.0);
00180 
00181         std::list<TopoDS_Wire>::iterator it = wire_list.begin();
00182         while (it != wire_list.end()) {
00183             Bnd_Box box2;
00184             BRepBndLib::Add(*it, box2);
00185             box2.SetGap(0.0);
00186             if (!box.IsOut(box2)) {
00187                 sep_list.push_back(*it);
00188                 it = wire_list.erase(it);
00189             }
00190             else {
00191                 ++it;
00192             }
00193         }
00194 
00195         sep_wire_list.push_back(sep_list);
00196     }
00197 
00198     if (sep_wire_list.size() == 1) {
00199         std::list<TopoDS_Wire>& wires = sep_wire_list.front();
00200         return makeFace(wires);
00201     }
00202     else if (sep_wire_list.size() > 1) {
00203         TopoDS_Compound comp;
00204         BRep_Builder builder;
00205         builder.MakeCompound(comp);
00206         for (std::list< std::list<TopoDS_Wire> >::iterator it = sep_wire_list.begin(); it != sep_wire_list.end(); ++it) {
00207             TopoDS_Shape aFace = makeFace(*it);
00208             if (!aFace.IsNull())
00209                 builder.Add(comp, aFace);
00210         }
00211 
00212         return comp;
00213     }
00214     else {
00215         return TopoDS_Shape(); // error
00216     }
00217 }
00218 

Generated on Wed Nov 23 19:00:11 2011 for FreeCAD by  doxygen 1.6.1