FreeCAD/src/Mod/Part/App/PropertyTopoShape.cpp
2016-09-22 11:49:28 +02:00

583 lines
19 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 <sstream>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepBndLib.hxx>
# include <BRepBuilderAPI_GTransform.hxx>
# include <Bnd_Box.hxx>
# include <BRepTools.hxx>
# include <BRepTools_ShapeSet.hxx>
# include <BRepBuilderAPI_Copy.hxx>
# include <TopTools_HSequenceOfShape.hxx>
# include <TopTools_MapOfShape.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Iterator.hxx>
# include <TopExp.hxx>
# include <Standard_Failure.hxx>
# include <gp_GTrsf.hxx>
# include <gp_Trsf.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 <App/Application.h>
#include <App/DocumentObject.h>
#include <App/ObjectIdentifier.h>
#include "PropertyTopoShape.h"
#include "TopoShapePy.h"
#include "TopoShapeFacePy.h"
#include "TopoShapeEdgePy.h"
#include "TopoShapeWirePy.h"
#include "TopoShapeVertexPy.h"
#include "TopoShapeSolidPy.h"
#include "TopoShapeShellPy.h"
#include "TopoShapeCompSolidPy.h"
#include "TopoShapeCompoundPy.h"
using namespace Part;
TYPESYSTEM_SOURCE(Part::PropertyPartShape , App::PropertyComplexGeoData);
PropertyPartShape::PropertyPartShape()
{
}
PropertyPartShape::~PropertyPartShape()
{
}
void PropertyPartShape::setValue(const TopoShape& sh)
{
aboutToSetValue();
_Shape = sh;
hasSetValue();
}
void PropertyPartShape::setValue(const TopoDS_Shape& sh)
{
aboutToSetValue();
_Shape.setShape(sh);
hasSetValue();
}
const TopoDS_Shape& PropertyPartShape::getValue(void)const
{
return _Shape.getShape();
}
const TopoShape& PropertyPartShape::getShape() const
{
return this->_Shape;
}
const Data::ComplexGeoData* PropertyPartShape::getComplexData() const
{
return &(this->_Shape);
}
Base::BoundBox3d PropertyPartShape::getBoundingBox() const
{
Base::BoundBox3d box;
if (_Shape.getShape().IsNull())
return box;
try {
// If the shape is empty an exception may be thrown
Bnd_Box bounds;
BRepBndLib::Add(_Shape.getShape(), bounds);
bounds.SetGap(0.0);
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
box.MinX = xMin;
box.MaxX = xMax;
box.MinY = yMin;
box.MaxY = yMax;
box.MinZ = zMin;
box.MaxZ = zMax;
}
catch (Standard_Failure) {
}
return box;
}
void PropertyPartShape::transformGeometry(const Base::Matrix4D &rclTrf)
{
aboutToSetValue();
_Shape.transformGeometry(rclTrf);
hasSetValue();
}
PyObject *PropertyPartShape::getPyObject(void)
{
Base::PyObjectBase* prop;
const TopoDS_Shape& sh = _Shape.getShape();
if (sh.IsNull()) {
prop = new TopoShapePy(new TopoShape(sh));
}
else {
TopAbs_ShapeEnum type = sh.ShapeType();
switch (type)
{
case TopAbs_COMPOUND:
prop = new TopoShapeCompoundPy(new TopoShape(sh));
break;
case TopAbs_COMPSOLID:
prop = new TopoShapeCompSolidPy(new TopoShape(sh));
break;
case TopAbs_SOLID:
prop = new TopoShapeSolidPy(new TopoShape(sh));
break;
case TopAbs_SHELL:
prop = new TopoShapeShellPy(new TopoShape(sh));
break;
case TopAbs_FACE:
prop = new TopoShapeFacePy(new TopoShape(sh));
break;
case TopAbs_WIRE:
prop = new TopoShapeWirePy(new TopoShape(sh));
break;
case TopAbs_EDGE:
prop = new TopoShapeEdgePy(new TopoShape(sh));
break;
case TopAbs_VERTEX:
prop = new TopoShapeVertexPy(new TopoShape(sh));
break;
case TopAbs_SHAPE:
default:
prop = new TopoShapePy(new TopoShape(sh));
break;
}
}
if (prop) prop->setConst();
return prop;
}
void PropertyPartShape::setPyObject(PyObject *value)
{
if (PyObject_TypeCheck(value, &(TopoShapePy::Type))) {
TopoShapePy *pcObject = static_cast<TopoShapePy*>(value);
setValue(*pcObject->getTopoShapePtr());
}
else {
std::string error = std::string("type must be 'Shape', not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
App::Property *PropertyPartShape::Copy(void) const
{
PropertyPartShape *prop = new PropertyPartShape();
prop->_Shape = this->_Shape;
if (!_Shape.getShape().IsNull()) {
BRepBuilderAPI_Copy copy(_Shape.getShape());
prop->_Shape.setShape(copy.Shape());
}
return prop;
}
void PropertyPartShape::Paste(const App::Property &from)
{
aboutToSetValue();
_Shape = dynamic_cast<const PropertyPartShape&>(from)._Shape;
hasSetValue();
}
unsigned int PropertyPartShape::getMemSize (void) const
{
return _Shape.getMemSize();
}
void PropertyPartShape::getPaths(std::vector<App::ObjectIdentifier> &paths) const
{
paths.push_back(App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String("ShapeType")));
paths.push_back(App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String("Orientation")));
paths.push_back(App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String("Length")));
paths.push_back(App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String("Area")));
paths.push_back(App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String("Volume")));
}
void PropertyPartShape::Save (Base::Writer &writer) const
{
if(!writer.isForceXML()) {
//See SaveDocFile(), RestoreDocFile()
if (writer.getMode("BinaryBrep")) {
writer.Stream() << writer.ind() << "<Part file=\""
<< writer.addFile("PartShape.bin", this)
<< "\"/>" << std::endl;
}
else {
writer.Stream() << writer.ind() << "<Part file=\""
<< writer.addFile("PartShape.brp", this)
<< "\"/>" << std::endl;
}
}
}
void PropertyPartShape::Restore(Base::XMLReader &reader)
{
reader.readElement("Part");
std::string file (reader.getAttribute("file") );
if (!file.empty()) {
// initate a file read
reader.addFile(file.c_str(),this);
}
}
void PropertyPartShape::SaveDocFile (Base::Writer &writer) const
{
// If the shape is empty we simply store nothing. The file size will be 0 which
// can be checked when reading in the data.
if (_Shape.getShape().IsNull())
return;
// NOTE: Cleaning the triangulation may cause problems on some algorithms like BOP
// Before writing to the project we clean all triangulation data to save memory
BRepBuilderAPI_Copy copy(_Shape.getShape());
const TopoDS_Shape& myShape = copy.Shape();
BRepTools::Clean(myShape); // remove triangulation
if (writer.getMode("BinaryBrep")) {
TopoShape shape;
shape.setShape(myShape);
shape.exportBinary(writer.Stream());
}
else {
bool direct = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", true);
if (!direct) {
// create a temporary file and copy the content to the zip stream
// once the tmp. filename is known use always the same because otherwise
// we may run into some problems on the Linux platform
static Base::FileInfo fi(App::Application::getTempFileName());
if (!BRepTools::Write(myShape,(const Standard_CString)fi.filePath().c_str())) {
// Note: Do NOT throw an exception here because if the tmp. file could
// not be created we should not abort.
// We only print an error message but continue writing the next files to the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("Shape of '%s' cannot be written to BRep file '%s'\n",
obj->Label.getValue(),fi.filePath().c_str());
}
else {
Base::Console().Error("Cannot save BRep file '%s'\n", fi.filePath().c_str());
}
std::stringstream ss;
ss << "Cannot save BRep file '" << fi.filePath() << "'";
writer.addError(ss.str());
}
Base::ifstream file(fi, std::ios::in | std::ios::binary);
if (file){
unsigned long ulSize = 0;
std::streambuf* buf = file.rdbuf();
if (buf) {
unsigned long ulCurr;
ulCurr = buf->pubseekoff(0, std::ios::cur, std::ios::in);
ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in);
buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in);
}
// read in the ASCII file and write back to the stream
std::strstreambuf sbuf(ulSize);
file >> &sbuf;
writer.Stream() << &sbuf;
}
file.close();
// remove temp file
fi.deleteFile();
}
else {
BRepTools::Write(myShape, writer.Stream());
}
}
}
void PropertyPartShape::RestoreDocFile(Base::Reader &reader)
{
Base::FileInfo brep(reader.getFileName());
if (brep.hasExtension("bin")) {
TopoShape shape;
shape.importBinary(reader);
setValue(shape);
}
else {
bool direct = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", true);
if (!direct) {
BRep_Builder builder;
// create a temporary file and copy the content from the zip stream
Base::FileInfo fi(App::Application::getTempFileName());
// read in the ASCII file and write back to the file stream
Base::ofstream file(fi, std::ios::out | std::ios::binary);
unsigned long ulSize = 0;
if (reader) {
std::streambuf* buf = file.rdbuf();
reader >> buf;
file.flush();
ulSize = buf->pubseekoff(0, std::ios::cur, std::ios::in);
}
file.close();
// Read the shape from the temp file, if the file is empty the stored shape was already empty.
// If it's still empty after reading the (non-empty) file there must occurred an error.
TopoDS_Shape shape;
if (ulSize > 0) {
if (!BRepTools::Read(shape, (const Standard_CString)fi.filePath().c_str(), builder)) {
// Note: Do NOT throw an exception here because if the tmp. created file could
// not be read it's NOT an indication for an invalid input stream 'reader'.
// We only print an error message but continue reading the next files from the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("BRep file '%s' with shape of '%s' seems to be empty\n",
fi.filePath().c_str(),obj->Label.getValue());
}
else {
Base::Console().Warning("Loaded BRep file '%s' seems to be empty\n", fi.filePath().c_str());
}
}
}
// delete the temp file
fi.deleteFile();
setValue(shape);
}
else {
BRep_Builder builder;
TopoDS_Shape shape;
BRepTools::Read(shape, reader, builder);
setValue(shape);
}
}
}
// -------------------------------------------------------------------------
TYPESYSTEM_SOURCE(Part::PropertyShapeHistory , App::PropertyLists);
PropertyShapeHistory::PropertyShapeHistory()
{
}
PropertyShapeHistory::~PropertyShapeHistory()
{
}
void PropertyShapeHistory::setValue(const ShapeHistory& sh)
{
aboutToSetValue();
_lValueList.resize(1);
_lValueList[0] = sh;
hasSetValue();
}
void PropertyShapeHistory::setValues(const std::vector<ShapeHistory>& values)
{
aboutToSetValue();
_lValueList = values;
hasSetValue();
}
PyObject *PropertyShapeHistory::getPyObject(void)
{
return Py::new_reference_to(Py::None());
}
void PropertyShapeHistory::setPyObject(PyObject *)
{
}
void PropertyShapeHistory::Save (Base::Writer &) const
{
}
void PropertyShapeHistory::Restore(Base::XMLReader &)
{
}
void PropertyShapeHistory::SaveDocFile (Base::Writer &) const
{
}
void PropertyShapeHistory::RestoreDocFile(Base::Reader &)
{
}
App::Property *PropertyShapeHistory::Copy(void) const
{
PropertyShapeHistory *p= new PropertyShapeHistory();
p->_lValueList = _lValueList;
return p;
}
void PropertyShapeHistory::Paste(const Property &from)
{
aboutToSetValue();
_lValueList = dynamic_cast<const PropertyShapeHistory&>(from)._lValueList;
hasSetValue();
}
// -------------------------------------------------------------------------
TYPESYSTEM_SOURCE(Part::PropertyFilletEdges , App::PropertyLists);
PropertyFilletEdges::PropertyFilletEdges()
{
}
PropertyFilletEdges::~PropertyFilletEdges()
{
}
void PropertyFilletEdges::setValue(int id, double r1, double r2)
{
aboutToSetValue();
_lValueList.resize(1);
_lValueList[0].edgeid = id;
_lValueList[0].radius1 = r1;
_lValueList[0].radius2 = r2;
hasSetValue();
}
void PropertyFilletEdges::setValues(const std::vector<FilletElement>& values)
{
aboutToSetValue();
_lValueList = values;
hasSetValue();
}
PyObject *PropertyFilletEdges::getPyObject(void)
{
Py::List list(getSize());
std::vector<FilletElement>::const_iterator it;
int index = 0;
for (it = _lValueList.begin(); it != _lValueList.end(); ++it) {
Py::Tuple ent(3);
ent.setItem(0, Py::Int(it->edgeid));
ent.setItem(1, Py::Float(it->radius1));
ent.setItem(2, Py::Float(it->radius2));
list[index++] = ent;
}
return Py::new_reference_to(list);
}
void PropertyFilletEdges::setPyObject(PyObject *value)
{
Py::Sequence list(value);
std::vector<FilletElement> values;
values.reserve(list.size());
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
FilletElement fe;
Py::Tuple ent(*it);
fe.edgeid = (int)Py::Int(ent.getItem(0));
fe.radius1 = (double)Py::Float(ent.getItem(1));
fe.radius2 = (double)Py::Float(ent.getItem(2));
values.push_back(fe);
}
setValues(values);
}
void PropertyFilletEdges::Save (Base::Writer &writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<FilletEdges file=\"" << writer.addFile(getName(), this) << "\"/>" << std::endl;
}
}
void PropertyFilletEdges::Restore(Base::XMLReader &reader)
{
reader.readElement("FilletEdges");
std::string file (reader.getAttribute("file") );
if (!file.empty()) {
// initate a file read
reader.addFile(file.c_str(),this);
}
}
void PropertyFilletEdges::SaveDocFile (Base::Writer &writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
for (std::vector<FilletElement>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
str << it->edgeid << it->radius1 << it->radius2;
}
}
void PropertyFilletEdges::RestoreDocFile(Base::Reader &reader)
{
Base::InputStream str(reader);
uint32_t uCt=0;
str >> uCt;
std::vector<FilletElement> values(uCt);
for (std::vector<FilletElement>::iterator it = values.begin(); it != values.end(); ++it) {
str >> it->edgeid >> it->radius1 >> it->radius2;
}
setValues(values);
}
App::Property *PropertyFilletEdges::Copy(void) const
{
PropertyFilletEdges *p= new PropertyFilletEdges();
p->_lValueList = _lValueList;
return p;
}
void PropertyFilletEdges::Paste(const Property &from)
{
aboutToSetValue();
_lValueList = dynamic_cast<const PropertyFilletEdges&>(from)._lValueList;
hasSetValue();
}