/*************************************************************************** * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include # include # include // for Precision::Confusion() # include # include #endif #include #include #include #include #include #include #include #include #include #include #include "PartFeature.h" #include "PartFeaturePy.h" using namespace Part; PROPERTY_SOURCE(Part::Feature, App::GeoFeature) Feature::Feature(void) { ADD_PROPERTY(Shape, (TopoDS_Shape())); } Feature::~Feature() { } short Feature::mustExecute(void) const { return GeoFeature::mustExecute(); } App::DocumentObjectExecReturn *Feature::recompute(void) { try { return App::GeoFeature::recompute(); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); App::DocumentObjectExecReturn* ret = new App::DocumentObjectExecReturn(e->GetMessageString()); if (ret->Why.empty()) ret->Why = "Unknown OCC exception"; return ret; } } App::DocumentObjectExecReturn *Feature::execute(void) { this->Shape.touch(); return App::DocumentObject::StdReturn; } PyObject *Feature::getPyObject(void) { if (PythonObject.is(Py::_None())){ // ref counter is set to 1 PythonObject = Py::Object(new PartFeaturePy(this),true); } return Py::new_reference_to(PythonObject); } std::vector Feature::getPySubObjects(const std::vector& NameVec) const { std::vector temp; for(std::vector::const_iterator it=NameVec.begin();it!=NameVec.end();++it){ PyObject *obj = Shape.getShape().getPySubShape((*it).c_str()); if(obj) temp.push_back(obj); } return temp; } void Feature::onChanged(const App::Property* prop) { // if the placement has changed apply the change to the point data as well if (prop == &this->Placement) { TopoShape& shape = const_cast(this->Shape.getShape()); shape.setTransform(this->Placement.getValue().toMatrix()); } // if the point data has changed check and adjust the transformation as well else if (prop == &this->Shape) { if (this->isRecomputing()) { TopoShape& shape = const_cast(this->Shape.getShape()); shape.setTransform(this->Placement.getValue().toMatrix()); } else { Base::Placement p; // shape must not be null to override the placement if (!this->Shape.getValue().IsNull()) { p.fromMatrix(this->Shape.getShape().getTransform()); if (p != this->Placement.getValue()) this->Placement.setValue(p); } } } GeoFeature::onChanged(prop); } TopLoc_Location Feature::getLocation() const { Base::Placement pl = this->Placement.getValue(); Base::Rotation rot(pl.getRotation()); Base::Vector3d axis; double angle; rot.getValue(axis, angle); gp_Trsf trf; trf.SetRotation(gp_Ax1(gp_Pnt(), gp_Dir(axis.x, axis.y, axis.z)), angle); trf.SetTranslationPart(gp_Vec(pl.getPosition().x,pl.getPosition().y,pl.getPosition().z)); return TopLoc_Location(trf); } ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_ShapeEnum type, const TopoDS_Shape& newS, const TopoDS_Shape& oldS) { ShapeHistory history; history.type = type; TopTools_IndexedMapOfShape newM, oldM; TopExp::MapShapes(newS, type, newM); // map containing all old objects of type "type" TopExp::MapShapes(oldS, type, oldM); // map containing all new objects of type "type" // Look at all objects in the old shape and try to find the modified object in the new shape for (int i=1; i<=oldM.Extent(); i++) { bool found = false; TopTools_ListIteratorOfListOfShape it; // Find all new objects that are a modification of the old object (e.g. a face was resized) for (it.Initialize(mkShape.Modified(oldM(i))); it.More(); it.Next()) { found = true; for (int j=1; j<=newM.Extent(); j++) { // one old object might create several new ones! if (newM(j).IsPartner(it.Value())) { history.shapeMap[i-1].push_back(j-1); // adjust indices to start at zero break; } } } // Find all new objects that were generated from an old object (e.g. a face generated from an edge) for (it.Initialize(mkShape.Generated(oldM(i))); it.More(); it.Next()) { found = true; for (int j=1; j<=newM.Extent(); j++) { if (newM(j).IsPartner(it.Value())) { history.shapeMap[i-1].push_back(j-1); break; } } } if (!found) { // Find all old objects that don't exist any more (e.g. a face was completely cut away) if (mkShape.IsDeleted(oldM(i))) { history.shapeMap[i-1] = std::vector(); } else { // Mop up the rest (will this ever be reached?) for (int j=1; j<=newM.Extent(); j++) { if (newM(j).IsPartner(oldM(i))) { history.shapeMap[i-1].push_back(j-1); break; } } } } } return history; } ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory& newH) { ShapeHistory join; join.type = oldH.type; for (ShapeHistory::MapList::const_iterator it = oldH.shapeMap.begin(); it != oldH.shapeMap.end(); ++it) { int old_shape_index = it->first; if (it->second.empty()) join.shapeMap[old_shape_index] = ShapeHistory::List(); for (ShapeHistory::List::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { ShapeHistory::MapList::const_iterator kt = newH.shapeMap.find(*jt); if (kt != newH.shapeMap.end()) { ShapeHistory::List& ary = join.shapeMap[old_shape_index]; ary.insert(ary.end(), kt->second.begin(), kt->second.end()); } } } return join; } const TopoDS_Shape Feature::findOriginOf(const TopoDS_Shape& reference) { /* Base::Console().Error("Looking for origin of face in %s\n", this->getName()); if (reference.ShapeType() == TopAbs_FACE) { // Find index of reference in the history } */ return TopoDS_Shape(); } /// returns the type name of the ViewProvider const char* Feature::getViewProviderName(void) const { return "PartGui::ViewProviderPart"; } // --------------------------------------------------------- PROPERTY_SOURCE(Part::FilletBase, Part::Feature) FilletBase::FilletBase() { ADD_PROPERTY(Base,(0)); ADD_PROPERTY(Edges,(0,0,0)); Edges.setSize(0); } short FilletBase::mustExecute() const { if (Base.isTouched() || Edges.isTouched()) return 1; return 0; } // --------------------------------------------------------- PROPERTY_SOURCE(Part::FeatureExt, Part::Feature) namespace App { /// @cond DOXERR PROPERTY_SOURCE_TEMPLATE(Part::FeaturePython, Part::Feature) template<> const char* Part::FeaturePython::getViewProviderName(void) const { return "PartGui::ViewProviderPython"; } template<> PyObject* Part::FeaturePython::getPyObject(void) { if (PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new FeaturePythonPyT(this),true); } return Py::new_reference_to(PythonObject); } /// @endcond // explicit template instantiation template class PartExport FeaturePythonT; } // ---------------------------------------------------------------- #include #include #include #include #include #include std::vector Part::findAllFacesCutBy( const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir) { // Find the centre of gravity of the face GProp_GProps props; BRepGProp::SurfaceProperties(face,props); gp_Pnt cog = props.CentreOfMass(); // create a line through the centre of gravity gp_Lin line = gce_MakeLin(cog, dir); // Find intersection of line with all faces of the shape std::vector result; BRepIntCurveSurface_Inter mkSection; // TODO: Less precision than Confusion() should be OK? for (mkSection.Init(shape, line, Precision::Confusion()); mkSection.More(); mkSection.Next()) { gp_Pnt iPnt = mkSection.Pnt(); double dsq = cog.SquareDistance(iPnt); if (dsq < Precision::Confusion()) continue; // intersection with original face // Find out which side of the original face the intersection is on gce_MakeDir mkDir(cog, iPnt); if (!mkDir.IsDone()) continue; // some error (appears highly unlikely to happen, though...) if (mkDir.Value().IsOpposite(dir, Precision::Confusion())) continue; // wrong side of face (opposite to extrusion direction) cutFaces newF; newF.face = mkSection.Face(); newF.distsq = dsq; result.push_back(newF); } return result; } const bool Part::checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, const bool quick, const bool touch_is_intersection) { Bnd_Box first_bb, second_bb; BRepBndLib::Add(first, first_bb); first_bb.SetGap(0); BRepBndLib::Add(second, second_bb); second_bb.SetGap(0); // Note: This test fails if the objects are touching one another at zero distance if (first_bb.IsOut(second_bb)) return false; // no intersection if (quick) return true; // assumed intersection // Try harder if (touch_is_intersection) { // If both shapes fuse to a single solid, then they intersect BRepAlgoAPI_Fuse mkFuse(first, second); if (!mkFuse.IsDone()) return false; if (mkFuse.Shape().IsNull()) return false; // Did we get one or two solids? TopExp_Explorer xp; xp.Init(mkFuse.Shape(),TopAbs_SOLID); if (xp.More()) { // At least one solid xp.Next(); return (xp.More() == Standard_False); } else { return false; } } else { // If both shapes have common material, then they intersect BRepAlgoAPI_Common mkCommon(first, second); if (!mkCommon.IsDone()) return false; if (mkCommon.Shape().IsNull()) return false; // Did we get a solid? TopExp_Explorer xp; xp.Init(mkCommon.Shape(),TopAbs_SOLID); return (xp.More() == Standard_True); } }