386 lines
13 KiB
C++
386 lines
13 KiB
C++
/***************************************************************************
|
|
* 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 <gp_Trsf.hxx>
|
|
# include <gp_Ax1.hxx>
|
|
# include <BRepBuilderAPI_MakeShape.hxx>
|
|
# include <BRepAlgoAPI_Fuse.hxx>
|
|
# include <BRepAlgoAPI_Common.hxx>
|
|
# include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
# include <TopExp.hxx>
|
|
# include <TopTools_IndexedMapOfShape.hxx>
|
|
# include <Standard_Failure.hxx>
|
|
# include <TopoDS_Face.hxx>
|
|
# include <gp_Dir.hxx>
|
|
# include <gp_Pln.hxx> // for Precision::Confusion()
|
|
# include <Bnd_Box.hxx>
|
|
# include <BRepBndLib.hxx>
|
|
#endif
|
|
|
|
|
|
#include <strstream>
|
|
#include <Base/Console.h>
|
|
#include <Base/Writer.h>
|
|
#include <Base/Reader.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/FileInfo.h>
|
|
#include <Base/Stream.h>
|
|
#include <Base/Placement.h>
|
|
#include <Base/Rotation.h>
|
|
#include <App/FeaturePythonPyImp.h>
|
|
|
|
#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)
|
|
{
|
|
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<PyObject *> Feature::getPySubObjects(const std::vector<std::string>& NameVec) const
|
|
{
|
|
std::vector<PyObject *> temp;
|
|
for(std::vector<std::string>::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<TopoShape&>(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<TopoShape&>(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<int>();
|
|
}
|
|
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<Part::PartFeaturePy>(this),true);
|
|
}
|
|
return Py::new_reference_to(PythonObject);
|
|
}
|
|
/// @endcond
|
|
|
|
// explicit template instantiation
|
|
template class PartExport FeaturePythonT<Part::Feature>;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
#include <GProp_GProps.hxx>
|
|
#include <BRepGProp.hxx>
|
|
#include <gce_MakeLin.hxx>
|
|
#include <BRepIntCurveSurface_Inter.hxx>
|
|
#include <IntCurveSurface_IntersectionPoint.hxx>
|
|
#include <gce_MakeDir.hxx>
|
|
|
|
std::vector<Part::cutFaces> 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<cutFaces> 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);
|
|
}
|
|
}
|