diff --git a/src/Mod/TechDraw/App/AppTechDraw.cpp b/src/Mod/TechDraw/App/AppTechDraw.cpp new file mode 100644 index 0000000000..27dc59e9dd --- /dev/null +++ b/src/Mod/TechDraw/App/AppTechDraw.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * * + * This program 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. * + * for detail see the LICENCE text file. * + * Jürgen Riegel 2007 * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif + +#include +#include + +#include "DrawPage.h" +#include "DrawSVGTemplate.h" +#include "DrawParametricTemplate.h" +#include "DrawView.h" +#include "DrawViewCollection.h" +#include "DrawViewPart.h" +#include "DrawViewSection.h" +#include "DrawViewAnnotation.h" +#include "DrawViewDimension.h" +#include "DrawProjGroupItem.h" +#include "DrawProjGroup.h" +#include "DrawViewSymbol.h" +#include "DrawProjection.h" +#include "DrawViewClip.h" +#include "DrawHatch.h" + +extern struct PyMethodDef Drawing_methods[]; + +PyDoc_STRVAR(module_drawing_doc, +"This module is the Drawing module."); + + +/* Python entry */ +extern "C" { +void DrawingExport initDrawing() +{ + // load dependent module + try { + Base::Interpreter().loadModule("Part"); + Base::Interpreter().loadModule("Measure"); + //Base::Interpreter().loadModule("Mesh"); + } + catch(const Base::Exception& e) { + PyErr_SetString(PyExc_ImportError, e.what()); + return; + } + Py_InitModule3("Drawing", Drawing_methods, module_drawing_doc); /* mod name, table ptr */ + Base::Console().Log("Loading Drawing module... done\n"); + + + // NOTE: To finish the initialization of our own type objects we must + // call PyType_Ready, otherwise we run into a segmentation fault, later on. + // This function is responsible for adding inherited slots from a type's base class. + + TechDraw::DrawPage ::init(); + TechDraw::DrawView ::init(); + TechDraw::DrawViewCollection ::init(); + TechDraw::DrawViewPart ::init(); + TechDraw::DrawProjection ::init(); + TechDraw::DrawViewAnnotation ::init(); + TechDraw::DrawViewSymbol ::init(); + + TechDraw::DrawViewSection ::init(); + TechDraw::DrawViewDimension ::init(); + TechDraw::DrawProjGroup ::init(); + TechDraw::DrawProjGroupItem ::init(); + TechDraw::DrawTemplate ::init(); + TechDraw::DrawParametricTemplate::init(); + TechDraw::DrawSVGTemplate ::init(); + + TechDraw::DrawViewClip ::init(); + TechDraw::DrawHatch ::init(); + + // Python Types + TechDraw::DrawViewPython ::init(); + TechDraw::DrawViewPartPython ::init(); + TechDraw::DrawTemplatePython ::init(); + TechDraw::DrawViewSymbolPython::init(); +} + +} // extern "C" diff --git a/src/Mod/TechDraw/App/AppTechDrawPy.cpp b/src/Mod/TechDraw/App/AppTechDrawPy.cpp new file mode 100644 index 0000000000..b5b2ad12a8 --- /dev/null +++ b/src/Mod/TechDraw/App/AppTechDrawPy.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** + * 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 +#endif + +#include +#include "ProjectionAlgos.h" +#include +#include +#include + +#include + +using namespace TechDraw; +using namespace Part; +using namespace std; + +static PyObject * +project(PyObject *self, PyObject *args) +{ + PyObject *pcObjShape; + PyObject *pcObjDir=0; + + if (!PyArg_ParseTuple(args, "O!|O!", &(TopoShapePy::Type), &pcObjShape,&(Base::VectorPy::Type), &pcObjDir)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + TopoShapePy* pShape = static_cast(pcObjShape); + Base::Vector3d Vector(0,0,1); + if (pcObjDir) + Vector = *static_cast(pcObjDir)->getVectorPtr(); + + ProjectionAlgos Alg(pShape->getTopoShapePtr()->_Shape,Vector); + + Py::List list; + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.V)) , true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.V1)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.H)) , true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.H1)), true)); + + return Py::new_reference_to(list); + + } PY_CATCH_OCC; + +} + +static PyObject * +projectEx(PyObject *self, PyObject *args) +{ + PyObject *pcObjShape; + PyObject *pcObjDir=0; + + if (!PyArg_ParseTuple(args, "O!|O!", &(TopoShapePy::Type), &pcObjShape,&(Base::VectorPy::Type), &pcObjDir)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + TopoShapePy* pShape = static_cast(pcObjShape); + Base::Vector3d Vector(0,0,1); + if (pcObjDir) + Vector = *static_cast(pcObjDir)->getVectorPtr(); + + ProjectionAlgos Alg(pShape->getTopoShapePtr()->_Shape,Vector); + + Py::List list; + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.V)) , true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.V1)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.VN)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.VO)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.VI)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.H)) , true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.H1)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.HN)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.HO)), true)); + list.append(Py::Object(new TopoShapePy(new TopoShape(Alg.HI)), true)); + + return Py::new_reference_to(list); + + } PY_CATCH_OCC; +} + +static PyObject * +projectToSVG(PyObject *self, PyObject *args) +{ + PyObject *pcObjShape; + PyObject *pcObjDir=0; + const char *type=0; + float scale=1.0f; + float tol=0.1f; + + if (!PyArg_ParseTuple(args, "O!|O!sff", &(TopoShapePy::Type), &pcObjShape, + &(Base::VectorPy::Type), &pcObjDir, &type, &scale, &tol)) + return NULL; + + PY_TRY { + TopoShapePy* pShape = static_cast(pcObjShape); + Base::Vector3d Vector(0,0,1); + if (pcObjDir) + Vector = static_cast(pcObjDir)->value(); + ProjectionAlgos Alg(pShape->getTopoShapePtr()->_Shape,Vector); + + bool hidden = false; + if (type && std::string(type) == "ShowHiddenLines") + hidden = true; + + Py::String result(Alg.getSVG(hidden?ProjectionAlgos::WithHidden:ProjectionAlgos::Plain, scale, tol)); + return Py::new_reference_to(result); + + } PY_CATCH_OCC; +} + +static PyObject * +projectToDXF(PyObject *self, PyObject *args) +{ + PyObject *pcObjShape; + PyObject *pcObjDir=0; + const char *type=0; + float scale=1.0f; + float tol=0.1f; + + if (!PyArg_ParseTuple(args, "O!|O!sff", &(TopoShapePy::Type), &pcObjShape, + &(Base::VectorPy::Type), &pcObjDir, &type, &scale, &tol)) + return NULL; + + PY_TRY { + TopoShapePy* pShape = static_cast(pcObjShape); + Base::Vector3d Vector(0,0,1); + if (pcObjDir) + Vector = static_cast(pcObjDir)->value(); + ProjectionAlgos Alg(pShape->getTopoShapePtr()->_Shape,Vector); + + bool hidden = false; + if (type && std::string(type) == "ShowHiddenLines") + hidden = true; + + Py::String result(Alg.getDXF(hidden?ProjectionAlgos::WithHidden:ProjectionAlgos::Plain, scale, tol)); + return Py::new_reference_to(result); + + } PY_CATCH_OCC; +} + +static PyObject * +removeSvgTags(PyObject *self, PyObject *args) +{ + const char* svgcode; + if (!PyArg_ParseTuple(args, "s",&svgcode)) + return NULL; + + PY_TRY { + string svg(svgcode); + string empty = ""; + string endline = "--endOfLine--"; + string linebreak = "\\n"; + // removing linebreaks for regex to work + boost::regex e1 ("\\n"); + svg = boost::regex_replace(svg, e1, endline); + // removing starting xml definition + boost::regex e2 ("<\\?xml.*?\\?>"); + svg = boost::regex_replace(svg, e2, empty); + // removing starting svg tag + boost::regex e3 (""); + svg = boost::regex_replace(svg, e3, empty); + // removing sodipodi tags -- DANGEROUS, some sodipodi tags are single, better leave it + //boost::regex e4 (""); + //svg = boost::regex_replace(svg, e4, empty); + // removing metadata tags + boost::regex e5 (""); + svg = boost::regex_replace(svg, e5, empty); + // removing closing svg tags + boost::regex e6 (""); + svg = boost::regex_replace(svg, e6, empty); + // restoring linebreaks + boost::regex e7 ("--endOfLine--"); + svg = boost::regex_replace(svg, e7, linebreak); + Py::String result(svg); + + return Py::new_reference_to(result); + } PY_CATCH_OCC; +} + +/* registration table */ +struct PyMethodDef Drawing_methods[] = { + {"project" ,project ,METH_VARARGS, + "[visiblyG0,visiblyG1,hiddenG0,hiddenG1] = project(TopoShape[,App.Vector Direction, string type]) -- Project a shape and return the visible/invisible parts of it."}, + {"projectEx" ,projectEx ,METH_VARARGS, + "[V,V1,VN,VO,VI,H,H1,HN,HO,HI] = projectEx(TopoShape[,App.Vector Direction, string type]) -- Project a shape and return the all parts of it."}, + {"projectToSVG" ,projectToSVG ,METH_VARARGS, + "string = projectToSVG(TopoShape[,App.Vector Direction, string type]) -- Project a shape and return the SVG representation as string."}, + {"projectToDXF" ,projectToDXF ,METH_VARARGS, + "string = projectToDXF(TopoShape[,App.Vector Direction, string type]) -- Project a shape and return the DXF representation as string."}, + {"removeSvgTags" ,removeSvgTags ,METH_VARARGS, + "string = removeSvgTags(string) -- Removes the opening and closing svg tags and other metatags from a svg code, making it embeddable"}, + {NULL, NULL} /* end of table marker */ +}; diff --git a/src/Mod/TechDraw/App/CMakeLists.txt b/src/Mod/TechDraw/App/CMakeLists.txt new file mode 100644 index 0000000000..04e8d50cdd --- /dev/null +++ b/src/Mod/TechDraw/App/CMakeLists.txt @@ -0,0 +1,135 @@ +if(MSVC) + add_definitions(-DFCAppTechDraw -DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH) +else(MSVC) + add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H -DHAVE_ACOSH -DHAVE_ATANH -DHAVE_ASINH) +endif(MSVC) + +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/src + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR} + ${Boost_INCLUDE_DIRS} + ${QT_INCLUDE_DIR} + ${OCC_INCLUDE_DIR} + ${ZLIB_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIRS} + ${XercesC_INCLUDE_DIRS} + ${QT_QTCORE_INCLUDE_DIR} +) +link_directories(${OCC_LIBRARY_DIR}) + +set(TechDrawLIBS + Measure + Part + FreeCADApp +) + +generate_from_xml(DrawPagePy) +generate_from_xml(DrawViewPy) +generate_from_xml(DrawViewSymbolPy) +generate_from_xml(DrawTemplatePy) +generate_from_xml(DrawParametricTemplatePy) +generate_from_xml(DrawSVGTemplatePy) +generate_from_xml(DrawViewSymbolPy) + +SET(Draw_SRCS + DrawPage.cpp + DrawPage.h + DrawProjection.cpp + DrawProjection.h + DrawView.cpp + DrawView.h + DrawViewPart.cpp + DrawViewPart.h + DrawViewAnnotation.cpp + DrawViewAnnotation.h + DrawViewSymbol.cpp + DrawViewSymbol.h + DrawViewClip.cpp + DrawViewClip.h + DrawProjGroup.cpp + DrawProjGroup.h + DrawProjGroupItem.cpp + DrawProjGroupItem.h + DrawParametricTemplate.cpp + DrawParametricTemplate.h + DrawSVGTemplate.cpp + DrawSVGTemplate.h + DrawTemplate.cpp + DrawTemplate.h + DrawViewCollection.cpp + DrawViewCollection.h + DrawViewDimension.cpp + DrawViewDimension.h + DrawViewSection.cpp + DrawViewSection.h + DrawHatch.cpp + DrawHatch.h +) + +SET(TechDraw_SRCS + AppTechDraw.cpp + AppTechDrawPy.cpp + DrawUtil.cpp + DrawUtil.h + PreCompiled.cpp + PreCompiled.h +) + +SET(Geometry_SRCS + Geometry.cpp + Geometry.h + GeometryObject.cpp + GeometryObject.h +) + +SET(Python_SRCS + DrawPagePy.xml + DrawPagePyImp.cpp + DrawViewPy.xml + DrawViewPyImp.cpp + DrawViewSymbolPy.xml + DrawViewSymbolPyImp.cpp + DrawTemplatePy.xml + DrawTemplatePyImp.cpp + DrawParametricTemplatePy.xml + DrawParametricTemplatePyImp.cpp + DrawSVGTemplatePy.xml + DrawSVGTemplatePyImp.cpp +) + +SOURCE_GROUP("Mod" FILES ${TechDraw_SRCS}) +SOURCE_GROUP("Features" FILES ${Draw_SRCS}) +SOURCE_GROUP("Geometry" FILES ${Geometry_SRCS}) +SOURCE_GROUP("Python" FILES ${Python_SRCS}) + + +if(MSVC) + #add_definitions(-D_PreComp_) + #GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" TechDrawCPP_SRCS ${TechDraw_SRCS} ${Draw_SRCS} ) + #ADD_MSVC_PRECOMPILED_HEADER(TechDraw PreCompiled.h PreCompiled.cpp TechDrawCPP_SRCS) +endif(MSVC) + +add_library(TechDraw SHARED ${TechDraw_SRCS} ${Draw_SRCS} ${TechDrawAlgos_SRCS} + ${Geometry_SRCS} ${Python_SRCS}) +target_link_libraries(TechDraw ${TechDrawLIBS};${QT_QTXML_LIBRARY};${TechDraw}) + +SET(TechDrawScripts + Init.py +) + +fc_target_copy_resource(TechDraw + ${CMAKE_SOURCE_DIR}/src/Mod/TechDraw + ${CMAKE_BINARY_DIR}/Mod/TechDraw + ${TechDrawScripts}) + +fc_target_copy_resource(TechDraw + ${CMAKE_SOURCE_DIR}/src/Mod/TechDraw + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw + ${TechDrawTemplates}) + +SET_BIN_DIR(TechDraw TechDraw /Mod/TechDraw) +SET_PYTHON_PREFIX_SUFFIX(TechDraw) + +INSTALL(TARGETS TechDraw DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/Mod/TechDraw/App/DrawHatch.cpp b/src/Mod/TechDraw/App/DrawHatch.cpp new file mode 100644 index 0000000000..6527a764ce --- /dev/null +++ b/src/Mod/TechDraw/App/DrawHatch.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (c) 2015 WandererFan * + * * + * 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 +#endif + +#include + +#include +#include +#include +#include +#include + +#include "DrawHatch.h" + +using namespace TechDraw; +using namespace std; + +PROPERTY_SOURCE(TechDraw::DrawHatch, TechDraw::DrawView) + + +DrawHatch::DrawHatch(void) +{ + static const char *vgroup = "Hatch"; + + ADD_PROPERTY_TYPE(PartView, (0), vgroup, (App::PropertyType)(App::Prop_None), "Parent view feature"); + ADD_PROPERTY_TYPE(DirProjection ,(0,0,1.0) ,vgroup,App::Prop_None,"Projection direction when Hatch was defined"); //sb RO? + ADD_PROPERTY_TYPE(Edges,(0,0),vgroup,(App::PropertyType)(App::Prop_None),"The outline of the hatch area"); + ADD_PROPERTY_TYPE(HatchPattern ,(""),vgroup,App::Prop_None,"The hatch pattern file for this area"); + ADD_PROPERTY_TYPE(HatchColor,(0.0f,0.0f,0.0f),vgroup,App::Prop_None,"The color of the hatch area"); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Drawing"); + + std::string defaultDir = App::Application::getResourceDir() + "Mod/Drawing/patterns"; + QString patternDir = QString::fromStdString(hGrp->GetASCII("PatternDir", defaultDir.c_str())); + if (patternDir.isEmpty()) { //PatternDir key probably has null value + patternDir = QString::fromStdString(defaultDir); + } + std::string defaultFileName = "simple.svg"; + QString patternFileName = QString::fromStdString(hGrp->GetASCII("PatternFile",defaultFileName.c_str())); + if (patternFileName.isEmpty()) { + patternFileName = QString::fromStdString(defaultFileName); + } + patternFileName = patternDir + QString::fromUtf8("/") + patternFileName; + HatchPattern.setValue(patternFileName.toUtf8().constData()); +} + +DrawHatch::~DrawHatch() +{ +} + +void DrawHatch::onChanged(const App::Property* prop) +{ + if (prop == &PartView || + prop == &Edges || + prop == &HatchPattern || + prop == &HatchColor) { + if (!isRestoring()) { + DrawHatch::execute(); + if (PartView.getValue()) { + PartView.getValue()->touch(); + PartView.getValue()->recompute(); + } + } + } + App::DocumentObject::onChanged(prop); +} + +App::DocumentObjectExecReturn *DrawHatch::execute(void) +{ + //TODO: need to refresh DrawViewPart to reflect change in hatch + return App::DocumentObject::StdReturn; +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawHatchPython, TechDraw::DrawHatch) +template<> const char* TechDraw::DrawHatchPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderHatch"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawHatch.h b/src/Mod/TechDraw/App/DrawHatch.h new file mode 100644 index 0000000000..64874b4d83 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawHatch.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (c) 2015 WandererFan * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _Drawing_DrawHatch_h_ +#define _Drawing_DrawHatch_h_ + +# include +# include +# include +#include + +#include "DrawView.h" +#include "DrawViewPart.h" + +namespace TechDraw +{ + +class DrawingExport DrawHatch : public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawHatch); + +public: + DrawHatch(); + virtual ~DrawHatch(); + + App::PropertyLink PartView; + App::PropertyVector DirProjection; //edge list is only valid for original projection? + App::PropertyLinkSubList Edges; + App::PropertyFile HatchPattern; + App::PropertyColor HatchColor; + + //short mustExecute() const; + + virtual App::DocumentObjectExecReturn *execute(void); + + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderHatch"; + } + + //DrawViewPart* getViewPart() const; + +protected: + void onChanged(const App::Property* prop); + +private: +}; + +typedef App::FeaturePythonT DrawHatchPython; + +} //namespace TechDraw +#endif diff --git a/src/Mod/TechDraw/App/DrawPage.cpp b/src/Mod/TechDraw/App/DrawPage.cpp new file mode 100644 index 0000000000..942d3db811 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawPage.cpp @@ -0,0 +1,275 @@ +/*************************************************************************** + * 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 +#endif + +#include +#include +#include +#include +#include +#include + +#include "DrawPage.h" +#include "DrawView.h" +#include "DrawProjGroup.h" +#include "DrawViewClip.h" +#include "DrawTemplate.h" +#include "DrawViewCollection.h" +#include "DrawViewPart.h" +#include "DrawViewDimension.h" + +#include "DrawPagePy.h" // generated from DrawPagePy.xml + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawPage +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawPage, App::DocumentObject) + +const char* DrawPage::ProjectionTypeEnums[]= {"First Angle", + "Third Angle", + NULL}; + +DrawPage::DrawPage(void) +{ + static const char *group = "Page"; + + ADD_PROPERTY_TYPE(Template, (0), group, (App::PropertyType)(App::Prop_None), "Attached Template"); + ADD_PROPERTY_TYPE(Views, (0), group, (App::PropertyType)(App::Prop_None),"Attached Views"); + + // Projection Properties + ProjectionType.setEnums(ProjectionTypeEnums); + ADD_PROPERTY(ProjectionType, ((long)0)); + ADD_PROPERTY_TYPE(Scale ,(1.0), group, App::Prop_None, "Scale factor for this Page"); +} + +DrawPage::~DrawPage() +{ +} + +void DrawPage::onBeforeChange(const App::Property* prop) +{ + App::DocumentObject::onBeforeChange(prop); +} + +void DrawPage::onChanged(const App::Property* prop) +{ + if (prop == &Template) { + if (!isRestoring()) { + //TODO: reload if Template prop changes (ie different Template) + Base::Console().Message("TODO: Unimplemented function DrawPage::onChanged(Template)\n"); + } + } else if (prop == &Views) { + if (!isRestoring()) { + //TODO: reload if Views prop changes (ie adds/deletes) + //touch(); + } + } else if(prop == &Scale) { + // touch all views in the Page as they may be dependent on this scale + const std::vector &vals = Views.getValues(); + for(std::vector::const_iterator it = vals.begin(); it < vals.end(); ++it) { + TechDraw::DrawView *view = dynamic_cast(*it); + if (view != NULL && view->ScaleType.isValue("Document")) { + view->Scale.touch(); + } + } + } else if (prop == &ProjectionType) { + // touch all ortho views in the Page as they may be dependent on Projection Type + const std::vector &vals = Views.getValues(); + for(std::vector::const_iterator it = vals.begin(); it < vals.end(); ++it) { + TechDraw::DrawProjGroup *view = dynamic_cast(*it); + if (view != NULL && view->ProjectionType.isValue("Document")) { + view->ProjectionType.touch(); + } + } + + // TODO: Also update Template graphic. + + } + App::DocumentObject::onChanged(prop); +} + +App::DocumentObjectExecReturn *DrawPage::execute(void) +{ + Template.touch(); + Views.touch(); + return App::DocumentObject::StdReturn; +} + +short DrawPage::mustExecute() const +{ + if(Scale.isTouched()) + return 1; + + // Check the value of template if this has been modified + App::DocumentObject* tmpl = Template.getValue(); + if(tmpl && tmpl->isTouched()) + return 1; + + // Check if within this Page, any Views have been touched + bool ViewsTouched = false; + const std::vector &vals = Views.getValues(); + for(std::vector::const_iterator it = vals.begin(); it < vals.end(); ++it) { + if((*it)->isTouched()) { + return 1; + } + } + + return (ViewsTouched) ? 1 : App::DocumentObject::mustExecute(); +} + +PyObject *DrawPage::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new DrawPagePy(this),true); + } + + return Py::new_reference_to(PythonObject); +} + +bool DrawPage::hasValidTemplate() const +{ + App::DocumentObject *obj = 0; + obj = Template.getValue(); + + if(obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) { + TechDraw::DrawTemplate *templ = static_cast(obj); + if (templ->getWidth() > 0. && + templ->getHeight() > 0.) { + return true; + } + } + + return false; +} + +double DrawPage::getPageWidth() const +{ + App::DocumentObject *obj = 0; + obj = Template.getValue(); + + if( obj && obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId()) ) { + TechDraw::DrawTemplate *templ = static_cast(obj); + return templ->getWidth(); + } + + throw Base::Exception("Template not set for Page"); +} + +double DrawPage::getPageHeight() const +{ + App::DocumentObject *obj = 0; + obj = Template.getValue(); + + if(obj) { + if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) { + TechDraw::DrawTemplate *templ = static_cast(obj); + return templ->getHeight(); + } + } + + throw Base::Exception("Template not set for Page"); +} + +const char * DrawPage::getPageOrientation() const +{ + App::DocumentObject *obj; + obj = Template.getValue(); + + if(obj) { + if(obj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId())) { + TechDraw::DrawTemplate *templ = static_cast(obj); + + return templ->Orientation.getValueAsString(); + } + } + throw Base::Exception("Template not set for Page"); +} + +int DrawPage::addView(App::DocumentObject *docObj) +{ + if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) + return -1; + + const std::vector currViews = Views.getValues(); + std::vector newViews(currViews); + newViews.push_back(docObj); + Views.setValues(newViews); + Views.touch(); + return Views.getSize(); +} + +int DrawPage::removeView(App::DocumentObject *docObj) +{ + if(!docObj->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) + return -1; + + const std::vector currViews = Views.getValues(); + std::vector newViews; + std::vector::const_iterator it = currViews.begin(); + for (; it != currViews.end(); it++) { + std::string viewName = docObj->getNameInDocument(); + if (viewName.compare((*it)->getNameInDocument()) != 0) { + newViews.push_back((*it)); + } + } + Views.setValues(newViews); + Views.touch(); + + return Views.getSize(); +} + +void DrawPage::onDocumentRestored() +{ + std::vector featViews = Views.getValues(); + std::vector::const_iterator it = featViews.begin(); + //first, make sure all the Parts have been executed so GeometryObjects exist + for(; it != featViews.end(); ++it) { + TechDraw::DrawViewPart *part = dynamic_cast(*it); + if (part != NULL) { + part->execute(); + } + } + //second, make sure all the Dimensions have been executed so Measurements have References + for(it = featViews.begin(); it != featViews.end(); ++it) { + TechDraw::DrawViewDimension *dim = dynamic_cast(*it); + if (dim != NULL) { + dim->execute(); + } + } + recompute(); + App::DocumentObject::onDocumentRestored(); +} + diff --git a/src/Mod/TechDraw/App/DrawPage.h b/src/Mod/TechDraw/App/DrawPage.h new file mode 100644 index 0000000000..fdc3d36205 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawPage.h @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * * + * 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 * + * * + ***************************************************************************/ + + +#ifndef _DrawPage_h_ +#define _DrawPage_h_ + +#include "App/DocumentObject.h" +#include "App/DocumentObjectGroup.h" +#include "App/PropertyStandard.h" +#include "App/PropertyFile.h" +//#include "App/FeaturePython.h" + +namespace TechDraw +{ + +class DrawingExport DrawPage: public App::DocumentObject +{ + PROPERTY_HEADER(TechDraw::DrawPage); + +public: + /// Constructor + DrawPage(void); + virtual ~DrawPage(); + + App::PropertyLinkList Views; + App::PropertyLink Template; + + App::PropertyFloat Scale; + App::PropertyEnumeration ProjectionType; // First or Third Angle + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + int addView(App::DocumentObject *docObj); + int removeView(App::DocumentObject* docObj); + short mustExecute() const; + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderDrawingPage"; + } + + PyObject *getPyObject(void); + +//App::DocumentObjectExecReturn * recompute(void); + + /// Check whether we've got a valid template + /*! + * \return boolean answer to the question: "Doest thou have a valid template?" + */ + bool hasValidTemplate() const; + /// Returns width of the template + /*! + * \throws Base::Exception if no template is loaded. + */ + double getPageWidth() const; + /// Returns height of the template + /*! + * \throws Base::Exception if no template is loaded. + */ + double getPageHeight() const; + const char* getPageOrientation() const; + +protected: + void onBeforeChange(const App::Property* prop); + void onChanged(const App::Property* prop); + virtual void onDocumentRestored(); + +private: + static const char* ProjectionTypeEnums[]; +}; + +} //namespace TechDraw + + +#endif diff --git a/src/Mod/TechDraw/App/DrawPagePy.xml b/src/Mod/TechDraw/App/DrawPagePy.xml new file mode 100644 index 0000000000..0f0e2cfedd --- /dev/null +++ b/src/Mod/TechDraw/App/DrawPagePy.xml @@ -0,0 +1,38 @@ + + + + + + Feature for creating and manipulating Drawing Pages + + + + addView(DrawView) - Add a View to this Page + + + + + Return the width of this page + + + + + Return the height of this page + + + + + Return the orientation of this page + + + + + diff --git a/src/Mod/TechDraw/App/DrawPagePyImp.cpp b/src/Mod/TechDraw/App/DrawPagePyImp.cpp new file mode 100644 index 0000000000..71bcf3d590 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawPagePyImp.cpp @@ -0,0 +1,65 @@ + +#include "PreCompiled.h" +#include + +#include "Mod/Drawing/App/DrawPage.h" +#include "Mod/Drawing/App/DrawView.h" +#include "DrawViewPy.h" + +// inclusion of the generated files (generated out of DrawPagePy.xml) +#include "DrawPagePy.h" +#include "DrawPagePy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawPagePy::representation(void) const +{ + return std::string(""); +} + +PyObject* DrawPagePy::addView(PyObject* args) +{ + PyObject *pcFeatView; + + if (!PyArg_ParseTuple(args, "O!", &(TechDraw::DrawViewPy::Type), &pcFeatView)) { // convert args: Python->C + Base::Console().Error("Error: DrawPagePy::addView - Bad Args\n"); + return NULL; // NULL triggers exception + } + + //page->addView(page->getDocument()->getObject(FeatName.c_str())); + + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + +// double getPageWidth() const; +PyObject* DrawPagePy::getPageWidth(PyObject *args) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + +// double getPageHeight() const; +PyObject* DrawPagePy::getPageHeight(PyObject *args) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + +// const char* getPageOrientation() const; +PyObject* DrawPagePy::getPageOrientation(PyObject *args) +{ + PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented"); + return 0; +} + +PyObject *DrawPagePy::getCustomAttributes(const char* attr) const +{ + return 0; +} + +int DrawPagePy::setCustomAttributes(const char* attr, PyObject *obj) +{ + return 0; +} diff --git a/src/Mod/TechDraw/App/DrawParametricTemplate.cpp b/src/Mod/TechDraw/App/DrawParametricTemplate.cpp new file mode 100644 index 0000000000..4dff0f1ecb --- /dev/null +++ b/src/Mod/TechDraw/App/DrawParametricTemplate.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "Geometry.h" + +#include +#include + +#include "DrawParametricTemplate.h" +#include "DrawParametricTemplatePy.h" + +using namespace TechDraw; +using namespace std; + +PROPERTY_SOURCE(TechDraw::DrawParametricTemplate, TechDraw::DrawTemplate) + +DrawParametricTemplate::DrawParametricTemplate(void) +{ + static const char *group = "Page"; + ADD_PROPERTY_TYPE(Template ,(""),group, (App::PropertyType) App::Prop_None,"Template script"); +} + +DrawParametricTemplate::~DrawParametricTemplate() +{ +} + + +PyObject *DrawParametricTemplate::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawParametricTemplatePy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +unsigned int DrawParametricTemplate::getMemSize(void) const +{ + return 0; +} + +double DrawParametricTemplate::getWidth() const { + throw Base::Exception("Need to Implement"); +} + + +double DrawParametricTemplate::getHeight() const { + throw Base::Exception("Need to Implement"); +} + + +short DrawParametricTemplate::mustExecute() const +{ + return App::DocumentObject::mustExecute(); +} + +/// get called by the container when a Property was changed +void DrawParametricTemplate::onChanged(const App::Property* prop) +{ + App::DocumentObject::onChanged(prop); +} + +App::DocumentObjectExecReturn *DrawParametricTemplate::execute(void) +{ + std::string temp = Template.getValue(); + if (!temp.empty()) { + Base::FileInfo tfi(temp); + if (!tfi.isReadable()) { + // if there is a old absolute template file set use a redirect + return App::DocumentObject::StdReturn; + } + try { + Base::Interpreter().runFile(temp.c_str(), true); + } + catch(const Base::Exception& e) { + PyErr_SetString(PyExc_ImportError, e.what()); + return App::DocumentObject::StdReturn; + } + } + + return App::DocumentObject::StdReturn; +} + +int DrawParametricTemplate::drawLine(double x1, double y1, double x2, double y2) +{ + DrawingGeometry::Generic *line = new DrawingGeometry::Generic(); + + line->points.push_back(Base::Vector2D(x1, y1)); + line->points.push_back(Base::Vector2D(x2, y2)); + + geom.push_back(line); // Push onto geometry stack + return geom.size() -1; +} + +int DrawParametricTemplate::clearGeometry() +{ + for(std::vector::iterator it = geom.begin(); it != geom.end(); ++it) { + delete *it; + *it = 0; + } + geom.clear(); + return 0; +} + +// Python Template feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawParametricTemplatePython, TechDraw::DrawParametricTemplate) +template<> const char* TechDraw::DrawParametricTemplatePython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderPython"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawParametricTemplate.h b/src/Mod/TechDraw/App/DrawParametricTemplate.h new file mode 100644 index 0000000000..d889873074 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawParametricTemplate.h @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_DrawParametricTemplate_h_ +#define _TECHDRAW_DrawParametricTemplate_h_ + +#include +#include + +#include "DrawTemplate.h" + +namespace TechDrawGeometry +{ + class BaseGeom; +} + +namespace TechDraw +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawParametricTemplate: public TechDraw::DrawTemplate +{ + PROPERTY_HEADER(TechDraw::DrawParametricTemplate); + +public: + DrawParametricTemplate(); /// Constructor + ~DrawParametricTemplate(); + + App::PropertyFile Template; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + + short mustExecute() const; + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderTemplate"; + } + + // from base class + virtual PyObject *getPyObject(void); + virtual unsigned int getMemSize(void) const; + +public: + std::vector getGeometry() { return geom; } + int clearGeometry(); + + // Template Drawing Methods + int drawLine(double x1, double y1, double x2, double y2); + + double getHeight() const; + double getWidth() const; + +protected: + void onChanged(const App::Property* prop); + +protected: + std::vector geom; + +private: + static const char* OrientationEnums[]; +}; + +typedef App::FeaturePythonT DrawParametricTemplatePython; + +} //namespace TechDraw + + + +#endif //_TECHDRAW_DrawParametricTemplate_h_ diff --git a/src/Mod/TechDraw/App/DrawParametricTemplatePy.xml b/src/Mod/TechDraw/App/DrawParametricTemplatePy.xml new file mode 100644 index 0000000000..19ada4acaa --- /dev/null +++ b/src/Mod/TechDraw/App/DrawParametricTemplatePy.xml @@ -0,0 +1,28 @@ + + + + + + Feature for creating and manipulating Drawing Templates + + + + Draw a line + + + + + Number of geometry in template + + + + + diff --git a/src/Mod/TechDraw/App/DrawParametricTemplatePyImp.cpp b/src/Mod/TechDraw/App/DrawParametricTemplatePyImp.cpp new file mode 100644 index 0000000000..7cc068c583 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawParametricTemplatePyImp.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 +#endif + +#include "Mod/Drawing/App/DrawParametricTemplate.h" + +// inclusion of the generated files (generated out of DrawParametricTemplateSFPy.xml) +#include "DrawParametricTemplatePy.h" +#include "DrawParametricTemplatePy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawParametricTemplatePy::representation(void) const +{ + return ""; +} + +PyObject *DrawParametricTemplatePy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawParametricTemplatePy::setCustomAttributes(const char* attr, PyObject* obj) +{ + // search in PropertyList + App::Property *prop = getDrawParametricTemplatePtr()->getPropertyByName(attr); + if (prop) { + // Read-only attributes must not be set over its Python interface + short Type = getDrawParametricTemplatePtr()->getPropertyType(prop); + if (Type & App::Prop_ReadOnly) { + std::stringstream s; + s << "Object attribute '" << attr << "' is read-only"; + throw Py::AttributeError(s.str()); + } + + prop->setPyObject(obj); + return 1; + } + + return 0; +} + + +PyObject* DrawParametricTemplatePy::drawLine(PyObject *args) +{ + PyObject *pcObj; + double x1, y1; + double x2, y2; + + if (!PyArg_ParseTuple(args, "dddd", &x1, &y1, &x2, &y2)) + return 0; + + getDrawParametricTemplatePtr()->drawLine(x1,y1,x2,y2); + + Py_Return; + +} + +Py::Int DrawParametricTemplatePy::getGeometryCount(void) const +{ + int size = getDrawParametricTemplatePtr()->getGeometry().size(); + return Py::Int(size); +} diff --git a/src/Mod/TechDraw/App/DrawProjGroup.cpp b/src/Mod/TechDraw/App/DrawProjGroup.cpp new file mode 100644 index 0000000000..585b055e1f --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjGroup.cpp @@ -0,0 +1,613 @@ +/*************************************************************************** + * Copyright (c) 2013-2014 Luke Parry * + * Copyright (c) 2014 Joe Dowsett * + * * + * 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 +#endif + +#include +#include + +#include +#include +#include + +#include + +#include +#include "DrawPage.h" +#include "DrawProjGroup.h" + +using namespace TechDraw; + +const char* DrawProjGroup::ProjectionTypeEnums[] = {"Document", + "First Angle", + "Third Angle", + NULL}; + +PROPERTY_SOURCE(TechDraw::DrawProjGroup, TechDraw::DrawViewCollection) + +DrawProjGroup::DrawProjGroup(void) +{ + static const char *group = "Drawing view"; + + ADD_PROPERTY_TYPE(Anchor, (0), group, App::Prop_None, "The root view to align projections with"); + + ProjectionType.setEnums(ProjectionTypeEnums); + ADD_PROPERTY(ProjectionType, ((long)0)); + + ADD_PROPERTY_TYPE(spacingX, (15), group, App::Prop_None, "Horizontal spacing between views"); + ADD_PROPERTY_TYPE(spacingY, (15), group, App::Prop_None, "Vertical spacing between views"); + + ADD_PROPERTY(viewOrientationMatrix, (Base::Matrix4D())); +} + +DrawProjGroup::~DrawProjGroup() +{ +} + +short DrawProjGroup::mustExecute() const +{ + if(Views.isTouched() || + Source.isTouched()) { + return 1; + } + + if (ProjectionType.isTouched()) + return 1; + return TechDraw::DrawViewCollection::mustExecute(); +} + +Base::BoundBox3d DrawProjGroup::getBoundingBox() const +{ + Base::BoundBox3d bbox; + + std::vector views = Views.getValues(); + TechDraw::DrawProjGroupItem *anchorView = dynamic_cast(Anchor.getValue()); + for (std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawViewPart::getClassTypeId())) { + DrawViewPart *part = static_cast(*it); + Base::BoundBox3d bb = part->getBoundingBox(); + + bb.ScaleX(1. / part->Scale.getValue()); + bb.ScaleY(1. / part->Scale.getValue()); + + // X and Y of dependant views are relative to the anchorView + if (part != anchorView) { + bb.MoveX(part->X.getValue()); + bb.MoveY(part->Y.getValue()); + } + + bbox.Add(bb); + } + } + // This /should/ leave the centre of the bounding box at (0,0) except when + // we're in the process of updating the anchor view's position (eg called + // by moveToCentre()) + if (anchorView) { //TODO: It looks like we might be getting called before an anchor view is set - weird... + bbox.MoveX(anchorView->X.getValue()); + bbox.MoveY(anchorView->Y.getValue()); + } + return bbox; +} + +TechDraw::DrawPage * DrawProjGroup::getPage(void) const +{ + //TODO: DrawView already has DrawPage* findParentPage() + return findParentPage(); + //TechDraw::DrawPage *ret = NULL; + + //std::vector parent = getInList(); + //for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + // if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) { + // ret = static_cast(*it); + // } + //} + + //return ret; +} + +// Function provided by Joe Dowsett, 2014 +double DrawProjGroup::calculateAutomaticScale() const +{ + TechDraw::DrawPage *page = getPage(); + + if (page == NULL) + throw Base::Exception("No page is assigned to this feature"); + + if(!page->hasValidTemplate()) + throw Base::Exception("Page template isn't valid"); + + DrawProjGroupItem *viewPtrs[10]; + + arrangeViewPointers(viewPtrs); + double width, height; + minimumBbViews(viewPtrs, width, height); + + // C++ Standard says casting bool to int gives 0 or 1 + int numVertSpaces = (viewPtrs[0] || viewPtrs[3] || viewPtrs[7]) + + (viewPtrs[2] || viewPtrs[5] || viewPtrs[9]) + + (viewPtrs[6] != NULL); + int numHorizSpaces = (viewPtrs[0] || viewPtrs[1] || viewPtrs[2]) + + (viewPtrs[7] || viewPtrs[8] || viewPtrs[9]); + + double availableX = page->getPageWidth() - spacingX.getValue() * (numVertSpaces + 1); + double availableY = page->getPageHeight() - spacingY.getValue() * (numHorizSpaces + 1); + + double scale_x = availableX / width; + double scale_y = availableY / height; + + float working_scale = std::min(scale_x, scale_y); + + //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239... + //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50 + + float exponent = std::floor(std::log10(working_scale)); //if working_scale = a * 10^b, what is b? + working_scale *= std::pow(10, -exponent); //now find what 'a' is. + + float valid_scales[2][8] = {{1.0, 1.25, 2.0, 2.5, 3.75, 5.0, 7.5, 10.0}, //equate to 1:10, 1:8, 1:5, 1:4, 3:8, 1:2, 3:4, 1:1 + {1.0, 1.5 , 2.0, 3.0, 4.0 , 5.0, 8.0, 10.0}}; //equate to 1:1, 3:2, 2:1, 3:1, 4:1, 5:1, 8:1, 10:1 + + int i = 7; + while (valid_scales[(exponent >= 0)][i] > working_scale) //choose closest value smaller than 'a' from list. + i -= 1; //choosing top list if exponent -ve, bottom list for +ve exponent + + //now have the appropriate scale, reapply the *10^b + return valid_scales[(exponent >= 0)][i] * pow(10, exponent); +} + +void DrawProjGroup::minimumBbViews(DrawProjGroupItem *viewPtrs[10], + double &width, double &height) const +{ + // Get bounding boxes in object scale + Base::BoundBox3d bboxes[10]; + makeViewBbs(viewPtrs, bboxes, false); + + double col0w = std::max(std::max(bboxes[0].LengthX(), bboxes[3].LengthX()), bboxes[7].LengthX()), + col1w = std::max(std::max(bboxes[1].LengthX(), bboxes[4].LengthX()), bboxes[8].LengthX()), + col2w = std::max(std::max(bboxes[2].LengthX(), bboxes[5].LengthX()), bboxes[9].LengthX()), + col3w = bboxes[6].LengthX(), + row0h = std::max(std::max(bboxes[0].LengthY(), bboxes[1].LengthY()), bboxes[2].LengthY()), + row1h = std::max(std::max(bboxes[3].LengthY(), bboxes[4].LengthY()), + std::max(bboxes[5].LengthY(), bboxes[6].LengthY())), + row2h = std::max(std::max(bboxes[7].LengthY(), bboxes[8].LengthY()), bboxes[9].LengthY()); + + width = col0w + col1w + col2w + col3w; + height = row0h + row1h + row2h; +} + +void DrawProjGroup::onChanged(const App::Property* prop) +{ + //TODO: For some reason, when the projection type is changed, the isometric views show change appropriately, but the orthographic ones dont... Or vice-versa. + if ( prop == &ProjectionType || + prop == &ScaleType || + prop == &viewOrientationMatrix || + ((prop == &Scale) && !Scale.StatusBits.test(5)) ) { + if (!isRestoring()) { + execute(); + } + } + TechDraw::DrawViewCollection::onChanged(prop); +} + +void DrawProjGroup::moveToCentre(void) +{ + // Update the anchor view's X and Y to keep the bounding box centred on the origin + Base::BoundBox3d tempbbox = getBoundingBox(); + DrawProjGroupItem *anchorView = dynamic_cast(Anchor.getValue()); + if (anchorView) { + anchorView->X.setValue((tempbbox.MinX + tempbbox.MaxX) / -2.0); + anchorView->Y.setValue((tempbbox.MinY + tempbbox.MaxY) / -2.0); + } +} + +App::DocumentObject * DrawProjGroup::getProjObj(const char *viewProjType) const +{ + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + + DrawView *view = dynamic_cast(*it); + if(view->getTypeId() == DrawProjGroupItem::getClassTypeId()) { + DrawProjGroupItem *projPtr = dynamic_cast(*it); + + if( strcmp(viewProjType, projPtr->Type.getValueAsString()) == 0 ) + return *it; + } + } + + return 0; +} + +bool DrawProjGroup::hasProjection(const char *viewProjType) const +{ + const std::vector &views = Views.getValues(); + + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + + TechDraw::DrawView *view = dynamic_cast(*it); + if(view->getTypeId() == TechDraw::DrawProjGroupItem::getClassTypeId()) { + TechDraw::DrawProjGroupItem *projPtr = dynamic_cast(*it); + + if( strcmp(viewProjType, projPtr->Type.getValueAsString()) == 0 ) { + return true; + } + } + } + return false; +} + +bool DrawProjGroup::checkViewProjType(const char *in) +{ + if ( strcmp(in, "Front") == 0 || + strcmp(in, "Left") == 0 || + strcmp(in, "Right") == 0 || + strcmp(in, "Top") == 0 || + strcmp(in, "Bottom") == 0 || + strcmp(in, "Rear") == 0 || + strcmp(in, "FrontTopLeft") == 0 || + strcmp(in, "FrontTopRight") == 0 || + strcmp(in, "FrontBottomLeft") == 0 || + strcmp(in, "FrontBottomRight") == 0) { + return true; + } + return false; +} + +App::DocumentObject * DrawProjGroup::addProjection(const char *viewProjType) +{ + DrawProjGroupItem *view = NULL; + + if ( checkViewProjType(viewProjType) && !hasProjection(viewProjType) ) { + std::string FeatName = getDocument()->getUniqueObjectName("ProjGroup"); + App::DocumentObject *docObj = getDocument()->addObject("TechDraw::DrawProjGroupItem", + FeatName.c_str()); + + view = dynamic_cast( docObj ); + view->Source.setValue( Source.getValue() ); + view->ScaleType.setValue( ScaleType.getValue() ); + view->Scale.setValue( Scale.getValue() ); + view->Type.setValue( viewProjType ); + view->Label.setValue( viewProjType ); + setViewOrientation( view, viewProjType ); + + addView(view); //from DrawViewCollection + moveToCentre(); + } + + return view; +} + +void DrawProjGroup::setViewOrientation(DrawProjGroupItem *v, const char *projType) const +{ + Base::Vector3d dir, xDir; + + // Traditional orthographic + if(strcmp(projType, "Front") == 0) { + dir.Set(0, 1, 0); + xDir.Set(1, 0, 0); + + } else if(strcmp(projType, "Rear") == 0) { + dir.Set(0, -1, 0); + xDir.Set(-1, 0, 0); + + } else if(strcmp(projType, "Right") == 0) { + dir.Set(1, 0, 0); + xDir.Set(0, -1, 0); + + } else if(strcmp(projType, "Left") == 0) { + dir.Set(-1, 0, 0); + xDir.Set(0, 1, 0); + + } else if(strcmp(projType, "Top") == 0) { + dir.Set(0, 0, 1); + xDir.Set(1, 0, 0); + + } else if(strcmp(projType, "Bottom") == 0) { + dir.Set(0, 0, -1); + xDir.Set(1, 0, 0); + + // Isometric + } else if(strcmp(projType, "FrontTopLeft") == 0) { + dir.Set(-1/sqrt(3), 1/sqrt(3), 1/sqrt(3)); + xDir.Set(sqrt(2)/2.0, sqrt(2.0)/2.0, 0); + + } else if(strcmp(projType, "FrontTopRight") == 0) { + dir.Set(1/sqrt(3), 1/sqrt(3), 1/sqrt(3)); + xDir.Set(sqrt(2)/2.0, -sqrt(2.0)/2.0, 0); + + } else if(strcmp(projType, "FrontBottomRight") == 0) { + dir.Set(1/sqrt(3), 1/sqrt(3), -1/sqrt(3)); + xDir.Set(sqrt(2)/2.0, -sqrt(2.0)/2.0, 0); + + } else if(strcmp(projType, "FrontBottomLeft") == 0) { + dir.Set(-1/sqrt(3), 1/sqrt(3), -1/sqrt(3)); + xDir.Set(sqrt(2)/2.0, sqrt(2.0)/2.0, 0); + + } else { + throw Base::Exception("Unknown view type in DrawProjGroup::setViewOrientation()"); + } + + dir = viewOrientationMatrix.getValue() * dir; + xDir = viewOrientationMatrix.getValue() * xDir; + + v->Direction.setValue(dir); + v->XAxisDirection.setValue(xDir); +} + +int DrawProjGroup::removeProjection(const char *viewProjType) +{ + if ( checkViewProjType(viewProjType) ) { + if(!hasProjection(viewProjType)) { + throw Base::Exception("The projection doesn't exist in the group"); + } + + // Iterate through the child views and find the projection type + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + + TechDraw::DrawView *view = dynamic_cast(*it); + if(view->getTypeId() == TechDraw::DrawProjGroupItem::getClassTypeId()) { + TechDraw::DrawProjGroupItem *projPtr = dynamic_cast(*it); + + if ( strcmp(viewProjType, projPtr->Type.getValueAsString()) == 0 ) { + // Remove from the document + getDocument()->remObject((*it)->getNameInDocument()); + moveToCentre(); + return views.size(); + } + } + } + } + + return -1; +} + +void DrawProjGroup::arrangeViewPointers(DrawProjGroupItem *viewPtrs[10]) const +{ + for (int i=0; i<10; ++i) { + viewPtrs[i] = NULL; + } + + DrawProjGroupItem *anchorView = dynamic_cast(Anchor.getValue()); + + if (!anchorView) { //TODO: Consider not requiring an anchor view, or allowing ones other than "Front" + throw Base::Exception("No anchor view set in DrawProjGroup::arrangeViewPointers()"); + } + + // Determine layout - should be either "First Angle" or "Third Angle" + const char* projType; + if (ProjectionType.isValue("Document")) { + projType = findParentPage()->ProjectionType.getValueAsString(); + } else { + projType = ProjectionType.getValueAsString(); + } + + // Iterate through views and populate viewPtrs + DrawProjGroupItem* oView; + std::vector views = Views.getValues(); + if ( strcmp(projType, "Third Angle") == 0 || + strcmp(projType, "First Angle") == 0 ) { + // Third Angle: FTL T FTRight + // L F Right Rear + // FBL B FBRight + // + // First Angle: FBRight B FBL + // Right F L Rear + // FTRight T FTL + bool thirdAngle = (strcmp(projType, "Third Angle") == 0); + for (std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawProjGroupItem::getClassTypeId())) { + oView = dynamic_cast(*it); + + const char *viewTypeCStr = oView->Type.getValueAsString(); + if (strcmp(viewTypeCStr, "Front") == 0) { + viewPtrs[thirdAngle ? 4 : 4] = oView; + } else if (strcmp(viewTypeCStr, "Left") == 0) { + viewPtrs[thirdAngle ? 3 : 5] = oView; + } else if (strcmp(viewTypeCStr, "Right") == 0) { + viewPtrs[thirdAngle ? 5 : 3] = oView; + } else if (strcmp(viewTypeCStr, "Top") == 0) { + viewPtrs[thirdAngle ? 1 : 8] = oView; + } else if (strcmp(viewTypeCStr, "Bottom") == 0) { + viewPtrs[thirdAngle ? 8 : 1] = oView; + } else if (strcmp(viewTypeCStr, "Rear") == 0) { + viewPtrs[thirdAngle ? 6 : 6] = oView; + } else if (strcmp(viewTypeCStr, "FrontTopLeft") == 0) { + viewPtrs[thirdAngle ? 0 : 9] = oView; + } else if (strcmp(viewTypeCStr, "FrontTopRight") == 0) { + viewPtrs[thirdAngle ? 2 : 7] = oView; + } else if (strcmp(viewTypeCStr, "FrontBottomLeft") == 0) { + viewPtrs[thirdAngle ? 7 : 2] = oView; + } else if (strcmp(viewTypeCStr, "FrontBottomRight") == 0) { + viewPtrs[thirdAngle ? 9 : 0] = oView; + } else { + throw Base::Exception("Unknown view type in DrawProjGroup::arrangeViewPointers()"); + } + } + } + } else { + throw Base::Exception("Unknown view type in DrawProjGroup::arrangeViewPointers()"); + } +} + +void DrawProjGroup::makeViewBbs(DrawProjGroupItem *viewPtrs[10], + Base::BoundBox3d bboxes[10], + bool documentScale) const +{ + for (int i = 0; i < 10; ++i) + if (viewPtrs[i]) { + bboxes[i] = viewPtrs[i]->getBoundingBox(); + if (!documentScale) { + double scale = 1.0 / viewPtrs[i]->Scale.getValue(); + bboxes[i].ScaleX(scale); + bboxes[i].ScaleY(scale); + bboxes[i].ScaleZ(scale); + } + } else { + // BoundBox3d defaults to length=(FLOAT_MAX + -FLOAT_MAX) + bboxes[i].ScaleX(0); + bboxes[i].ScaleY(0); + bboxes[i].ScaleZ(0); + } +} + +bool DrawProjGroup::distributeProjections() +{ + DrawProjGroupItem *viewPtrs[10]; + + arrangeViewPointers(viewPtrs); + + // TODO: Work on not requiring the front view... + if (!viewPtrs[4]) { + return false; + } + + // Calculate bounding boxes for each displayed view + Base::BoundBox3d bboxes[10]; + makeViewBbs(viewPtrs, bboxes); + + // Now that things are setup, do the spacing + double xSpacing = spacingX.getValue(); //in mm + double ySpacing = spacingY.getValue(); //in mm + + if (viewPtrs[0]) { + double displace = std::max(bboxes[0].LengthX() + bboxes[4].LengthX(), + bboxes[0].LengthY() + bboxes[4].LengthY()); + viewPtrs[0]->X.setValue(displace / -2.0 - xSpacing); + viewPtrs[0]->Y.setValue(displace / 2.0 + ySpacing); + } + if (viewPtrs[1]) { + viewPtrs[1]->Y.setValue((bboxes[1].LengthY() + bboxes[4].LengthY()) / 2.0 + ySpacing); + } + if (viewPtrs[2]) { + double displace = std::max(bboxes[2].LengthX() + bboxes[4].LengthX(), + bboxes[2].LengthY() + bboxes[4].LengthY()); + viewPtrs[2]->X.setValue(displace / 2.0 + xSpacing); + viewPtrs[2]->Y.setValue(displace / 2.0 + ySpacing); + } + if (viewPtrs[3]) { + viewPtrs[3]->X.setValue((bboxes[3].LengthX() + bboxes[4].LengthX()) / -2.0 - xSpacing); + } + if (viewPtrs[4]) { // TODO: Move this check above, and figure out a sane bounding box based on other existing views + } + if (viewPtrs[5]) { + viewPtrs[5]->X.setValue((bboxes[5].LengthX() + bboxes[4].LengthX()) / 2.0 + xSpacing); + } + if (viewPtrs[6]) { + if (viewPtrs[5]) + viewPtrs[6]->X.setValue((bboxes[6].LengthX() + bboxes[4].LengthX()) / 2.0 + bboxes[5].LengthX() + 2 * xSpacing); + else + viewPtrs[6]->X.setValue((bboxes[6].LengthX() + bboxes[4].LengthX()) / 2.0 + xSpacing); + } + if (viewPtrs[7]) { + double displace = std::max(bboxes[7].LengthX() + bboxes[4].LengthX(), + bboxes[7].LengthY() + bboxes[4].LengthY()); + viewPtrs[7]->X.setValue(displace / -2.0 - xSpacing); + viewPtrs[7]->Y.setValue(displace / -2.0 - ySpacing); + } + if (viewPtrs[8]) { + viewPtrs[8]->Y.setValue((bboxes[8].LengthY() + bboxes[4].LengthY()) / -2.0 - ySpacing); + } + if (viewPtrs[9]) { + double displace = std::max(bboxes[9].LengthX() + bboxes[4].LengthX(), + bboxes[9].LengthY() + bboxes[4].LengthY()); + viewPtrs[9]->X.setValue(displace / 2.0 + xSpacing); + viewPtrs[9]->Y.setValue(displace / -2.0 - ySpacing); + } + + return true; +} + +//TODO: Turn this into a command so it can be issued from python +void DrawProjGroup::setFrontViewOrientation(const Base::Matrix4D &newMat) +{ + viewOrientationMatrix.setValue(newMat); + + DrawProjGroupItem *view; + std::vector views = Views.getValues(); + for (std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawProjGroupItem::getClassTypeId())) { + view = dynamic_cast(*it); + setViewOrientation(view, view->Type.getValueAsString()); + view->touch(); + } + } +} + +App::DocumentObjectExecReturn *DrawProjGroup::execute(void) +{ + if (ScaleType.isValue("Automatic")) { + + //Recalculate scale + double autoScale = calculateAutomaticScale(); + + if(std::abs(Scale.getValue() - autoScale) > FLT_EPSILON) { + // Set this Scale + Scale.setValue(autoScale); + + //Rebuild the view + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + App::DocumentObject *docObj = *it; + if(docObj->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { + DrawView *view = dynamic_cast(*it); + + //Set scale factor of each view + view->ScaleType.setValue("Custom"); + view->Scale.setValue(autoScale); + view->Scale.touch(); + view->Scale.StatusBits.set(2); + view->touch(); + } + } + } + } + + // recalculate positions for children + if (Views.getSize()) { + distributeProjections(); + } + //touch(); + + return DrawViewCollection::execute(); +} + +App::Enumeration DrawProjGroup::usedProjectionType(void) +{ + //TODO: Would've been nice to have an Enumeration(const PropertyEnumeration &) constructor + App::Enumeration ret(ProjectionTypeEnums, ProjectionType.getValueAsString()); + if (ret.isValue("Document")) { + TechDraw::DrawPage * page = getPage(); + if ( page != NULL ) { + ret.setValue(page->ProjectionType.getValueAsString()); + } + } + return ret; +} + +void DrawProjGroup::onDocumentRestored() +{ + execute(); +} diff --git a/src/Mod/TechDraw/App/DrawProjGroup.h b/src/Mod/TechDraw/App/DrawProjGroup.h new file mode 100644 index 0000000000..6785c10058 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjGroup.h @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_FEATUREVIEWGROUP_H_ +#define _TECHDRAW_FEATUREVIEWGROUP_H_ + +#include +#include +#include + +#include +#include +#include "DrawViewCollection.h" +#include "DrawProjGroupItem.h" + +namespace TechDraw +{ + +/** + * Class super-container for managing a collection of DrawProjGroupItem + * Page Features + */ +class DrawingExport DrawProjGroup : public TechDraw::DrawViewCollection +{ + PROPERTY_HEADER(TechDraw::DrawProjGroup); + +public: + /// Constructor + DrawProjGroup(); + ~DrawProjGroup(); + + App::PropertyEnumeration ProjectionType; + + /// Default horizontal spacing between adjacent views on Drawing, in mm + App::PropertyFloat spacingX; + /// Default vertical spacing between adjacent views on Drawing, in mm + App::PropertyFloat spacingY; + + /// Transforms Direction and XAxisDirection vectors in child views + App::PropertyMatrix viewOrientationMatrix; + + App::PropertyLink Anchor; /// Anchor Element to align views to + + Base::BoundBox3d getBoundingBox() const; + double calculateAutomaticScale() const; + + /// Check if container has a view of a specific type + bool hasProjection(const char *viewProjType) const; + + App::DocumentObject * getProjObj(const char *viewProjType) const; + + //! Adds a projection to the group + /*! + * \return pointer to the new view + */ + App::DocumentObject * addProjection(const char *viewProjType); + + //! Removes a projection from the group + /*! + * \return number of projections remaining + */ + int removeProjection(const char *viewProjType); + + /// Automatically position child views + bool distributeProjections(void); + + /// Changes child views' coordinate space + /*! + * Used to set the Direction and XAxisDirection in child views + */ + void setFrontViewOrientation(const Base::Matrix4D &newMat); + + short mustExecute() const; + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual void onDocumentRestored(); + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderProjGroup"; + } + + /// Determines either "First Angle" or "Third Angle". + App::Enumeration usedProjectionType(void); + + /// Allowed projection types - either Document, First Angle or Third Angle + static const char* ProjectionTypeEnums[]; + +protected: + void onChanged(const App::Property* prop); + + //! Moves anchor view to keep our bounding box centre on the origin + void moveToCentre(); + + /// Annoying helper - keep in sync with DrawProjGroupItem::TypeEnums + /*! + * \TODO See note regarding App::PropertyEnumeration on my wiki page http://freecadweb.org/wiki/index.php?title=User:Ian.rees + * \return true iff 'in' is a valid name for an orthographic/isometric view + */ + bool checkViewProjType(const char *in); + + /// Sets Direction and XAxisDirection in v + /*! + * Applies viewOrientationMatrix to appropriate unit vectors depending on projType + */ + void setViewOrientation(DrawProjGroupItem *v, const char *projType) const; + + /// Populates an array of DrawProjGroupItem*s arranged for drawing + /*! + * Setup array of pointers to the views that we're displaying, + * assuming front is in centre (index 4): + *
+     * [0]  [1]  [2]
+     * [3]  [4]  [5]  [6]
+     * [7]  [8]  [9]
+     *
+     * Third Angle:  FTL  T  FTRight
+     *                L   F   Right   Rear
+     *               FBL  B  FBRight
+     *
+     * First Angle:  FBRight  B  FBL
+     *                Right   F   L  Rear
+     *               FTRight  T  FTL
+     * 
+ */ + void arrangeViewPointers(DrawProjGroupItem *viewPtrs[10]) const; + + /// Populates array of 10 BoundBox3d's given DrawProjGroupItem *s + /*! + * If documentScale is set, then returned bounding boxes are scaled as in + * the Drawing. Otherwise, the dimensions are as in object space. + */ + void makeViewBbs(DrawProjGroupItem *viewPtrs[10], + Base::BoundBox3d bboxes[10], + bool documentScale = true) const; + + /// Helper for calculateAutomaticScale + /*! + * Returns a width and height in object-space scale, for the enabled views + * without accounting for their actual X and Y positions or borders. + */ + void minimumBbViews(DrawProjGroupItem *viewPtrs[10], + double &width, double &height) const; + + /// Returns pointer to our page, or NULL if it couldn't be located + TechDraw::DrawPage * getPage(void) const; +}; + +} //namespace TechDraw + +#endif // _TECHDRAW_FEATUREVIEWGROUP_H_ diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.cpp b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp new file mode 100644 index 0000000000..2e472e10ff --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 +#endif + +#include +#include +#include + +#include "DrawProjGroupItem.h" + +using namespace TechDraw; + +const char* DrawProjGroupItem::TypeEnums[] = {"Front", + "Left", + "Right", + "Rear", + "Top", + "Bottom", + "FrontTopLeft", + "FrontTopRight", + "FrontBottomLeft", + "FrontBottomRight", + NULL}; + + +PROPERTY_SOURCE(TechDraw::DrawProjGroupItem, TechDraw::DrawViewPart) + +DrawProjGroupItem::DrawProjGroupItem(void) +{ + Type.setEnums(TypeEnums); + ADD_PROPERTY(Type, ((long)0)); + + // Set Hidden + Direction.StatusBits.set(3); + + // Set Hidden + XAxisDirection.StatusBits.set(3); + + // Scale and ScaleType are Readonly + Scale.StatusBits.set(2); + ScaleType.StatusBits.set(2); +} + +short DrawProjGroupItem::mustExecute() const +{ + if (Type.isTouched()) + return 1; + return TechDraw::DrawViewPart::mustExecute(); +} + +void DrawProjGroupItem::onChanged(const App::Property *prop) +{ + TechDraw::DrawViewPart::onChanged(prop); + + //TODO: Should we allow changes to the Type here? Seems that should be handled through DrawProjGroup + if (prop == &Type && Type.isTouched()) { + if (!isRestoring()) { + execute(); + } + } + +} + +DrawProjGroupItem::~DrawProjGroupItem() +{ +} + +void DrawProjGroupItem::onDocumentRestored() +{ + // Rebuild the view + execute(); +} + +/* +//TODO: Perhaps we don't need this anymore? +App::DocumentObjectExecReturn *DrawProjGroupItem::execute(void) +{ + if(Type.isTouched()) { + Type.purgeTouched(); + } + + return TechDraw::DrawViewPart::execute(); +}*/ + diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.h b/src/Mod/TechDraw/App/DrawProjGroupItem.h new file mode 100644 index 0000000000..f82472cabf --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawProjGroupItem_h_ +#define _DrawProjGroupItem_h_ + +#include +#include +#include +#include "DrawViewPart.h" + +namespace TechDraw +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawProjGroupItem : public TechDraw::DrawViewPart +{ + PROPERTY_HEADER(TechDraw::DrawProjGroupItem); + +public: + /// Constructor + DrawProjGroupItem(); + ~DrawProjGroupItem(); + + App::PropertyEnumeration Type; + + short mustExecute() const; + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual void onDocumentRestored(); +// virtual App::DocumentObjectExecReturn *execute(void); // TODO: Delete me too if we take out the implementation + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderProjGroupItem"; + } + +protected: + /// Called by the container when a Property was changed + void onChanged(const App::Property* prop); +private: + static const char* TypeEnums[]; +}; + +} //namespace TechDraw + +#endif diff --git a/src/Mod/TechDraw/App/DrawProjection.cpp b/src/Mod/TechDraw/App/DrawProjection.cpp new file mode 100644 index 0000000000..8a0834df61 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjection.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (c) 2009 Werner Mayer * + * * + * 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 +#endif + + +#include +#include +#include +#include +#include + +#include "DrawProjection.h" +#include "ProjectionAlgos.h" + +using namespace TechDraw; + + +PROPERTY_SOURCE(TechDraw::DrawProjection, Part::Feature) + + +DrawProjection::DrawProjection() +{ + static const char *group = "Projection"; + ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"Shape to project"); + ADD_PROPERTY_TYPE(Direction ,(Base::Vector3d(0.0,0.0,1.0)),group,App::Prop_None,"Projection direction"); + ADD_PROPERTY_TYPE(VCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(Rg1LineVCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(RgNLineVCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(OutLineVCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(IsoLineVCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(HCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(Rg1LineHCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(RgNLineHCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(OutLineHCompound ,(true),group,App::Prop_None,"Projection parameter"); + ADD_PROPERTY_TYPE(IsoLineHCompound ,(true),group,App::Prop_None,"Projection parameter"); +} + +DrawProjection::~DrawProjection() +{ +} + +App::DocumentObjectExecReturn *DrawProjection::execute(void) +{ + App::DocumentObject* link = Source.getValue(); + if (!link) + return new App::DocumentObjectExecReturn("No object linked"); + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a Part object"); + const TopoDS_Shape& shape = static_cast(link)->Shape.getShape()._Shape; + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape object is empty"); + + try { + const Base::Vector3d& dir = Direction.getValue(); + TechDraw::ProjectionAlgos alg(shape, dir); + + TopoDS_Compound comp; + BRep_Builder builder; + builder.MakeCompound(comp); + if (!alg.V.IsNull() && VCompound.getValue()) + builder.Add(comp, alg.V); + if (!alg.V1.IsNull() && Rg1LineVCompound.getValue()) + builder.Add(comp, alg.V1); + if (!alg.VN.IsNull() && RgNLineVCompound.getValue()) + builder.Add(comp, alg.VN); + if (!alg.VO.IsNull() && OutLineVCompound.getValue()) + builder.Add(comp, alg.VO); + if (!alg.VI.IsNull() && IsoLineVCompound.getValue()) + builder.Add(comp, alg.VI); + if (!alg.H.IsNull() && HCompound.getValue()) + builder.Add(comp, alg.H); + if (!alg.H1.IsNull() && Rg1LineHCompound.getValue()) + builder.Add(comp, alg.H1); + if (!alg.HN.IsNull() && RgNLineHCompound.getValue()) + builder.Add(comp, alg.HN); + if (!alg.HO.IsNull() && OutLineHCompound.getValue()) + builder.Add(comp, alg.HO); + if (!alg.HI.IsNull() && IsoLineHCompound.getValue()) + builder.Add(comp, alg.HI); + + Shape.setValue(comp); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} diff --git a/src/Mod/TechDraw/App/DrawProjection.h b/src/Mod/TechDraw/App/DrawProjection.h new file mode 100644 index 0000000000..7f0b8343bc --- /dev/null +++ b/src/Mod/TechDraw/App/DrawProjection.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (c) 2009 Werner Mayer * + * * + * 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 * + * * + ***************************************************************************/ + + +#ifndef TECHDRAW_FEATUREPROJECTION +#define TECHDRAW_FEATUREPROJECTION + + +#include +#include +#include +#include + + +namespace TechDraw +{ + + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawProjection : public Part::Feature +{ + PROPERTY_HEADER(TechDraw::DrawProjection); + +public: + /// Constructor + DrawProjection(); + virtual ~DrawProjection(); + + App::PropertyLink Source; + App::PropertyVector Direction; + App::PropertyBool VCompound; + App::PropertyBool Rg1LineVCompound; + App::PropertyBool RgNLineVCompound; + App::PropertyBool OutLineVCompound; + App::PropertyBool IsoLineVCompound; + App::PropertyBool HCompound; + App::PropertyBool Rg1LineHCompound; + App::PropertyBool RgNLineHCompound; + App::PropertyBool OutLineHCompound; + App::PropertyBool IsoLineHCompound; + + /** @name methods overide feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} +}; + +} //namespace TechDraw + + + +#endif // TECHDRAW_FEATUREPROJECTION diff --git a/src/Mod/TechDraw/App/DrawSVGTemplate.cpp b/src/Mod/TechDraw/App/DrawSVGTemplate.cpp new file mode 100644 index 0000000000..073cd77f1a --- /dev/null +++ b/src/Mod/TechDraw/App/DrawSVGTemplate.cpp @@ -0,0 +1,361 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * 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 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "DrawPage.h" +#include "DrawSVGTemplate.h" + +#include "DrawSVGTemplatePy.h" + +using namespace TechDraw; +using namespace std; + +PROPERTY_SOURCE(TechDraw::DrawSVGTemplate, TechDraw::DrawTemplate) + +DrawSVGTemplate::DrawSVGTemplate() +{ + static const char *group = "Drawing view"; + + //TODO: Do we need PageResult anymore? + // PageTemplate points to the template file in tmp/FreeCAD-AB-CD-EF-.../myTemplate.svg + // When restoring saved document, Template is redundant/incorrect - PageResult is the correct info. -wf- + ADD_PROPERTY_TYPE(PageResult, (0), group, App::Prop_Output, "Resulting SVG document of that page"); //really copy of original Template + //with EditableFields replaced? + ADD_PROPERTY_TYPE(Template, (""), group, App::Prop_Transient, "Template for the page"); + + // Width and Height properties shouldn't be set by the user + Height.StatusBits.set(2); // Read Only + Width.StatusBits.set(2); // Read Only + Orientation.StatusBits.set(2); // Read Only +} + +DrawSVGTemplate::~DrawSVGTemplate() +{ +} + +/* +std::string DrawSVGTemplate::getSvgIdForEditable(const std::string &editableName) +{ + if (editableSvgIds.count(editableName)) { + return editableSvgIds[editableName]; + } else { + return ""; + } +}*/ + +PyObject *DrawSVGTemplate::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawSVGTemplatePy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +unsigned int DrawSVGTemplate::getMemSize(void) const +{ + return 0; +} + +short DrawSVGTemplate::mustExecute() const +{ + return TechDraw::DrawTemplate::mustExecute(); +} + +void DrawSVGTemplate::onChanged(const App::Property* prop) +{ + bool updatePage = false; + + if (prop == &PageResult) { + if (isRestoring()) { + + //original template has been stored in fcstd file + Template.setValue(PageResult.getValue()); + } + } else if (prop == &Template) { + if (!isRestoring()) { + EditableTexts.setValues(getEditableTextsFromTemplate()); + updatePage = true; + } + } else if (prop == &EditableTexts) { + if (!isRestoring()) { + updatePage = true; + } + } + + if (updatePage) { + execute(); + + // Update the parent page if exists + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) { + TechDraw::DrawPage *page = static_cast(*it); + page->touch(); + } + } + } + + TechDraw::DrawTemplate::onChanged(prop); +} + +App::DocumentObjectExecReturn * DrawSVGTemplate::execute(void) +{ + std::string temp = Template.getValue(); + if (temp.empty()) + return App::DocumentObject::StdReturn; + + Base::FileInfo fi(temp); + if (!fi.isReadable()) { + // non-empty template value, but can't read file + // if there is a old absolute template file set use a redirect + fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName()); + // try the redirect + if (!fi.isReadable()) { + Base::Console().Log("DrawPage::execute() not able to open %s!\n",Template.getValue()); + std::string error = std::string("Cannot open file ") + Template.getValue(); + return new App::DocumentObjectExecReturn(error); + } + } + + if (std::string(PageResult.getValue()).empty()) + PageResult.setValue(fi.filePath().c_str()); + + // open Template file + string line; + ifstream file (fi.filePath().c_str()); + + // make a temp file for FileIncluded Property + string tempName = PageResult.getExchangeTempFile(); + ostringstream ofile; + string tempendl = "--endOfLine--"; + + while (!file.eof()) + { + getline(file,line); + // check if the marker in the template is found + if(line.find("") == string::npos) { + // if not - write through + ofile << line << tempendl; + } + + //double t0, t1,t2,t3; + float t0, t1,t2,t3; + if(line.find("" + blockDimensions = QRectF(t0, t1, t2 - t0, t3 - t1); + } + + } + file.close(); + + // checking for freecad editable texts + string outfragment(ofile.str()); + + std::map subs = EditableTexts.getValues(); + + if (subs.size() > 0) { + boost::regex e1 ("(.*?)"); + string::const_iterator begin, end; + begin = outfragment.begin(); + end = outfragment.end(); + boost::match_results what; + + // Find editable texts + while (boost::regex_search(begin, end, what, e1)) { + // if we have a replacement value for the text we've found + if (subs.count(what[1].str())) { + // change it to specified value + boost::regex e2 ("((.*?)()"); + outfragment = boost::regex_replace(outfragment, e2, "$1>" + subs[what[1].str()] + "$3"); + } + begin = what[0].second; + } + } + + + // restoring linebreaks and saving the file + boost::regex e3 ("--endOfLine--"); + string fmt = "\\n"; + outfragment = boost::regex_replace(outfragment, e3, fmt); + ofstream outfinal(tempName.c_str()); + outfinal << outfragment; + outfinal.close(); + + PageResult.setValue(tempName.c_str()); + + + // Calculate the dimensions of the page and store for retrieval + + QFile resultFile(QString::fromAscii(PageResult.getValue())); + if (!resultFile.exists()) { + throw Base::Exception("Couldn't load document from PageResult"); + } + + QDomDocument doc(QString::fromAscii("mydocument")); + + if (!doc.setContent(&resultFile)) { + resultFile.close(); + throw Base::Exception("Couldn't parse template SVG contents"); + } + + // Parse the document XML + QDomElement docElem = doc.documentElement(); + + // Obtain the size of the SVG document by reading the document attirbutes + Base::Quantity quantity; + + // Obtain the width + QString str = docElem.attribute(QString::fromAscii("width")); + quantity = Base::Quantity::parse(str); + quantity.setUnit(Base::Unit::Length); + + Width.setValue(quantity.getValue()); + + str = docElem.attribute(QString::fromAscii("height")); + quantity = Base::Quantity::parse(str); + quantity.setUnit(Base::Unit::Length); + + Height.setValue(quantity.getValue()); + + bool isLandscape = getWidth() / getHeight() >= 1.; + + Orientation.setValue(isLandscape ? 1 : 0); + + // Housekeeping close the file + resultFile.close(); + + touch(); + + return TechDraw::DrawTemplate::execute(); +} + +void DrawSVGTemplate::getBlockDimensions(double &x, double &y, double &width, double &height) const +{ + x = blockDimensions.left(); + y = blockDimensions.bottom(); + width = blockDimensions.width(); + height = blockDimensions.height(); +} + +double DrawSVGTemplate::getWidth() const +{ + return Width.getValue(); +} + +double DrawSVGTemplate::getHeight() const +{ + return Height.getValue(); +} + + +std::map DrawSVGTemplate::getEditableTextsFromTemplate() +{ + std::map eds; + + std::string temp = Template.getValue(); + if (!temp.empty()) { + Base::FileInfo tfi(temp); + if (!tfi.isReadable()) { + // if there is a old absolute template file set use a redirect + tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName()); + // try the redirect + if (!tfi.isReadable()) { + return eds; + } + } + string tline, tfrag; + ifstream tfile (tfi.filePath().c_str()); + while (!tfile.eof()) { + getline (tfile,tline); + tfrag += tline; + tfrag += "--endOfLine--"; + } + tfile.close(); + //this catches all the tags: + //keep tagRegex in sync with Gui/QGISVGTemplate.cpp + boost::regex tagRegex ("]*freecad:editable=[^>]*)>[^<]*]*>([^<]*)"); + boost::regex nameRegex("freecad:editable=\"(.*?)\""); + boost::regex valueRegex("(.*?)"); + + string::const_iterator tbegin, tend; + tbegin = tfrag.begin(); + tend = tfrag.end(); + boost::match_results tagMatch; + boost::match_results nameMatch; + boost::match_results valueMatch; + while (boost::regex_search(tbegin, tend, tagMatch, tagRegex)) { + if ( boost::regex_search(tagMatch[0].first, tagMatch[0].second, nameMatch, nameRegex) && + boost::regex_search(tagMatch[0].first, tagMatch[0].second, valueMatch, valueRegex)) { + //found valid name/value pair + string name = nameMatch[1]; + string value = valueMatch[1]; + if (eds.count(name) > 0) { + //TODO: Throw or [better] change key + qDebug() << "Got duplicate value for key "< const char* TechDraw::DrawSVGTemplatePython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderPython"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawSVGTemplate.h b/src/Mod/TechDraw/App/DrawSVGTemplate.h new file mode 100644 index 0000000000..a6f5723eca --- /dev/null +++ b/src/Mod/TechDraw/App/DrawSVGTemplate.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_DrawSVGTemplate_h_ +#define _TECHDRAW_DrawSVGTemplate_h_ + +#include +#include +#include +#include +#include +#include "DrawTemplate.h" + +namespace TechDraw +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawSVGTemplate: public TechDraw::DrawTemplate +{ + PROPERTY_HEADER(TechDraw::DrawSVGTemplate); + +public: + DrawSVGTemplate(); /// Constructor + ~DrawSVGTemplate(); + + App::PropertyFileIncluded PageResult; + App::PropertyFile Template; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + short mustExecute() const; + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderTemplate"; + } + + /// Returns the SVG ID for editable field with name editableName + /*! + * If editableName isn't known, returns an empty string + */ + // std::string getSvgIdForEditable(const std::string &editableName); + + // from base class + virtual PyObject *getPyObject(void); + virtual unsigned int getMemSize(void) const; + + double getWidth() const; + double getHeight() const; + void getBlockDimensions(double &x, double &y, double &width, double &height) const; + +protected: + void onChanged(const App::Property* prop); + + /// Returns map with + /*! + * Also populates editableSvgIds + */ + std::map getEditableTextsFromTemplate(); + + QRectF blockDimensions; +}; + +typedef App::FeaturePythonT DrawSVGTemplatePython; + +} //namespace TechDraw + +#endif //_TECHDRAW_DrawSVGTemplate_h_ diff --git a/src/Mod/TechDraw/App/DrawSVGTemplatePy.xml b/src/Mod/TechDraw/App/DrawSVGTemplatePy.xml new file mode 100644 index 0000000000..833aad92cf --- /dev/null +++ b/src/Mod/TechDraw/App/DrawSVGTemplatePy.xml @@ -0,0 +1,17 @@ + + + + + + Feature for creating and manipulating Drawing SVG Templates + + + diff --git a/src/Mod/TechDraw/App/DrawSVGTemplatePyImp.cpp b/src/Mod/TechDraw/App/DrawSVGTemplatePyImp.cpp new file mode 100644 index 0000000000..4cf19bff98 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawSVGTemplatePyImp.cpp @@ -0,0 +1,43 @@ + +#include "PreCompiled.h" + +#include "Mod/Drawing/App/DrawSVGTemplate.h" + +// inclusion of the generated files (generated out of DrawSVGTemplatePy.xml) +#include "DrawSVGTemplatePy.h" +#include "DrawSVGTemplatePy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawSVGTemplatePy::representation(void) const +{ + return std::string(""); +} + +PyObject *DrawSVGTemplatePy::getCustomAttributes(const char* attr) const +{ + return 0; +} + +int DrawSVGTemplatePy::setCustomAttributes(const char* attr, PyObject* obj) +{ + // search in PropertyList + App::Property *prop = getDrawSVGTemplatePtr()->getPropertyByName(attr); + if (prop) { + // Read-only attributes must not be set over its Python interface + short Type = getDrawSVGTemplatePtr()->getPropertyType(prop); + if (Type & App::Prop_ReadOnly) { + std::stringstream s; + s << "Object attribute '" << attr << "' is read-only"; + throw Py::AttributeError(s.str()); + } + + prop->setPyObject(obj); + return 1; + } + + return 0; +} + + diff --git a/src/Mod/TechDraw/App/DrawTemplate.cpp b/src/Mod/TechDraw/App/DrawTemplate.cpp new file mode 100644 index 0000000000..6b61b26bad --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTemplate.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include "DrawPage.h" +#include "DrawTemplate.h" +#include "DrawTemplatePy.h" + +using namespace TechDraw; +using namespace std; + +PROPERTY_SOURCE(TechDraw::DrawTemplate, App::DocumentObject) + + +const char* DrawTemplate::OrientationEnums[]= {"Portrait", + "Landscape", + NULL}; + + + +DrawTemplate::DrawTemplate(void) +{ + const char *group = "Page Properties"; + + Orientation.setEnums(OrientationEnums); + ADD_PROPERTY(Orientation, ((long)0)); + + // Physical Properties inherent to every template class + ADD_PROPERTY_TYPE(Width, (0), group, (App::PropertyType)(App::Prop_None), "Width of page"); + ADD_PROPERTY_TYPE(Height, (0), group, (App::PropertyType)(App::Prop_None), "Height of page"); + ADD_PROPERTY_TYPE(PaperSize, (""), group, (App::PropertyType)(App::Prop_None), "Paper Format"); + + ADD_PROPERTY_TYPE(EditableTexts, (), group, (App::PropertyType)(App::Prop_None), + "Editable strings in the template"); +} + +DrawTemplate::~DrawTemplate() +{ + Base::Console().Log("template destroyed"); +} + + +PyObject *DrawTemplate::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawTemplatePy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +unsigned int DrawTemplate::getMemSize(void) const +{ + return 0; +} + +double DrawTemplate::getWidth() const +{ + return Width.getValue(); +} + +double DrawTemplate::getHeight() const +{ + return Height.getValue(); +} + +short DrawTemplate::mustExecute() const +{ + return App::DocumentObject::mustExecute(); +} + +/// get called by the container when a Property was changed +void DrawTemplate::onChanged(const App::Property* prop) +{ + App::DocumentObject::onChanged(prop); +} + +App::DocumentObjectExecReturn *DrawTemplate::execute(void) +{ + DrawPage *page = 0; + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) { + page = dynamic_cast(*it); + } + } + + if(page) { + page->Template.touch(); + } + + return App::DocumentObject::execute(); +} + +void DrawTemplate::getBlockDimensions(double &x, double &y, double &width, double &height) const +{ + throw Base::Exception("implement in virtual function"); +} + +// Python Template feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawTemplatePython, TechDraw::DrawTemplate) +template<> const char* TechDraw::DrawTemplatePython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderPython"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} // namespace App diff --git a/src/Mod/TechDraw/App/DrawTemplate.h b/src/Mod/TechDraw/App/DrawTemplate.h new file mode 100644 index 0000000000..dbd8e8088f --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTemplate.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_DrawTemplate_h_ +#define _TECHDRAW_DrawTemplate_h_ + +#include + +#include +#include +#include +#include + +namespace TechDrawGeometry +{ + class BaseGeom; +} + +namespace TechDraw +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawTemplate: public App::DocumentObject +{ + PROPERTY_HEADER(TechDraw::DrawTemplate); + +public: + DrawTemplate(); /// Constructor + ~DrawTemplate(); + + // Page Physical Properties + App::PropertyLength Width; + App::PropertyLength Height; + App::PropertyEnumeration Orientation; + App::PropertyString PaperSize; + + App::PropertyMap EditableTexts; + +public: + + /// Returns template width in mm + virtual double getWidth() const; + /// Returns template height in mm + virtual double getHeight() const; + + virtual void getBlockDimensions(double &x, double &y, double &width, double &height) const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + + virtual short mustExecute() const; + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderTemplate"; + } + + // from base class + virtual PyObject *getPyObject(void); + virtual unsigned int getMemSize(void) const; + +protected: + void onChanged(const App::Property* prop); + +private: + static const char* OrientationEnums[]; + +}; + +typedef App::FeaturePythonT DrawTemplatePython; + +} //namespace TechDraw + + + +#endif //_TECHDRAW_DrawTemplate_h_ diff --git a/src/Mod/TechDraw/App/DrawTemplatePy.xml b/src/Mod/TechDraw/App/DrawTemplatePy.xml new file mode 100644 index 0000000000..1a73d9a043 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTemplatePy.xml @@ -0,0 +1,17 @@ + + + + + + Feature for creating and manipulating Drawing Templates + + + diff --git a/src/Mod/TechDraw/App/DrawTemplatePyImp.cpp b/src/Mod/TechDraw/App/DrawTemplatePyImp.cpp new file mode 100644 index 0000000000..723aff9933 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTemplatePyImp.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (c) 2014 Luke Parry * + * * + * 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 +#endif + +#include "Mod/Drawing/App/DrawTemplate.h" + +// inclusion of the generated files (generated out of DrawTemplateSFPy.xml) +#include "DrawTemplatePy.h" +#include "DrawTemplatePy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawTemplatePy::representation(void) const +{ + return ""; +} + +PyObject *DrawTemplatePy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawTemplatePy::setCustomAttributes(const char* attr, PyObject* obj) +{ + // search in PropertyList + App::Property *prop = getDrawTemplatePtr()->getPropertyByName(attr); + if (prop) { + // Read-only attributes must not be set over its Python interface + short Type = getDrawTemplatePtr()->getPropertyType(prop); + if (Type & App::Prop_ReadOnly) { + std::stringstream s; + s << "Object attribute '" << attr << "' is read-only"; + throw Py::AttributeError(s.str()); + } + + prop->setPyObject(obj); + return 1; + } + + return 0; +} diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp new file mode 100644 index 0000000000..19aae4d2a5 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -0,0 +1,100 @@ + +/*************************************************************************** + * Copyright (c) 2015 WandererFan * + * * + * 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 +#endif + +#include +#include +#include +#include + +#include "DrawUtil.h" + +namespace DrawUtil { + +//============================================================================== +// convenient utility functions for Drawing Module +//============================================================================== +extern "C" { +int DrawingExport getIndexFromName(std::string geomName) +{ + boost::regex re("\\d+$"); //one of more digits at end of string + boost::match_results what; + boost::match_flag_type flags = boost::match_default; + char* endChar; + std::string::const_iterator begin = geomName.begin(); + std::string::const_iterator end = geomName.end(); + std::stringstream ErrorMsg; + + if (!geomName.empty()) { + if (boost::regex_search(begin, end, what, re, flags)) { + return int (std::strtol(what.str().c_str(), &endChar, 10)); //TODO: use std::stoi() in c++11 + } else { + ErrorMsg << "getIndexFromName: malformed geometry name - " << geomName; + throw Base::Exception(ErrorMsg.str()); + } + } else { + throw Base::Exception("getIndexFromName - empty geometry name"); + } +} + +std::string DrawingExport getGeomTypeFromName(std::string geomName) +{ + boost::regex re("^[a-zA-Z]*"); //one or more letters at start of string + boost::match_results what; + boost::match_flag_type flags = boost::match_default; + std::string::const_iterator begin = geomName.begin(); + std::string::const_iterator end = geomName.end(); + std::stringstream ErrorMsg; + + if (!geomName.empty()) { + if (boost::regex_search(begin, end, what, re, flags)) { + return what.str(); //TODO: use std::stoi() in c++11 + } else { + ErrorMsg << "In getGeomTypeFromName: malformed geometry name - " << geomName; + throw Base::Exception(ErrorMsg.str()); + } + } else { + throw Base::Exception("getGeomTypeFromName - empty geometry name"); + } +} + +std::string DrawingExport makeGeomName(std::string geomType, int index) +{ + std::stringstream newName; + newName << geomType << index; + return newName.str(); +} +} //end extern "C" +} //end namespace DrawUtil diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h new file mode 100644 index 0000000000..b27728f6bf --- /dev/null +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (c) 2015 WandererFan * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawUtil_h_ +#define _DrawUtil_h_ + +namespace DrawUtil { +extern "C" { + +int getIndexFromName(std::string geomName); +std::string getGeomTypeFromName(std::string geomName); +std::string makeGeomName(std::string geomType, int index); + +} //end extern "C" +} //end namespace DrawUtil +#endif diff --git a/src/Mod/TechDraw/App/DrawView.cpp b/src/Mod/TechDraw/App/DrawView.cpp new file mode 100644 index 0000000000..0a36737eba --- /dev/null +++ b/src/Mod/TechDraw/App/DrawView.cpp @@ -0,0 +1,183 @@ +/*************************************************************************** + * 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 +#endif + + +#include +#include +#include +#include +#include +#include + +#include "DrawView.h" +#include "DrawPage.h" +#include "DrawViewCollection.h" +#include "DrawViewClip.h" + +using namespace TechDraw; + + +//=========================================================================== +// DrawView +//=========================================================================== + +const char* DrawView::ScaleTypeEnums[]= {"Document", + "Automatic", + "Custom", + NULL}; + +PROPERTY_SOURCE(TechDraw::DrawView, App::DocumentObject) + + + +DrawView::DrawView(void) +{ + static const char *group = "Drawing view"; + ADD_PROPERTY_TYPE(X ,(0),group,App::Prop_None,"X position of the view on the page in modelling units (mm)"); + ADD_PROPERTY_TYPE(Y ,(0),group,App::Prop_None,"Y position of the view on the page in modelling units (mm)"); + ADD_PROPERTY_TYPE(Scale ,(1.0),group,App::Prop_None,"Scale factor of the view"); + ADD_PROPERTY_TYPE(Rotation ,(0),group,App::Prop_None,"Rotation of the view on the page in degrees counterclockwise"); + + // The 'Visible' property is handled by the view provider exclusively. It has the 'Output' flag set to + // avoid to call the execute() method. The view provider touches the page object, instead. + App::PropertyType propType = static_cast(App::Prop_Hidden|App::Prop_Output); + ADD_PROPERTY_TYPE(Visible, (true),group,propType,"Control whether view is visible in page object"); + + ScaleType.setEnums(ScaleTypeEnums); + ADD_PROPERTY_TYPE(ScaleType,((long)0),group, App::Prop_None, "Scale Type"); +} + +DrawView::~DrawView() +{ +} + +App::DocumentObjectExecReturn *DrawView::recompute(void) +{ + try { + return App::DocumentObject::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 *DrawView::execute(void) +{ + if (ScaleType.isValue("Document")) { + Scale.StatusBits.set(2, true); + + TechDraw::DrawPage *page = findParentPage(); + if(page) { + if(std::abs(page->Scale.getValue() - Scale.getValue()) > FLT_EPSILON) { + Scale.setValue(page->Scale.getValue()); // Recalculate scale from page + Scale.touch(); + } + } + } else if (ScaleType.isValue("Custom")) { + Scale.StatusBits.set(2, false); + //TODO: need to ?recompute? ?redraw? to get this to stick. Mantis #1941 + //TODO: try Gui::Selection to force update + //currently need to lose focus and re-get focus to make Scale editable. + //Scale.touch(); // causes loop + } + return App::DocumentObject::execute(); +} + +/// get called by the container when a Property was changed +void DrawView::onChanged(const App::Property* prop) +{ + if (prop == &X || + prop == &Y || + prop == &ScaleType || + prop == &Rotation) { + if (!isRestoring()) { + DrawView::execute(); + } + } + + App::DocumentObject::onChanged(prop); +} + +void DrawView::onDocumentRestored() +{ + // Rebuild the view + execute(); +} + +DrawPage* DrawView::findParentPage() const +{ + // Get Feature Page + DrawPage *page = 0; + DrawViewCollection *collection = 0; + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) { + page = dynamic_cast(*it); + } + + if ((*it)->getTypeId().isDerivedFrom(DrawViewCollection::getClassTypeId())) { + collection = dynamic_cast(*it); + page = collection->findParentPage(); + } + + if(page) + break; // Found page so leave + } + + return page; +} + +bool DrawView::isInClip() +{ + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawViewClip::getClassTypeId())) { + return true; + } + } + return false; +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewPython, TechDraw::DrawView) +template<> const char* TechDraw::DrawViewPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderView"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawView.h b/src/Mod/TechDraw/App/DrawView.h new file mode 100644 index 0000000000..bbe9010822 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawView.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawView_h_ +#define _DrawView_h_ + +#include +#include +#include + +namespace TechDraw +{ + +class DrawPage; + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawView : public App::DocumentObject +{ + PROPERTY_HEADER(TechDraw::DrawView); + +public: + /// Constructor + DrawView(void); + virtual ~DrawView(); + + App::PropertyFloat X; + App::PropertyFloat Y; + App::PropertyFloat Scale; + + App::PropertyEnumeration ScaleType; + App::PropertyFloat Rotation; + App::PropertyBool Visible; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *recompute(void); + virtual App::DocumentObjectExecReturn *execute(void); + virtual void onDocumentRestored(); + //@} + + bool isInClip(); + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderView"; + } + + DrawPage* findParentPage() const; + +protected: + void onChanged(const App::Property* prop); + std::string pageFeatName; + +private: + static const char* ScaleTypeEnums[]; +}; + +typedef App::FeaturePythonT DrawViewPython; + +} //namespace TechDraw + +#endif diff --git a/src/Mod/TechDraw/App/DrawViewAnnotation.cpp b/src/Mod/TechDraw/App/DrawViewAnnotation.cpp new file mode 100644 index 0000000000..493b489494 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewAnnotation.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2012 * + * Copyright (c) 2013 Luke Parry * + * * + * 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 +#endif + +#include + +#include +#include +#include +#include +#include + +#include "DrawViewAnnotation.h" + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawViewAnnotation +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewAnnotation, TechDraw::DrawView) + + +DrawViewAnnotation::DrawViewAnnotation(void) +{ + static const char *vgroup = "Annotation"; + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Drawing"); + std::string fontName = hGrp->GetASCII("LabelFont", "osifont"); + + ADD_PROPERTY_TYPE(Text ,("Default Text"),vgroup,App::Prop_None,"The text to be displayed"); + ADD_PROPERTY_TYPE(Font ,(fontName.c_str()) ,vgroup,App::Prop_None, "The name of the font to use"); + ADD_PROPERTY_TYPE(TextColor,(0.0f,0.0f,0.0f),vgroup,App::Prop_None,"The color of the text"); + + ADD_PROPERTY_TYPE(TextSize,(8),vgroup,App::Prop_None,"The size of the text in mm"); + + Scale.StatusBits.set(3); //hide scale. n/a for Annotation + ScaleType.StatusBits.set(3); +} + +DrawViewAnnotation::~DrawViewAnnotation() +{ +} + +App::DocumentObjectExecReturn *DrawViewAnnotation::execute(void) +{ + return App::DocumentObject::StdReturn; +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewAnnotationPython, TechDraw::DrawViewAnnotation) +template<> const char* TechDraw::DrawViewAnnotationPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderAnnotation"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewAnnotation.h b/src/Mod/TechDraw/App/DrawViewAnnotation.h new file mode 100644 index 0000000000..e24fde1174 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewAnnotation.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net 2012) * + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + + + + +#ifndef _DrawViewAnnotation_h_ +#define _DrawViewAnnotation_h_ + + +#include +#include +#include "DrawView.h" +#include + + +namespace TechDraw +{ + + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawViewAnnotation : public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewAnnotation); + +public: + /// Constructor + DrawViewAnnotation(void); + virtual ~DrawViewAnnotation(); + + App::PropertyStringList Text; + App::PropertyString Font; + App::PropertyColor TextColor; + App::PropertyInteger TextSize; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderAnnotation"; + } +}; + +typedef App::FeaturePythonT DrawViewAnnotationPython; + + +} //namespace TechDraw + + +#endif diff --git a/src/Mod/TechDraw/App/DrawViewClip.cpp b/src/Mod/TechDraw/App/DrawViewClip.cpp new file mode 100644 index 0000000000..53e05c72c6 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewClip.cpp @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * Copyright (c) WandererFan 2015 * + * * + * 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 +#endif + + +#include +#include +#include +#include +#include +#include + +#include "DrawViewClip.h" +#include "DrawView.h" +#include "DrawPage.h" + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawViewClip +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewClip, TechDraw::DrawView) + +DrawViewClip::DrawViewClip(void) +{ + static const char *group = "Clip Group"; + //App::PropertyType hidden = (App::PropertyType)(App::Prop_Hidden); + + ADD_PROPERTY_TYPE(Height ,(10),group,App::Prop_None,"The height of the view area of this clip"); + ADD_PROPERTY_TYPE(Width ,(10),group,App::Prop_None,"The width of the view area of this clip"); + ADD_PROPERTY_TYPE(ShowFrame ,(0) ,group,App::Prop_None,"Specifies if the clip frame appears on the page or not"); + ADD_PROPERTY_TYPE(ShowLabels ,(0) ,group,App::Prop_None,"Specifies if View labels appear within the clip area"); + ADD_PROPERTY_TYPE(Views ,(0) ,group,App::Prop_None,"The Views in this Clip group"); + + // The 'Visible' property is handled by the view provider exclusively. It has the 'Output' flag set to + // avoid to call the execute() method. The view provider touches the page object, instead. + App::PropertyType propType = static_cast(App::Prop_Hidden|App::Prop_Output); + ADD_PROPERTY_TYPE(Visible, (true),group,propType,"Control whether Clip is visible in page object"); + + // hide N/A properties + int bitReadOnly = 2; + int bitHidden = 3; + ScaleType.StatusBits.set(bitReadOnly, true); + ScaleType.StatusBits.set(bitHidden, true); + Scale.StatusBits.set(bitReadOnly, true); + Scale.StatusBits.set(bitHidden,true); +} + +DrawViewClip::~DrawViewClip() +{ +} + +void DrawViewClip::onChanged(const App::Property* prop) +{ + if (prop == &Height || + prop == &Width || + prop == &ShowFrame || + prop == &ShowLabels) { + if (!isRestoring()) { + DrawViewClip::execute(); + } + } + + DrawView::onChanged(prop); +} + +void DrawViewClip::addView(DrawView *view) +{ + const std::vector currViews = Views.getValues(); + std::vector newViews(currViews); + newViews.push_back(view); + Views.setValues(newViews); + Views.touch(); +} + +void DrawViewClip::removeView(DrawView *view) +{ + std::vector currViews = Views.getValues(); + std::vector newViews; + std::vector::iterator it = currViews.begin(); + for (; it != currViews.end(); it++) { + std::string viewName = view->getNameInDocument(); + if (viewName.compare((*it)->getNameInDocument()) != 0) { + newViews.push_back((*it)); + } + } + Views.setValues(newViews); + touch(); +} + +App::DocumentObjectExecReturn *DrawViewClip::execute(void) +{ + touch(); + + std::vector children = Views.getValues(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { + TechDraw::DrawView *view = static_cast(*it); + view->touch(); + } + } + + return DrawView::execute(); +} + +short DrawViewClip::mustExecute() const +{ + if (Views.isTouched()) { + return 1; + } else { + return TechDraw::DrawView::mustExecute(); + } +} + +std::vector DrawViewClip::getChildViewNames() +{ + std::vector childNames; + std::vector children = Views.getValues(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { + std::string name = (*it)->getNameInDocument(); + childNames.push_back(name); + } + } + return childNames; +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewClipPython, TechDraw::DrawViewClip) +template<> const char* TechDraw::DrawViewClipPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderDrawingClip"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewClip.h b/src/Mod/TechDraw/App/DrawViewClip.h new file mode 100644 index 0000000000..3c4b7f9d26 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewClip.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * Copyright (c) WandererFan 2015 * + * * + * 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 * + * * + ***************************************************************************/ + + +#ifndef _DrawViewClip_h_ +#define _DrawViewClip_h_ + + +#include +#include +#include +#include +#include "DrawViewCollection.h" +#include + +namespace TechDraw +{ + +class DrawingExport DrawViewClip: public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewClip); + +public: + /// Constructor + DrawViewClip(void); + virtual ~DrawViewClip(); + + App::PropertyFloat Width; + App::PropertyFloat Height; + App::PropertyBool ShowFrame; + App::PropertyBool ShowLabels; + App::PropertyBool Visible; + App::PropertyLinkList Views; + + void addView(DrawView *view); + void removeView(DrawView *view); + short mustExecute() const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderDrawingClip"; + } + std::vector getChildViewNames(); + + +protected: + void onChanged(const App::Property* prop); +}; + +typedef App::FeaturePythonT DrawViewClipPython; + +} //namespace TechDraw + + +#endif diff --git a/src/Mod/TechDraw/App/DrawViewCollection.cpp b/src/Mod/TechDraw/App/DrawViewCollection.cpp new file mode 100644 index 0000000000..d040243f5f --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewCollection.cpp @@ -0,0 +1,162 @@ +/*************************************************************************** + * 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 +#endif + +#include +#include + +#include "DrawPage.h" +#include "DrawViewCollection.h" + +using namespace TechDraw; + +//=========================================================================== +// DrawViewCollection +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewCollection, TechDraw::DrawView) + +DrawViewCollection::DrawViewCollection() +{ + static const char *group = "Drawing view"; + ADD_PROPERTY_TYPE(Source ,(0), group, App::Prop_None,"Shape to view"); + ADD_PROPERTY_TYPE(Views ,(0), group, App::Prop_None,"Attached Views"); + +} + +DrawViewCollection::~DrawViewCollection() +{ +} + +int DrawViewCollection::addView(DrawView *view) +{ + // Add the new view to the collection + std::vector newViews(Views.getValues()); + newViews.push_back(view); + Views.setValues(newViews); + + touch(); +//TODO: also have to touch the parent page's views to get repaint?? + DrawPage* page = findParentPage(); + if (page) { + page->Views.touch(); + } + return Views.getSize(); +} + +short DrawViewCollection::mustExecute() const +{ + // If Tolerance Property is touched + if (Views.isTouched() || + Source.isTouched()) { + return 1; + } else { + return TechDraw::DrawView::mustExecute(); + } +} + +int DrawViewCollection::countChildren() +{ + //Count the children recursively if needed + int numChildren = 0; + + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + + App::DocumentObject *docObj = dynamic_cast(*it); + if(docObj->getTypeId().isDerivedFrom(TechDraw::DrawViewCollection::getClassTypeId())) { + TechDraw::DrawViewCollection *viewCollection = dynamic_cast(*it); + numChildren += viewCollection->countChildren() + 1; + } else { + numChildren += 1; + } + } + return numChildren; +} + +void DrawViewCollection::onDocumentRestored() +{ + // Rebuild the view + execute(); +} + +/// get called by the container when a Property was changed +void DrawViewCollection::onChanged(const App::Property* prop) +{ + TechDraw::DrawView::onChanged(prop); + + if (prop == &Source || + prop == &Views){ + if (!isRestoring()) { + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawPage::getClassTypeId())) { + TechDraw::DrawPage *page = static_cast(*it); + page->Views.touch(); + } + } + } + } +} + +App::DocumentObjectExecReturn *DrawViewCollection::execute(void) +{ + if (ScaleType.isValue("Document")) { + // Recalculate scale + Scale.StatusBits.set(App::Prop_ReadOnly); + + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + App::DocumentObject *docObj = *it; + if(docObj->getTypeId().isDerivedFrom(TechDraw::DrawView::getClassTypeId())) { + TechDraw::DrawView *view = dynamic_cast(*it); + + // Set scale factor of each view + view->ScaleType.setValue("Document"); + view->touch(); + } + } + } else if(strcmp(ScaleType.getValueAsString(), "Custom") == 0) { + // Rebuild the view + Scale.StatusBits.set(App::Prop_ReadOnly, false); + + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + App::DocumentObject *docObj = *it; + if(docObj->getTypeId().isDerivedFrom(TechDraw::DrawView::getClassTypeId())) { + TechDraw::DrawView *view = dynamic_cast(*it); + + view->ScaleType.setValue("Custom"); + // Set scale factor of each view + view->Scale.setValue(Scale.getValue()); + view->touch(); + } + } + } + + return DrawView::execute(); +} diff --git a/src/Mod/TechDraw/App/DrawViewCollection.h b/src/Mod/TechDraw/App/DrawViewCollection.h new file mode 100644 index 0000000000..2a6f79cdfa --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewCollection.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_FEATUREVIEWCOLLECTION_h_ +#define _TECHDRAW_FEATUREVIEWCOLLECTION_h_ + +#include +#include + +#include "DrawView.h" + +namespace TechDraw +{ + +/** Base class for collection of view objects + */ +class DrawingExport DrawViewCollection : public DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewCollection); + +public: + App::PropertyLink Source; + App::PropertyLinkList Views; +public: + /// Constructor + DrawViewCollection(); + virtual ~DrawViewCollection(); + short mustExecute() const; + + int addView(DrawView *view); + + int countChildren(); + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual void onDocumentRestored(); + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderViewCollection"; + } + +protected: + void onChanged(const App::Property* prop); +}; + +} //namespace TechDraw + +#endif // _TECHDRAW_FEATUREVIEWCOLLECTION_h_ diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp new file mode 100644 index 0000000000..9d66e7b871 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -0,0 +1,506 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 +#endif + +#include +#include +#include +#include + +#include + +#include "DrawViewPart.h" +#include "DrawViewDimension.h" +#include "DrawUtil.h" + +#include +#include +#include + +using namespace TechDraw; + +//=========================================================================== +// DrawViewDimension +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewDimension, TechDraw::DrawView) + +const char* DrawViewDimension::TypeEnums[]= {"Distance", + "DistanceX", + "DistanceY", + "DistanceZ", + "Radius", + "Diameter", + "Angle", + NULL}; + +const char* DrawViewDimension::ProjTypeEnums[]= {"True", + "Projected", + NULL}; + +enum RefType{ + invalidRef, + oneEdge, + twoEdge, + twoVertex + }; + +DrawViewDimension::DrawViewDimension(void) +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Drawing"); + std::string fontName = hGrp->GetASCII("LabelFont", "osifont"); + + ADD_PROPERTY_TYPE(References,(0,0),"Dimension",(App::PropertyType)(App::Prop_None),"Dimension Supporting References"); + ADD_PROPERTY_TYPE(Precision,(2) ,"Dimension",(App::PropertyType)(App::Prop_None),"Dimension Precision"); + ADD_PROPERTY_TYPE(Font ,(fontName.c_str()),"Dimension",App::Prop_None, "The name of the font to use"); + ADD_PROPERTY_TYPE(Fontsize,(4) ,"Dimension",(App::PropertyType)(App::Prop_None),"Dimension text size in mm"); + ADD_PROPERTY_TYPE(CentreLines,(0) ,"Dimension",(App::PropertyType)(App::Prop_None),"Dimension Center Lines"); + ADD_PROPERTY_TYPE(ProjDirection ,(0.,0.,1.0), "Dimension",App::Prop_None,"Projection normal direction"); + ADD_PROPERTY_TYPE(FormatSpec,("%value%") ,"Dimension",(App::PropertyType)(App::Prop_None),"Dimension Format"); + + Type.setEnums(TypeEnums); //dimension type: length, radius etc + ADD_PROPERTY(Type,((long)0)); + + ProjectionType.setEnums(ProjTypeEnums); + ADD_PROPERTY(ProjectionType, ((long)0)); //True or Projected measurement + + //hide the DrawView properties that don't apply to Dimensions + //App::PropertyType propType = static_cast(App::Prop_Hidden|App::Prop_Output); + int bitReadOnly = 2; + int bitHidden = 3; + ScaleType.StatusBits.set(bitReadOnly, true); + ScaleType.StatusBits.set(bitHidden, true); + Scale.StatusBits.set(bitReadOnly, true); + Scale.StatusBits.set(bitHidden,true); + Rotation.StatusBits.set(bitReadOnly, true); + Rotation.StatusBits.set(bitHidden, true); + //TODO: hide Dimension X,Y? + + measurement = new Measure::Measurement(); +} + +DrawViewDimension::~DrawViewDimension() +{ + delete measurement; + measurement = 0; +} + +void DrawViewDimension::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + if (prop == &References || + prop == &Precision || + prop == &Font || + prop == &Fontsize || + prop == &CentreLines || + prop == &FormatSpec) { + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + if (prop == &ProjectionType) { + const std::vector &subElements = References.getSubValues(); + if (subElements.empty()) { + Base::Console().Log("INFO - DrawViewDimension::onChanged - no References yet\n"); + return; + } + std::vector::const_iterator subIt = subElements.begin(); + bool trueAllowed = true; + for(; subIt != subElements.end(); subIt++) { + std::string geomType = DrawUtil::getGeomTypeFromName((*subIt)); + int refIndex = DrawUtil::getIndexFromName((*subIt)); + int ref = get3DRef(refIndex,geomType); + if (ref < 0) { //-1 => no reference + trueAllowed = false; + break; + } + } + if (ProjectionType.isValue("True") && !trueAllowed) { + Base::Console().Warning("Dimension %s missing Reference to 3D model. Must be Projected.\n", getNameInDocument()); + ProjectionType.setValue("Projected"); + } + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + DrawView::onChanged(prop); + } +} + +short DrawViewDimension::mustExecute() const +{ + bool result = 0; + if (References.isTouched() || + Type.isTouched() || + ProjectionType.isTouched()) { + result = 1; + } else { + result = 0; + } + return result; +} + +App::DocumentObjectExecReturn *DrawViewDimension::execute(void) +{ + //Clear the previous measurement made + measurement->clear(); + + if (ProjectionType.isValue("True")) { + //Update Dimension.measurement with 3D References + const std::vector &subElements = References.getSubValues(); + ProjDirection.setValue(getViewPart()->Direction.getValue()); + XAxisDirection.setValue(getViewPart()->XAxisDirection.getValue()); + //Overall assumption is that the dimensions are only allowed for one view + App::DocumentObject *docObj = getViewPart()->Source.getValue(); + std::vector::const_iterator subEl = subElements.begin(); + for(; subEl != subElements.end(); subEl++) { + //figure out which 3D geometry belongs to the 2D geometry in Dimension.References + //and update the Measurement.References + std::string geomType = DrawUtil::getGeomTypeFromName((*subEl)); + int refIndex = DrawUtil::getIndexFromName((*subEl)); + int ref = get3DRef(refIndex,geomType); + std::string newName = DrawUtil::makeGeomName(geomType, ref); + if (ref < 0) { + Base::Console().Log("INFO - FVD::execute - no 3D ref yet. Probably loading document.\n"); + } else { + measurement->addReference(docObj,newName.c_str()); + } + } + } + //TODO: if ProjectionType = Projected and the Projected shape changes, the Dimension may become invalid (see tilted Cube example) + + return App::DocumentObject::StdReturn; +} + +std::string DrawViewDimension::getFormatedValue() const +{ + QString str = QString::fromUtf8(FormatSpec.getStrValue().c_str()); + + QRegExp rx(QString::fromAscii("%(\\w+)%")); //any word bracketed by % + QStringList list; + int pos = 0; + + while ((pos = rx.indexIn(str, pos)) != -1) { + list << rx.cap(0); + pos += rx.matchedLength(); + } + + for(QStringList::const_iterator it = list.begin(); it != list.end(); ++it) { + if(*it == QString::fromAscii("%value%")){ + double val = std::abs(getDimValue()); + str.replace(*it, QString::number(val, 'f', Precision.getValue()) ); + } else { //insert new placeholder replacement logic here + str.replace(*it, QString::fromAscii("")); + } + } + + return str.toStdString(); +} + +double DrawViewDimension::getDimValue() const +{ + double result = 0.0; + if (!getViewPart()->hasGeometry()) { //happens when loading saved document + return result; + } + if (ProjectionType.isValue("True")) { + // True Values + if (!measurement->hasReferences()) { + return result; + } + if(Type.isValue("Distance")) { + //TODO: measurement->length() is the sum of the lengths of the edges in the References. is this what we want here? + //return measurement->length(); + result = measurement->delta().Length(); + } else if(Type.isValue("DistanceX")){ + Base::Vector3d delta = measurement->delta(); + result = delta.x; + } else if(Type.isValue("DistanceY")){ + Base::Vector3d delta = measurement->delta(); + result = delta.y; + } else if(Type.isValue("DistanceZ")){ + Base::Vector3d delta = measurement->delta(); + result = delta.z; + } else if(Type.isValue("Radius")){ + result = measurement->radius(); + } else if(Type.isValue("Diameter")){ + result = measurement->radius() * 2.0; + } else if(Type.isValue("Angle")){ + result = measurement->angle(); + } else { + throw Base::Exception("getDimValue() - Unknown Dimension Type (1)"); + } + } else { + // Projected Values + const std::vector &objects = References.getValues(); + const std::vector &subElements = References.getSubValues(); + if (Type.isValue("Distance") && getRefType() == oneEdge) { + //TODO: Check for straight line Edge? + int idx = DrawUtil::getIndexFromName(subElements[0]); + DrawingGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); + DrawingGeometry::Generic* gen = static_cast(geom); + Base::Vector2D start = gen->points[0]; + Base::Vector2D end = gen->points[1]; + Base::Vector2D line = end - start; + result = line.Length() / getViewPart()->Scale.getValue(); + } else if (Type.isValue("Distance") && getRefType() == twoEdge) { + //only works for straight line edges + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + DrawingGeometry::BaseGeom* geom0 = getViewPart()->getProjEdgeByIndex(idx0); + DrawingGeometry::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1); + DrawingGeometry::Generic* gen0 = static_cast(geom0); + DrawingGeometry::Generic* gen1 = static_cast(geom1); + Base::Vector2D s0 = gen0->points[0]; + Base::Vector2D e0 = gen0->points[1]; + Base::Vector2D s1 = gen1->points[0]; + Base::Vector2D e1 = gen1->points[1]; + result = dist2Segs(s0,e0,s1,e1) / getViewPart()->Scale.getValue(); + } else if (Type.isValue("Distance") && getRefType() == twoVertex) { + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + DrawingGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); + DrawingGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); + Base::Vector2D start = v0->pnt; + Base::Vector2D end = v1->pnt; + Base::Vector2D line = end - start; + result = line.Length() / getViewPart()->Scale.getValue(); + } else if (Type.isValue("DistanceX") && getRefType() == oneEdge) { + int idx = DrawUtil::getIndexFromName(subElements[0]); + DrawingGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); + DrawingGeometry::Generic* gen = static_cast(geom); + Base::Vector2D start = gen->points[0]; + Base::Vector2D end = gen->points[1]; + Base::Vector2D line = end - start; + return fabs(line.fX) / getViewPart()->Scale.getValue(); + } else if (Type.isValue("DistanceY") && getRefType() == oneEdge) { + int idx = DrawUtil::getIndexFromName(subElements[0]); + DrawingGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); + DrawingGeometry::Generic* gen = static_cast(geom); + Base::Vector2D start = gen->points[0]; + Base::Vector2D end = gen->points[1]; + Base::Vector2D line = end - start; + result = fabs(line.fY) / getViewPart()->Scale.getValue(); + } else if (Type.isValue("DistanceX") && getRefType() == twoVertex) { + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + DrawingGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); + DrawingGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); + Base::Vector2D start = v0->pnt; + Base::Vector2D end = v1->pnt; + Base::Vector2D line = end - start; + result = fabs(line.fX) / getViewPart()->Scale.getValue(); + } else if (Type.isValue("DistanceY") && getRefType() == twoVertex) { + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + DrawingGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); + DrawingGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); + Base::Vector2D start = v0->pnt; + Base::Vector2D end = v1->pnt; + Base::Vector2D line = end - start; + result = fabs(line.fY) / getViewPart()->Scale.getValue(); + } else if(Type.isValue("Radius")){ + //only 1 reference for a Radius + int idx = DrawUtil::getIndexFromName(subElements[0]); + DrawingGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); + DrawingGeometry::Circle* circle = static_cast (base); + result = circle->radius / getViewPart()->Scale.getValue(); //Projected BaseGeom is scaled for drawing + } else if(Type.isValue("Diameter")){ + //only 1 reference for a Diameter + int idx = DrawUtil::getIndexFromName(subElements[0]); + DrawingGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); + DrawingGeometry::Circle* circle = static_cast (base); + result = (circle->radius * 2.0) / getViewPart()->Scale.getValue(); //Projected BaseGeom is scaled for drawing + } else if(Type.isValue("Angle")){ + // Must project lines to 2D so cannot use measurement framework this time + //Relcalculate the measurement based on references stored. + //WF: why not use projected geom in GeomObject and Vector2D.GetAngle? intersection pt & direction issues? + //TODO: do we need to distinguish inner vs outer angle? -wf +// if(subElements.size() != 2) { +// throw Base::Exception("FVD - Two references required for angle measurement"); +// } + if (getRefType() != twoEdge) { + throw Base::Exception("FVD - Two edge references required for angle measurement"); + } + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + TechDraw::DrawViewPart *viewPart = dynamic_cast(objects[0]); + DrawingGeometry::BaseGeom* edge0 = viewPart->getProjEdgeByIndex(idx0); + DrawingGeometry::BaseGeom* edge1 = viewPart->getProjEdgeByIndex(idx1); + + // Only can find angles with straight line edges + if(edge0->geomType == DrawingGeometry::GENERIC && + edge1->geomType == DrawingGeometry::GENERIC) { + DrawingGeometry::Generic *gen1 = static_cast(edge0); + DrawingGeometry::Generic *gen2 = static_cast(edge1); + + Base::Vector3d p1S(gen1->points.at(0).fX, gen1->points.at(0).fY, 0.); + Base::Vector3d p1E(gen1->points.at(1).fX, gen1->points.at(1).fY, 0.); + + Base::Vector3d p2S(gen2->points.at(0).fX, gen2->points.at(0).fY, 0.); + Base::Vector3d p2E(gen2->points.at(1).fX, gen2->points.at(1).fY, 0.); + + Base::Vector3d dir1 = p1E - p1S; + Base::Vector3d dir2 = p2E - p2S; + + // Line Intersetion (taken from ViewProviderSketch.cpp) + double det = dir1.x*dir2.y - dir1.y*dir2.x; + if ((det > 0 ? det : -det) < 1e-10) + throw Base::Exception("Invalid selection - Det = 0"); + + double c1 = dir1.y*gen1->points.at(0).fX - dir1.x*gen1->points.at(0).fY; + double c2 = dir2.y*gen2->points.at(1).fX - dir2.x*gen2->points.at(1).fY; + double x = (dir1.x*c2 - dir2.x*c1)/det; + double y = (dir1.y*c2 - dir2.y*c1)/det; + + // Intersection point + Base::Vector3d p0 = Base::Vector3d(x,y,0); + + Base::Vector3d lPos((double) X.getValue(), (double) Y.getValue(), 0.); + //Base::Vector3d delta = lPos - p0; + + // Create vectors point towards intersection always + Base::Vector3d a = -p0, b = -p0; + a += ((p1S - p0).Length() < FLT_EPSILON) ? p1E : p1S; + b += ((p2S - p0).Length() < FLT_EPSILON) ? p2E : p2S; + + double angle2 = atan2( a.x*b.y - a.y*b.x, a.x*b.x + a.y*b.y ); + result = angle2 * 180. / M_PI; + } else { + throw Base::Exception("getDimValue() - Unknown Dimension Type (2)"); + } + } //endif Angle + } //endif Projected + return result; +} + +DrawViewPart* DrawViewDimension::getViewPart() const +{ + return dynamic_cast(References.getValues().at(0)); +} + +int DrawViewDimension::getRefType() const +{ + int refType = invalidRef; + const std::vector &subElements = References.getSubValues(); + if ((subElements.size() == 1) && + (DrawUtil::getGeomTypeFromName(subElements[0]) == "Edge")) { + refType = oneEdge; + } else if (subElements.size() == 2) { + if ((DrawUtil::getGeomTypeFromName(subElements[0]) == "Edge") && + (DrawUtil::getGeomTypeFromName(subElements[1]) == "Edge")) { + refType = twoEdge; + } else if ((DrawUtil::getGeomTypeFromName(subElements[0]) == "Vertex") && + (DrawUtil::getGeomTypeFromName(subElements[1]) == "Vertex")) { + refType = twoVertex; + } + //} else add different types here - Vertex-Edge, Vertex-Face, ... + } + return refType; +} + +int DrawViewDimension::get3DRef(int refIndex, std::string geomType) const +{ + int ref = -1; + if (geomType.compare("Edge") == 0) { + ref = getViewPart()->getEdgeRefByIndex(refIndex); + } else if (geomType.compare("Vertex") == 0) { + ref = getViewPart()->getVertexRefByIndex(refIndex); + } + return ref; +} + +void DrawViewDimension::dumpRefs(char* text) const +{ + Base::Console().Message("DUMP - %s\n",text); + const std::vector &objects = References.getValues(); + const std::vector &subElements = References.getSubValues(); + std::vector::const_iterator objIt = objects.begin(); + std::vector::const_iterator subIt = subElements.begin(); + int i = 0; + for( ;objIt != objects.end();objIt++,subIt++,i++) { + Base::Console().Message("DUMP - ref: %d object: %s subElement: %s\n",i,(*objIt)->getNameInDocument(),(*subIt).c_str()); + } +} + +double DrawViewDimension::dist2Segs(Base::Vector2D s1, + Base::Vector2D e1, + Base::Vector2D s2, + Base::Vector2D e2) const +{ + gp_Pnt start(s1.fX,s1.fY,0.0); + gp_Pnt end(e1.fX,e1.fY,0.0); + TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(start); + TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(end); + BRepBuilderAPI_MakeEdge makeEdge1(v1,v2); + TopoDS_Edge edge1 = makeEdge1.Edge(); + + start = gp_Pnt(s2.fX,s2.fY,0.0); + end = gp_Pnt(e2.fX,e2.fY,0.0); + v1 = BRepBuilderAPI_MakeVertex(start); + v2 = BRepBuilderAPI_MakeVertex(end); + BRepBuilderAPI_MakeEdge makeEdge2(v1,v2); + TopoDS_Edge edge2 = makeEdge2.Edge(); + + BRepExtrema_DistShapeShape extss(edge1, edge2); + if (!extss.IsDone()) { + throw Base::Exception("FVD - BRepExtrema_DistShapeShape failed"); + } + int count = extss.NbSolution(); + double minDist = 0.0; + if (count != 0) { + minDist = extss.Value(); + } //TODO: else { explode } + + return minDist; +} + +bool DrawViewDimension::hasReferences(void) const +{ + bool result = false; + const std::vector &refs = References.getValues(); + if (refs.empty()) { + result = false; + } else { + result = true; + } + return result; +} diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h new file mode 100644 index 0000000000..3ba604805e --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _Drawing_DrawViewDimension_h_ +#define _Drawing_DrawViewDimension_h_ + +# include +# include +# include + +#include "DrawView.h" +#include "DrawViewPart.h" + +namespace Measure { +class Measurement; +} +namespace TechDraw +{ + +class DrawingExport DrawViewDimension : public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewDimension); + +public: + /// Constructor + DrawViewDimension(); + virtual ~DrawViewDimension(); + + App::PropertyEnumeration ProjectionType; //True/Projected + App::PropertyVector ProjDirection; //??why would dim have different projDir from View? + App::PropertyLinkSubList References; //Points to Projection SubFeatures + App::PropertyEnumeration Type; //DistanceX,DistanceY,Diameter, etc + App::PropertyVector XAxisDirection; //??always equal to View?? + + /// Properties for Visualisation + App::PropertyInteger Precision; + App::PropertyString Font; + App::PropertyFloat Fontsize; + App::PropertyBool CentreLines; + App::PropertyString FormatSpec; + + short mustExecute() const; + bool hasReferences(void) const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderDimension"; + } + + virtual std::string getFormatedValue() const; + virtual double getDimValue() const; + DrawViewPart* getViewPart() const; + +protected: + void onChanged(const App::Property* prop); + int getIndexFromName(std::string geomName) const; + int getRefType() const; //Vertex-Vertex, Edge, Edge-Edge + int get3DRef(int refIndex, std::string geomType) const; + +protected: + Measure::Measurement *measurement; + double dist2Segs(Base::Vector2D s1, + Base::Vector2D e1, + Base::Vector2D s2, + Base::Vector2D e2) const; +private: + static const char* TypeEnums[]; + static const char* ProjTypeEnums[]; + void dumpRefs(char* text) const; +}; + +} //namespace TechDraw +#endif diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp new file mode 100644 index 0000000000..81c7385efa --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -0,0 +1,471 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * * + * 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 +#endif + + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Geometry.h" +#include "DrawViewPart.h" +#include "ProjectionAlgos.h" +#include "DrawHatch.h" +//#include "DrawViewDimension.h" + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawViewPart +//=========================================================================== + +Base::Vector3d _getValidXDir(const DrawViewPart *me); + +App::PropertyFloatConstraint::Constraints DrawViewPart::floatRange = {0.01f,5.0f,0.05f}; + +PROPERTY_SOURCE(TechDraw::DrawViewPart, TechDraw::DrawView) + +DrawViewPart::DrawViewPart(void) : geometryObject(0) +{ + static const char *group = "Shape view"; + static const char *vgroup = "Drawing view"; + + ADD_PROPERTY_TYPE(Direction ,(0,0,1.0) ,group,App::Prop_None,"Projection normal direction"); + ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"3D Shape to view"); + ADD_PROPERTY_TYPE(ShowHiddenLines ,(false),group,App::Prop_None,"Control the appearance of the dashed hidden lines"); + ADD_PROPERTY_TYPE(ShowSmoothLines ,(false),group,App::Prop_None,"Control the appearance of the smooth lines"); + ADD_PROPERTY_TYPE(LineWidth,(0.7f),vgroup,App::Prop_None,"The thickness of the resulting lines"); + ADD_PROPERTY_TYPE(HiddenWidth,(0.15),vgroup,App::Prop_None,"The thickness of the hidden lines, if enabled"); + ADD_PROPERTY_TYPE(Tolerance,(0.05f),vgroup,App::Prop_None,"The tessellation tolerance"); + Tolerance.setConstraints(&floatRange); + ADD_PROPERTY_TYPE(XAxisDirection ,(1,0,0) ,group,App::Prop_None,"X-Axis direction"); + //ADD_PROPERTY_TYPE(HatchAreas ,(0),vgroup,App::Prop_None,"Hatched areas of this view"); + + geometryObject = new DrawingGeometry::GeometryObject(); +} + +DrawViewPart::~DrawViewPart() +{ + delete geometryObject; +} + + +App::DocumentObjectExecReturn *DrawViewPart::execute(void) +{ + App::DocumentObject *link = Source.getValue(); + if (!link) { + return new App::DocumentObjectExecReturn("FVP - No Source object linked"); + } + + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + return new App::DocumentObjectExecReturn("FVP - Linked object is not a Part object"); + } + + TopoDS_Shape shape = static_cast(link)->Shape.getShape()._Shape; + if (shape.IsNull()) { + return new App::DocumentObjectExecReturn("FVP - Linked shape object is empty"); + } + + try { + geometryObject->setTolerance(Tolerance.getValue()); + geometryObject->setScale(Scale.getValue()); + geometryObject->extractGeometry(shape, + Direction.getValue(), + ShowHiddenLines.getValue(), + _getValidXDir(this)); + bbox = geometryObject->calcBoundingBox(); + touch(); + + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } + + + // There is a guaranteed change so check any references linked to this and touch + // We need to update all views pointing at this (ProjectionGroup, ClipGroup, etc) + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { + TechDraw::DrawView *view = static_cast(*it); + view->touch(); + } + } + + return DrawView::execute(); +} + +short DrawViewPart::mustExecute() const +{ + short result = (Direction.isTouched() || + XAxisDirection.isTouched() || + Source.isTouched() || + Scale.isTouched() || + ScaleType.isTouched() || + ShowHiddenLines.isTouched()); + return result; +} + +void DrawViewPart::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + if (prop == &Direction || + prop == &XAxisDirection || + prop == &Source || + prop == &Scale || + prop == &ScaleType || + prop == &ShowHiddenLines) { + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + } + DrawView::onChanged(prop); + +//TODO: when scale changes, any Dimensions for this View sb recalculated. +} + +#if 0 +int DrawViewPart::addHatch(App::DocumentObject *docObj) +{ + if(!docObj->isDerivedFrom(TechDraw::DrawHatch::getClassTypeId())) + return -1; + + const std::vector currAreas = HatchAreas.getValues(); + std::vector newAreas(currAreas); + newAreas.push_back(docObj); + HatchAreas.setValues(newAreas); + HatchAreas.touch(); + return HatchAreas.getSize(); +} + +int DrawViewPart::removeHatch(App::DocumentObject *docObj) +{ + if(!docObj->isDerivedFrom(TechDraw::DrawHatch::getClassTypeId())) + return -1; + + const std::vector currAreas = HatchAreas.getValues(); + std::vector newAreas; + std::vector::const_iterator it = currAreas.begin(); + for (; it != currAreas.end(); it++) { + std::string areaName = docObj->getNameInDocument(); + if (areaName.compare((*it)->getNameInDocument()) != 0) { + newAreas.push_back((*it)); + } + } + HatchAreas.setValues(newAreas); + HatchAreas.touch(); + + return HatchAreas.getSize(); +} +#endif + +std::vector DrawViewPart::getHatches() const +{ + std::vector result; + std::vector children = getInList(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawHatch::getClassTypeId())) { + TechDraw::DrawHatch* hatch = dynamic_cast(*it); + result.push_back(hatch); + } + } + + return result; +} + +const std::vector & DrawViewPart::getVertexGeometry() const +{ + return geometryObject->getVertexGeometry(); +} + +const std::vector & DrawViewPart::getVertexReferences() const +{ + return geometryObject->getVertexRefs(); +} + +const std::vector & DrawViewPart::getFaceGeometry() const +{ + return geometryObject->getFaceGeometry(); +} + +const std::vector & DrawViewPart::getFaceReferences() const +{ + return geometryObject->getFaceRefs(); +} + +const std::vector & DrawViewPart::getEdgeGeometry() const +{ + return geometryObject->getEdgeGeometry(); +} + +const std::vector & DrawViewPart::getEdgeReferences() const +{ + return geometryObject->getEdgeRefs(); +} + +//! project Source Edge(idx) to 2D BaseGeom +DrawingGeometry::BaseGeom *DrawViewPart::getCompleteEdge(int idx) const +{ + //NOTE: idx is in fact a Reference to an Edge in Source + //returns projection of ref'd Edge as BaseGeom. Why not just use existing BaseGeom(idx)? + App::DocumentObject* link = Source.getValue(); + + if (!link || !link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return 0; + + const Part::TopoShape &topoShape = static_cast(link)->Shape.getShape(); + std::stringstream str; + str << "Edge" << idx; + TopoDS_Shape shape = topoShape.getSubShape(str.str().c_str()); + + + const TopoDS_Shape &support = static_cast(link)->Shape.getValue(); + //TODO: make sure prjShape gets deleted + + DrawingGeometry::BaseGeom* prjShape = 0; + try { + prjShape = geometryObject->projectEdge(shape, support, Direction.getValue(), _getValidXDir(this)); + } + catch(Standard_Failure) { + Base::Console().Error("getCompleteEdge - OCC Error - could not project Edge: %d\n",idx); + return 0; + } + catch (exception& e) { + Base::Console().Error("getCompleteEdge - unknown exception on Edge: %d - %s\n",idx,e.what()); + return 0; + } + catch(...) { + Base::Console().Error("getCompleteEdge - unknown error on Edge: %d\n",idx); + return 0; + } + + return prjShape; +} + +//! project Source Vertex(idx) to 2D geometry +DrawingGeometry::Vertex * DrawViewPart::getVertex(int idx) const +{ + //## Get the Part Link ##/ + App::DocumentObject* link = Source.getValue(); + + if (!link || !link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return 0; + + const Part::TopoShape &topoShape = static_cast(link)->Shape.getShape(); + std::stringstream str; + str << "Vertex" << idx; + TopoDS_Shape shape = topoShape.getSubShape(str.str().c_str()); + + const TopoDS_Shape &support = static_cast(link)->Shape.getValue(); + //TODO: Make sure prjShape gets deleted + DrawingGeometry::Vertex *prjShape = geometryObject->projectVertex(shape, support, Direction.getValue(), _getValidXDir(this)); + //Base::Console().Log("vert %f, %f \n", prjShape->pnt.fX, prjShape->pnt.fY); + return prjShape; +} + +DrawingGeometry::Vertex* DrawViewPart::getVertexGeomByRef(int ref) const +{ + const std::vector &verts = getVertexGeometry(); + if (verts.empty()) { + Base::Console().Log("INFO - getVertexGeomByRef(%d) - no Vertex Geometry. Probably restoring?\n",ref); + return NULL; + } + const std::vector &vertRefs = getVertexReferences(); + std::vector::const_iterator vert = verts.begin(); + bool found = false; + for(int i = 0 ; vert != verts.end(); ++vert, i++) { + if (vertRefs[i] == ref) { + found = true; + break; + } + } + if (found) { + return (*vert); + } else { + std::stringstream error; + error << "getVertexGeomByRef: no vertex geometry for ref: " << ref; + throw Base::Exception(error.str().c_str()); + } +} + +//! returns existing BaseGeom of Edge with 3D Reference = ref +DrawingGeometry::BaseGeom* DrawViewPart::getEdgeGeomByRef(int ref) const +{ + const std::vector &geoms = getEdgeGeometry(); + if (geoms.empty()) { + Base::Console().Log("INFO - getEdgeGeomByRef(%d) - no Edge Geometry. Probably restoring?\n",ref); + return NULL; + } + const std::vector &refs = getEdgeReferences(); + std::vector::const_iterator it = geoms.begin(); + bool found = false; + for(int i = 0 ; it != geoms.end(); ++it, i++) { + if (refs[i] == ref) { + found = true; + break; + } + } + if (found) { + return (*it); + } else { + std::stringstream error; + error << "getEdgeGeomByRef: no edge geometry for ref: " << ref; + throw Base::Exception(error.str().c_str()); + } +} + +//! returns existing BaseGeom of 2D Edge(idx) +DrawingGeometry::BaseGeom* DrawViewPart::getProjEdgeByIndex(int idx) const +{ + const std::vector &geoms = getEdgeGeometry(); + if (geoms.empty()) { + Base::Console().Log("INFO - getProjEdgeByIndex(%d) - no Edge Geometry. Probably restoring?\n",idx); + return NULL; + } + return geoms[idx]; +} + +//! returns existing geometry of 2D Vertex(idx) +DrawingGeometry::Vertex* DrawViewPart::getProjVertexByIndex(int idx) const +{ + const std::vector &geoms = getVertexGeometry(); + if (geoms.empty()) { + Base::Console().Log("INFO - getProjVertexByIndex(%d) - no Vertex Geometry. Probably restoring?\n",idx); + return NULL; + } + return geoms[idx]; +} + +int DrawViewPart::getEdgeRefByIndex(int idx) const +{ + const std::vector &refs = getEdgeReferences(); + if (refs.empty()) { + Base::Console().Log("INFO - getEdgeRefByIndex(%d) - no Edge Geometry. Probably restoring?\n",idx); + return -1; + } + return refs[idx]; +} + +int DrawViewPart::getVertexRefByIndex(int idx) const +{ + const std::vector &refs = getVertexReferences(); + if (refs.empty()) { + Base::Console().Log("INFO - getVertexRefByIndex(%d) - no Vertex Geometry. Probably restoring?\n",idx); + return -1; + } + return refs[idx]; +} + +Base::BoundBox3d DrawViewPart::getBoundingBox() const +{ + return bbox; +} + +bool DrawViewPart::hasGeometry(void) const +{ + bool result = false; + const std::vector &verts = getVertexGeometry(); + const std::vector &edges = getEdgeGeometry(); + if (verts.empty() && + edges.empty() ) { + result = false; + } else { + result = true; + } + return result; +} + +Base::Vector3d _getValidXDir(const DrawViewPart *me) +{ + Base::Vector3d xDir = me->XAxisDirection.getValue(); + if (xDir.Length() == 0) { + Base::Console().Warning("XAxisDirection has zero length - using (1,0,0)\n"); + xDir = Base::Vector3d(1.0,0.0,0.0); + } + return xDir; +} + +void DrawViewPart::dumpVertexRefs(char* text) const +{ + Base::Console().Message("DUMP - %s\n",text); + const std::vector &refs = getVertexReferences(); + std::vector::const_iterator it = refs.begin(); + int i = 0; + for( ; it != refs.end(); it++, i++) { + Base::Console().Message("DUMP - Vertex: %d ref: %d\n",i,(*it)); + } +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewPartPython, TechDraw::DrawViewPart) +template<> const char* TechDraw::DrawViewPartPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderView"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h new file mode 100644 index 0000000000..6c5ed22188 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawViewPart_h_ +#define _DrawViewPart_h_ + +#include +#include +#include "DrawView.h" +#include + +#include +#include "GeometryObject.h" + +namespace TechDraw { +class DrawHatch; +} + +namespace TechDraw +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawViewPart : public DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewPart); + +public: + /// Constructor + DrawViewPart(void); + virtual ~DrawViewPart(); + + App::PropertyLink Source; //Part Feature + App::PropertyVector Direction; //TODO: Rename to YAxisDirection or whatever this actually is + App::PropertyVector XAxisDirection; + App::PropertyBool ShowHiddenLines; + App::PropertyBool ShowSmoothLines; + App::PropertyFloat LineWidth; + App::PropertyFloat HiddenWidth; + App::PropertyFloatConstraint Tolerance; +// App::PropertyLinkList HatchAreas; //DrawHatch + + //int addHatch(App::DocumentObject *docObj); + //int removeHatch(App::DocumentObject *docObj); + std::vector getHatches(void) const; + + const std::vector & getVertexGeometry() const; + const std::vector & getEdgeGeometry() const; + const std::vector & getFaceGeometry() const; + bool hasGeometry(void) const; + + DrawingGeometry::BaseGeom* getProjEdgeByIndex(int idx) const; //get existing geom for edge idx in projection + DrawingGeometry::Vertex* getProjVertexByIndex(int idx) const; //get existing geom for vertex idx in projection + + int getEdgeRefByIndex(int idx) const; //get reference to Source edge for Projected edge idx + int getVertexRefByIndex(int idx) const; //get reference to Source Vertex for Projected Vertex idx + + DrawingGeometry::BaseGeom * getCompleteEdge(int idx) const; //project source edge idx + DrawingGeometry::Vertex * getVertex(int idx) const; //project source vertex + DrawingGeometry::Vertex* getVertexGeomByRef(int ref) const; + DrawingGeometry::BaseGeom* getEdgeGeomByRef(int ref) const; + + /// Get References for geometric features + const std::vector & getVertexReferences() const; + const std::vector & getEdgeReferences() const; + const std::vector & getFaceReferences() const; + + virtual Base::BoundBox3d getBoundingBox() const; + + short mustExecute() const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderViewPart"; + } + + void dumpVertexRefs(char* text) const; + +protected: + void onChanged(const App::Property* prop); + + DrawingGeometry::GeometryObject *geometryObject; + Base::BoundBox3d bbox; + +private: + static App::PropertyFloatConstraint::Constraints floatRange; + +}; + +typedef App::FeaturePythonT DrawViewPartPython; + +} //namespace TechDraw + +#endif // #ifndef _DrawViewPart_h_ diff --git a/src/Mod/TechDraw/App/DrawViewPartPy.xml b/src/Mod/TechDraw/App/DrawViewPartPy.xml new file mode 100644 index 0000000000..44f135e678 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPartPy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for creating and manipulating Drawing Part Views + + + + diff --git a/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp b/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp new file mode 100644 index 0000000000..61d365065f --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPartPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Drawing/App/DrawViewPart.h" + +// inclusion of the generated files (generated out of DrawViewPartPy.xml) +#include "DrawViewPartPy.h" +#include "DrawViewPartPy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawViewPartPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *DrawViewPartPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawViewPartPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/TechDraw/App/DrawViewPy.xml b/src/Mod/TechDraw/App/DrawViewPy.xml new file mode 100644 index 0000000000..b201fcaebf --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for creating and manipulating Drawing Views + + + + diff --git a/src/Mod/TechDraw/App/DrawViewPyImp.cpp b/src/Mod/TechDraw/App/DrawViewPyImp.cpp new file mode 100644 index 0000000000..4bc0ef903e --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Drawing/App/DrawView.h" + +// inclusion of the generated files (generated out of DrawViewPy.xml) +#include "DrawViewPy.h" +#include "DrawViewPy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawViewPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *DrawViewPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawViewPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp new file mode 100644 index 0000000000..ad74fadd31 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -0,0 +1,282 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * * + * 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 +#endif + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "DrawViewSection.h" +#include "ProjectionAlgos.h" + +using namespace TechDraw; +using namespace std; + +//=========================================================================== +// DrawViewSection +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewSection, TechDraw::DrawViewPart) + +DrawViewSection::DrawViewSection() +{ + static const char *group = "Shape view"; + + ADD_PROPERTY_TYPE(SectionNormal ,(0,0,1.0) ,group,App::Prop_None,"Section Plane normal direction"); + ADD_PROPERTY_TYPE(SectionOrigin ,(0,0,0) ,group,App::Prop_None,"Section Plane Origin"); + ADD_PROPERTY_TYPE(ShowCutSurface ,(true),group,App::Prop_None,"Show the cut surface"); + + geometryObject = new DrawingGeometry::GeometryObject(); +} + +DrawViewSection::~DrawViewSection() +{ +} + +short DrawViewSection::mustExecute() const +{ + // If Tolerance Property is touched + if(SectionNormal.isTouched() || + SectionOrigin.isTouched() || + ShowCutSurface.isTouched()) + return 1; + + return TechDraw::DrawViewPart::mustExecute(); +} + +App::DocumentObjectExecReturn *DrawViewSection::execute(void) +{ + //## Get the Part Link ##/ + App::DocumentObject* link = Source.getValue(); + + if (!link) + return new App::DocumentObjectExecReturn("No object linked"); + + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a Part object"); + + const Part::TopoShape &partTopo = static_cast(link)->Shape.getShape(); + + if (partTopo._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape object is empty"); + + gp_Pln pln = getSectionPlane(); + // Get the Axis Directions for the Plane to transform UV components again + gp_XYZ xAxis = pln.XAxis().Direction().XYZ(); + gp_XYZ yAxis = pln.YAxis().Direction().XYZ(); + gp_XYZ origin = pln.Location().XYZ(); + + Base::BoundBox3d bb = partTopo.getBoundBox(); + + Base::Vector3d tmp1 = SectionOrigin.getValue(); + Base::Vector3d tmp2 = SectionNormal.getValue(); + + Base::Vector3d plnPnt(tmp1.x, tmp1.y, tmp1.z); + Base::Vector3d plnNorm(tmp2.x, tmp2.y, tmp2.z); + + if(!bb.IsCutPlane(plnPnt, plnNorm)) { + return new App::DocumentObjectExecReturn("Section Plane doesn't intersect part"); + } + + bb.Enlarge(1.0); // Enlarge the bounding box to prevent any clipping + + // Gather the points + std::vector pnts; + + pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MaxZ)); + + double uMax = 0, vMax = 0, wMax; + for(std::vector::const_iterator it = pnts.begin(); it != pnts.end(); ++it) { + // Project each bounding box point onto projection plane and find larges u,v values + + Base::Vector3d pnt = (*it); + pnt.ProjToPlane(plnPnt, plnNorm); + + uMax = std::max(uMax, std::abs(plnPnt[0] - pnt[0])); + vMax = std::max(vMax, std::abs(plnPnt[1] - pnt[1])); + + //wMax is the bounding box point furthest away used for determining extrusion length + double dist = (*it).DistanceToPlane(plnPnt, plnNorm); + wMax = std::max(wMax, dist); + } + + // Build face directly onto plane + BRepBuilderAPI_MakePolygon mkPoly; + gp_Pnt pn1(origin + xAxis * uMax + yAxis * vMax); + gp_Pnt pn2(origin + xAxis * uMax + yAxis * -vMax); + gp_Pnt pn3(origin + xAxis * -uMax + yAxis * -vMax); + gp_Pnt pn4(origin + xAxis * -uMax + yAxis * +vMax); + mkPoly.Add(pn1); + mkPoly.Add(pn2); + mkPoly.Add(pn3); + mkPoly.Add(pn4); + mkPoly.Close(); + + // Make the extrusion face + BRepBuilderAPI_MakeFace mkFace(mkPoly.Wire()); + TopoDS_Face aProjFace = mkFace.Face(); + if(aProjFace.IsNull()) + return new App::DocumentObjectExecReturn("DrawViewSection - Projected face is NULL"); + // Create an infinite projection (investigate if infite extrusion necessary) +// BRepPrimAPI_MakePrism PrismMaker(from, Ltotal*gp_Vec(dir), 0,1); // finite prism + TopoDS_Shape prism = BRepPrimAPI_MakePrism(aProjFace, wMax * gp_Vec(pln.Axis().Direction()), 0, 1).Shape(); + + // We need to copy the shape to not modify the BRepstructure + BRepBuilderAPI_Copy BuilderCopy(partTopo._Shape); + TopoDS_Shape myShape = BuilderCopy.Shape(); + + BRepAlgoAPI_Cut mkCut(myShape, prism); + // Let's check if the fusion has been successful + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Section cut has failed"); + + // Cache the result + result = mkCut.Shape(); + + try { + geometryObject->setTolerance(Tolerance.getValue()); + geometryObject->setScale(Scale.getValue()); + //TODO: Do we need to check for nonzero XAxisDirection here? + geometryObject->extractGeometry(result, Direction.getValue(), ShowHiddenLines.getValue(), XAxisDirection.getValue()); + bbox = geometryObject->calcBoundingBox(); + + touch(); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + Base::Console().Log("DrawViewSection::execute - extractGeometry failed: %s\n",e->GetMessageString()); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } + + // TODO: touch references? see DrawViewPart.execute() + return DrawView::execute(); //sb DrawViewPart? +} + +gp_Pln DrawViewSection::getSectionPlane() const +{ + Base::Vector3d plnPnt = SectionOrigin.getValue(); + Base::Vector3d plnNorm = SectionNormal.getValue(); + + return gp_Pln(gp_Pnt(plnPnt.x, plnPnt.y, plnPnt.z), gp_Dir(plnNorm.x, plnNorm.y, plnNorm.z)); +} + +//! tries to find the intersection of the section plane with the part??? +//face logic is turned off in GeometryObject, so this won't work now. +void DrawViewSection::getSectionSurface(std::vector §ionFace) const { + +#if MOD_TECHDRAW_HANDLE_FACES + if(result.IsNull()){ + //throw Base::Exception("Sectional View Result is Empty"); + Base::Console().Log("DrawViewSection::getSectionSurface - Sectional View Result is Empty\n"); + return; + } + + gp_Pln pln = getSectionPlane(); + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + // Iterate through all faces + TopExp_Explorer face(result, TopAbs_FACE); + for ( ; faces.More(); faces.Next()) { + const TopoDS_Face& face = TopoDS::Face(faces.Current()); + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() == GeomAbs_Plane){ + gp_Pln plane = adapt.Plane(); + if(plane.Contains(pln.Location(), Precision::Confusion()) && plane.Axis().IsParallel(pln.Axis(), Precision::Angular())) { + builder.Add(comp, face); + } + } + } + //TODO: Do we need to check for nonzero XAxisDirection here? + geometryObject->projectSurfaces(comp, result, Direction.getValue(), XAxisDirection.getValue(), sectionFace); +#endif +} +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSectionPython, TechDraw::DrawViewSection) +template<> const char* TechDraw::DrawViewSectionPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderView"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h new file mode 100644 index 0000000000..9ba979c8b7 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawViewSection_h_ +#define _DrawViewSection_h_ + +#include +#include +#include + +#include "DrawViewPart.h" + +class gp_Pln; + +namespace TechDraw +{ + + +/** Base class of all View Features in the drawing module + */ +class DrawingExport DrawViewSection : public DrawViewPart +{ + PROPERTY_HEADER(Part::DrawViewSection); + +public: + /// Constructor + DrawViewSection(void); + virtual ~DrawViewSection(); + + App::PropertyVector SectionNormal; + App::PropertyVector SectionOrigin; + App::PropertyBool ShowCutSurface; + + short mustExecute() const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); +// virtual void onChanged(const App::Property* prop); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderViewSection"; + } + +public: + void getSectionSurface(std::vector §ionFace) const; + +protected: + TopoDS_Shape result; + gp_Pln getSectionPlane() const; +}; + +typedef App::FeaturePythonT DrawViewSectionPython; + + +} //namespace TechDraw + +#endif diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.cpp b/src/Mod/TechDraw/App/DrawViewSymbol.cpp new file mode 100644 index 0000000000..4aac10e416 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSymbol.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2013 * + * * + * 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 +#endif + +#include +#include + +#include +#include +#include + +#include "DrawViewSymbol.h" + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawViewSymbol +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewSymbol, TechDraw::DrawView) + + +DrawViewSymbol::DrawViewSymbol(void) +{ + static const char *vgroup = "Drawing view"; + + ADD_PROPERTY_TYPE(Symbol,(""),vgroup,App::Prop_Hidden,"The SVG code defining this symbol"); + ADD_PROPERTY_TYPE(EditableTexts,(""),vgroup,App::Prop_None,"Substitution values for the editable strings in this symbol"); + ScaleType.setValue("Custom"); +} + +DrawViewSymbol::~DrawViewSymbol() +{ +} + +/// get called by the container when a Property was changed +void DrawViewSymbol::onChanged(const App::Property* prop) +{ + if (prop == &Symbol) { + if (!isRestoring()) { + std::vector eds; + std::string svg = Symbol.getValue(); + if (!svg.empty()) { + boost::regex e ("(.*?)"); + std::string::const_iterator tbegin, tend; + tbegin = svg.begin(); + tend = svg.end(); + boost::match_results twhat; + while (boost::regex_search(tbegin, tend, twhat, e)) { + eds.push_back(twhat[2]); + tbegin = twhat[0].second; + } + EditableTexts.setValues(eds); + } + } + } + TechDraw::DrawView::onChanged(prop); +} + +App::DocumentObjectExecReturn *DrawViewSymbol::execute(void) +{ + std::string svg = Symbol.getValue(); + const std::vector& editText = EditableTexts.getValues(); + + if (!editText.empty()) { + boost::regex e1 ("(.*?)"); + string::const_iterator begin, end; + begin = svg.begin(); + end = svg.end(); + boost::match_results what; + std::size_t count = 0; + std::string newsvg; + newsvg.reserve(svg.size()); + + while (boost::regex_search(begin, end, what, e1)) { + if (count < editText.size()) { + // change values of editable texts. Also strip the "freecad:editable" + // attribute so it isn't detected by the page + boost::regex e2 ("((.*?)()"); + boost::re_detail::string_out_iterator out(newsvg); + boost::regex_replace(out, begin, what[0].second, e2, "$1$3>"+editText[count]+"$5"); + } + count++; + begin = what[0].second; + } + + // now copy the rest + newsvg.insert(newsvg.end(), begin, end); + svg = newsvg; + } + + std::stringstream result; + result << "" << endl + << svg << endl + << "" << endl; + + // Apply the resulting fragment + // no more ViewResult! Need to xlate SVG to Geometry object??? + //ViewResult.setValue(result.str().c_str()); + + //return App::DocumentObject::StdReturn; + return DrawView::execute(); +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSymbolPython, TechDraw::DrawViewSymbol) +template<> const char* TechDraw::DrawViewSymbolPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderSymbol"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.h b/src/Mod/TechDraw/App/DrawViewSymbol.h new file mode 100644 index 0000000000..a7ce490f6a --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSymbol.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net 2013) * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawViewSymbol_h_ +#define _DrawViewSymbol_h_ + +#include +#include +#include "DrawView.h" +#include + +#include + +namespace TechDraw +{ + + +class DrawingExport DrawViewSymbol : public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewSymbol); + +public: + /// Constructor + DrawViewSymbol(void); + virtual ~DrawViewSymbol(); + + App::PropertyString Symbol; + App::PropertyStringList EditableTexts; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderSymbol"; + } + +protected: + void onChanged(const App::Property* prop); + Base::BoundBox3d bbox; +}; + +typedef App::FeaturePythonT DrawViewSymbolPython; + + +} //namespace TechDraw + + +#endif diff --git a/src/Mod/TechDraw/App/DrawViewSymbolPy.xml b/src/Mod/TechDraw/App/DrawViewSymbolPy.xml new file mode 100644 index 0000000000..1f26bb4ab3 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSymbolPy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for creating and manipulating Drawing SVG Symbol Views + + + + diff --git a/src/Mod/TechDraw/App/DrawViewSymbolPyImp.cpp b/src/Mod/TechDraw/App/DrawViewSymbolPyImp.cpp new file mode 100644 index 0000000000..85f0250595 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawViewSymbolPyImp.cpp @@ -0,0 +1,36 @@ + +#include "PreCompiled.h" + +#include "Mod/Drawing/App/DrawViewSymbol.h" +#include "Mod/Drawing/App/DrawView.h" +#include "Mod/Drawing/App/DrawViewPy.h" + +// inclusion of the generated files (generated out of DrawViewSymbolPy.xml) +#include "DrawViewSymbolPy.h" +#include "DrawViewSymbolPy.cpp" + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawViewSymbolPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *DrawViewSymbolPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawViewSymbolPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp new file mode 100644 index 0000000000..c9f9773150 --- /dev/null +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -0,0 +1,450 @@ +/*************************************************************************** + * Copyright (c) 2012 Luke Parry * + * * + * 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 +#endif + +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "Geometry.h" + +using namespace TechDrawGeometry; + +// Collection of Geometric Features +Wire::Wire() +{ + +} + +Wire::~Wire() +{ + for(std::vector::iterator it = geoms.begin(); it != geoms.end(); ++it) { + delete (*it); + *it = 0; + } + geoms.clear(); +} + +Face::Face() +{ + +} + +Face::~Face() +{ + for(std::vector::iterator it = wires.begin(); it != wires.end(); ++it) { + delete (*it); + *it = 0; + } + wires.clear(); +} + +BaseGeom::BaseGeom() : + geomType(NOTDEF), + reversed(false) +{ +} + +//! ugh. yuck. +std::vector BaseGeom::findEndPoints() +{ + std::vector result; + switch(this->geomType) { + case DrawingGeometry::CIRCLE: { + DrawingGeometry::Circle *geom = static_cast(this); + double x = geom->center.fX + geom->radius; + result.push_back(Base::Vector2D(x,geom->center.fY)); + result.push_back(Base::Vector2D(x,geom->center.fY)); + } break; + case DrawingGeometry::ARCOFCIRCLE: { + DrawingGeometry::AOC *geom = static_cast(this); + result.push_back(geom->startPnt); + result.push_back(geom->endPnt); + } break; + case DrawingGeometry::ELLIPSE: { + DrawingGeometry::Ellipse *geom = static_cast(this); + result.push_back(geom->center + Base::Vector2D(geom->major * cos(geom->angle), geom->major * sin(geom->angle))); + result.push_back(geom->center + Base::Vector2D(geom->major * cos(geom->angle), geom->major * sin(geom->angle))); + } break; + case DrawingGeometry::ARCOFELLIPSE: { + DrawingGeometry::AOE *geom = static_cast(this); + result.push_back(geom->startPnt); + result.push_back(geom->endPnt); + } break; + case DrawingGeometry::BSPLINE: { + DrawingGeometry::BSpline *geom = static_cast(this); + result.push_back(geom->segments.front().pnts[0]); + DrawingGeometry::BezierSegment tempSeg = geom->segments.back(); + result.push_back(tempSeg.pnts[tempSeg.poles - 1]); + } break; + case DrawingGeometry::GENERIC: { + DrawingGeometry::Generic *geom = static_cast(this); + result.push_back(geom->points.front()); + result.push_back(geom->points.back()); + } break; + default: + break; + } + return result; +} + +Base::Vector2D BaseGeom::getStartPoint() +{ + std::vector verts = findEndPoints(); + return verts[0]; +} + +Base::Vector2D BaseGeom::getEndPoint() +{ + std::vector verts = findEndPoints(); + return verts[1]; +} + +Ellipse::Ellipse() +{ + geomType = ELLIPSE; +} + +Ellipse::Ellipse(const BRepAdaptor_Curve& c) +{ + geomType = ELLIPSE; + + gp_Elips ellp = c.Ellipse(); + const gp_Pnt &p = ellp.Location(); + + center = Base::Vector2D(p.X(), p.Y()); + + major = ellp.MajorRadius(); + minor = ellp.MinorRadius(); + + gp_Dir xaxis = ellp.XAxis().Direction(); + angle = xaxis.AngleWithRef(gp_Dir(1, 0, 0), gp_Dir(0, 0, -1)); +} + +AOE::AOE() +{ + geomType = ARCOFELLIPSE; +} + +AOE::AOE(const BRepAdaptor_Curve& c) : Ellipse(c) +{ + geomType = ARCOFELLIPSE; + + double f = c.FirstParameter(); + double l = c.LastParameter(); + gp_Pnt s = c.Value(f); + gp_Pnt m = c.Value((l+f)/2.0); + gp_Pnt e = c.Value(l); + + gp_Vec v1(m,s); + gp_Vec v2(m,e); + gp_Vec v3(0,0,1); + double a = v3.DotCross(v1,v2); + + startAngle = f; + endAngle = l; + cw = (a < 0) ? true: false; + largeArc = (l-f > M_PI) ? true : false; + + startPnt = Base::Vector2D(s.X(), s.Y()); + endPnt = Base::Vector2D(e.X(), e.Y()); + midPnt = Base::Vector2D(m.X(), m.Y()); + /* + char las = (l-f > D_PI) ? '1' : '0'; // large-arc-flag + char swp = (a < 0) ? '1' : '0'; // sweep-flag, i.e. clockwise (0) or counter-clockwise (1) + out << "" << std::endl; +// if (startAngle > endAngle) {// if arc is reversed +// std::swap(startAngle, endAngle); +// }*/ + +// double ax = s.X() - center.fX; +// double ay = s.Y() - center.fY; +// double bx = e.X() - center.fX; +// double by = e.Y() - center.fY; + +// startAngle = f; +// float range = l-f; +// +// endAngle = startAngle + range; +} + +Circle::Circle() +{ + geomType = CIRCLE; +} + +Circle::Circle(const BRepAdaptor_Curve& c) +{ + geomType = CIRCLE; + + gp_Circ circ = c.Circle(); + const gp_Pnt& p = circ.Location(); + + radius = circ.Radius(); + center = Base::Vector2D(p.X(), p.Y()); +} + +AOC::AOC() +{ + geomType = ARCOFCIRCLE; +} + +AOC::AOC(const BRepAdaptor_Curve& c) : Circle(c) +{ + geomType = ARCOFCIRCLE; + + double f = c.FirstParameter(); + double l = c.LastParameter(); + gp_Pnt s = c.Value(f); + gp_Pnt m = c.Value((l+f)/2.0); + gp_Pnt e = c.Value(l); + + gp_Vec v1(m,s); + gp_Vec v2(m,e); + gp_Vec v3(0,0,1); + double a = v3.DotCross(v1,v2); + + startAngle = f; + endAngle = l; + cw = (a < 0) ? true: false; + largeArc = (l-f > M_PI) ? true : false; + + startPnt = Base::Vector2D(s.X(), s.Y()); + endPnt = Base::Vector2D(e.X(), e.Y()); + midPnt = Base::Vector2D(m.X(), m.Y()); +} + +Generic::Generic() +{ + geomType = GENERIC; +} + +Generic::Generic(const BRepAdaptor_Curve& c) +{ + geomType = GENERIC; + + TopLoc_Location location; + Handle_Poly_Polygon3D polygon = BRep_Tool::Polygon3D(c.Edge(), location); + if (!polygon.IsNull()) { + const TColgp_Array1OfPnt &nodes = polygon->Nodes(); + for (int i = nodes.Lower(); i <= nodes.Upper(); i++){ + points.push_back(Base::Vector2D(nodes(i).X(), nodes(i).Y())); + } + } +} + +Generic::Generic(Base::Vector2D start, Base::Vector2D end) +{ + geomType = GENERIC; + points.push_back(start); + points.push_back(end); +} + +BSpline::BSpline() +{ + geomType = BSPLINE; +} + +BSpline::BSpline(const BRepAdaptor_Curve &c) +{ + geomType = BSPLINE; + Handle_Geom_BSplineCurve spline = c.BSpline(); + if (spline->Degree() > 3) { + Standard_Real tol3D = 0.001; + Standard_Integer maxDegree = 3, maxSegment = 10; + Handle_BRepAdaptor_HCurve hCurve = new BRepAdaptor_HCurve(c); + // approximate the curve using a tolerance + //Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C2, maxSegment, maxDegree); //gives degree == 5 ==> too many poles ==> buffer overrun + Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree); + if (approx.IsDone() && approx.HasResult()) { + spline = approx.Curve(); + } else { + throw Base::Exception("Geometry::BSpline - could not approximate curve"); + } + } + + GeomConvert_BSplineCurveToBezierCurve crt(spline); + + BezierSegment tempSegment; + gp_Pnt controlPoint; + + for (Standard_Integer i = 1; i <= crt.NbArcs(); ++i) { + Handle_Geom_BezierCurve bezier = crt.Arc(i); + if (bezier->Degree() > 3) { + throw Base::Exception("Geometry::BSpline - converted curve degree > 3"); + } + tempSegment.poles = bezier->NbPoles(); + // Note: We really only need to keep the pnts[0] for the first Bezier segment, + // assuming this only gets used as in QGIViewPart::drawPainterPath + // ...it also gets used in GeometryObject::calcBoundingBox(), similar note applies + for (int pole = 1; pole <= tempSegment.poles; ++pole) { + controlPoint = bezier->Pole(pole); + tempSegment.pnts[pole - 1] = Base::Vector2D(controlPoint.X(), controlPoint.Y()); + } + segments.push_back(tempSegment); + } +} + +//! can this BSpline be represented by a straight line? +bool BSpline::isLine() +{ + bool result = true; + std::vector::iterator iSeg = segments.begin(); + double slope; + if ((*iSeg).poles == 2) { + slope = ((*iSeg).pnts[1].fY - (*iSeg).pnts[0].fY) / + ((*iSeg).pnts[1].fX - (*iSeg).pnts[0].fX); //always at least 2 points? + } + for (; iSeg != segments.end(); iSeg++) { + if ((*iSeg).poles != 2) { + result = false; + break; + } + double newSlope = ((*iSeg).pnts[1].fY - (*iSeg).pnts[0].fY) / ((*iSeg).pnts[1].fX - (*iSeg).pnts[0].fX); + if (fabs(newSlope - slope) > Precision::Confusion()) { + result = false; + break; + } + } + return result; +} + +//**** DrawingGeometry utility funtions + +extern "C" { +//! return a vector of BaseGeom*'s in tail to nose order +std::vector DrawingExport chainGeoms(std::vector geoms) +{ + std::vector result; + std::vector used(geoms.size(),false); + double tolerance = 0.0; + + if (geoms.empty()) { + return result; + } + + if (geoms.size() == 1) { //don't bother for single geom (circles, ellipses,etc) + result.push_back(geoms[0]); + } else { + result.push_back(geoms[0]); //start with first edge + Base::Vector2D atPoint = (geoms[0])->getEndPoint(); + used[0] = true; + for (unsigned int i = 1; i < geoms.size(); i++) { //do size-1 more edges + getNextReturn next = nextGeom(atPoint,geoms,used,tolerance); + if (next.index) { //found an unused edge with vertex == atPoint + DrawingGeometry::BaseGeom* nextEdge = geoms.at(next.index); + used[next.index] = true; + nextEdge->reversed = next.reversed; + result.push_back(nextEdge); + if (next.reversed) { + atPoint = nextEdge->getStartPoint(); + } else { + atPoint = nextEdge->getEndPoint(); + } + } else { + Base::Console().Log("Error - Geometry::chainGeoms - couldn't find next edge\n"); + //TARFU + } + } + } + return result; +} + +//! find an unused geom starts or ends at atPoint. returns index[1:geoms.size()),reversed [true,false] +getNextReturn DrawingExport nextGeom(Base::Vector2D atPoint, + std::vector geoms, + std::vector used, + double tolerance) +{ + getNextReturn result(0,false); + std::vector::iterator itGeom = geoms.begin(); + for (; itGeom != geoms.end(); itGeom++) { + unsigned int index = itGeom - geoms.begin(); + if (used[index]) { + continue; + } + if (atPoint == (*itGeom)->getStartPoint()) { + result.index = index; + result.reversed = false; + break; + } else if (atPoint == (*itGeom)->getEndPoint()) { + result.index = index; + result.reversed = true; + break; + } + } + return result; +} + +} //end extern C diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h new file mode 100644 index 0000000000..0329a38a03 --- /dev/null +++ b/src/Mod/TechDraw/App/Geometry.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (c) 2012 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef TECHDRAW_GEOMETRY_H +#define TECHDRAW_GEOMETRY_H + +#include +class BRepAdaptor_Curve; + +namespace TechDrawGeometry { + +enum ExtractionType { + Plain = 0, + WithHidden = 1, + WithSmooth = 2 +}; + +enum GeomType { + NOTDEF, + CIRCLE, + ARCOFCIRCLE, + ELLIPSE, + ARCOFELLIPSE, + BSPLINE, + GENERIC +}; + +class DrawingExport BaseGeom +{ +public: + BaseGeom(); + ~BaseGeom() {} +public: + GeomType geomType; + ExtractionType extractType; + bool reversed; + std::vector findEndPoints(); + Base::Vector2D getStartPoint(); + Base::Vector2D getEndPoint(); +}; + +class DrawingExport Circle: public BaseGeom +{ +public: + Circle(const BRepAdaptor_Curve &c); + Circle(); + ~Circle() {} +public: + Base::Vector2D center; + double radius; +}; + +class DrawingExport Ellipse: public BaseGeom +{ +public: + Ellipse(const BRepAdaptor_Curve &c); + Ellipse(); + ~Ellipse() {} +public: + Base::Vector2D center; + double minor; + double major; + /// Angle between the major axis of the ellipse and the X axis, in radian + double angle; +}; + +class DrawingExport AOE: public Ellipse +{ +public: + AOE(const BRepAdaptor_Curve &c); + AOE(); + ~AOE() {} +public: + Base::Vector2D startPnt; //TODO: The points are used for drawing, the angles for bounding box calcs - seems redundant + Base::Vector2D endPnt; + Base::Vector2D midPnt; + /// Angle in radian + double startAngle; + /// Angle in radian + double endAngle; + /// Arc is drawn clockwise from startAngle to endAngle if true, counterclockwise if false + bool cw; + bool largeArc; +}; + +class DrawingExport AOC: public Circle +{ +public: + AOC(const BRepAdaptor_Curve &c); + AOC(); + ~AOC() {} +public: + Base::Vector2D startPnt; + Base::Vector2D endPnt; + Base::Vector2D midPnt; + /// Angle in radian + double startAngle; + /// Angle in radian + double endAngle; + /// Arc is drawn clockwise from startAngle to endAngle if true, counterclockwise if false + bool cw; // TODO: Instead of this (and similar one in AOE), why not reorder startAngle and endAngle? + bool largeArc; +}; + +/// Handles degree 1 to 3 Bezier segments +/*! + * \todo extend this to higher orders if necessary + */ +struct BezierSegment +{ + /// Number of entries in pnts that are valid + int poles; + /// Control points for this segment + /*! + * Note that first and last used points define the endpoints for this + * segment, so when we know that a sequence of BezierSegment objects are + * going to be strung together, then we only need to know the start of + * the first element (or the end of the last element). + */ + Base::Vector2D pnts[4]; +}; + +class DrawingExport BSpline: public BaseGeom +{ +public: + BSpline(const BRepAdaptor_Curve &c); + BSpline(); + ~BSpline(){} +public: + bool isLine(void); + std::vector segments; +}; + +class Generic: public BaseGeom +{ +public: + Generic(Base::Vector2D start, Base::Vector2D end); + Generic(const BRepAdaptor_Curve& c); + Generic(); + ~Generic() {} + std::vector points; + +}; + +/// Simple Collection of geometric features based on BaseGeom inherited classes in order +struct DrawingExport Wire +{ + Wire(); + ~Wire(); + std::vector geoms; +}; + +/// Simple Collection of geometric features based on BaseGeom inherited classes in order +struct DrawingExport Face +{ + Face(); + ~Face(); + std::vector wires; +}; + +/// Simple vertex +struct DrawingExport Vertex +{ + Vertex(double x, double y) { pnt = Base::Vector2D(x, y); } + Vertex(Base::Vector2D v) { pnt = v; } + ~Vertex() {} + Base::Vector2D pnt; + ExtractionType extractType; +}; + +//*** utility functions +extern "C" { + +struct DrawingExport getNextReturn { + unsigned int index; + bool reversed; + explicit getNextReturn(int i = 0, bool r = false) : + index(i), + reversed(r) + {} +}; + +std::vector chainGeoms(std::vector geoms); +getNextReturn nextGeom(Base::Vector2D atPoint, + std::vector geoms, + std::vector used, + double tolerance); + +} //end extern "C" +} //end namespace TechDrawGeometry + +#endif //TECHDRAW_GEOMETRY_H diff --git a/src/Mod/TechDraw/App/GeometryObject.cpp b/src/Mod/TechDraw/App/GeometryObject.cpp new file mode 100644 index 0000000000..e210af3e90 --- /dev/null +++ b/src/Mod/TechDraw/App/GeometryObject.cpp @@ -0,0 +1,1455 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 +# include +# include +# include +# include +# include +# include + +# include +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include + +# include +# include + +// # include +# include + +# include +# include +# include +# include +# include +# include +# include + +#include +#endif // #ifndef _PreComp_ + +#include + +# include +# include +# include +# include + +# include + +# include "GeometryObject.h" + +//#include + +using namespace TechDrawGeometry; + +struct EdgePoints { + gp_Pnt v1, v2; + TopoDS_Edge edge; +}; + +GeometryObject::GeometryObject() : brep_hlr(0), Tolerance(0.05f), Scale(1.f) +{ +} + +GeometryObject::~GeometryObject() +{ + clear(); +} + +void GeometryObject::setTolerance(double value) +{ + Tolerance = value; +} + +void GeometryObject::setScale(double value) +{ + Scale = value; +} + +void GeometryObject::clear() +{ + + for(std::vector::iterator it = edgeGeom.begin(); it != edgeGeom.end(); ++it) { + delete *it; + *it = 0; + } + + for(std::vector::iterator it = faceGeom.begin(); it != faceGeom.end(); ++it) { + delete *it; + *it = 0; + } + + for(std::vector::iterator it = vertexGeom.begin(); it != vertexGeom.end(); ++it) { + delete *it; + *it = 0; + } + + vertexGeom.clear(); + vertexReferences.clear(); + + faceGeom.clear(); + faceReferences.clear(); + + edgeGeom.clear(); + edgeReferences.clear(); +} + +void GeometryObject::drawFace (const bool visible, const int iface, + Handle_HLRBRep_Data & DS, + TopoDS_Shape& Result) const +{ +// add all the edges for this face(iface) to Result + HLRBRep_FaceIterator Itf; + + for (Itf.InitEdge(DS->FDataArray().ChangeValue(iface)); Itf.MoreEdge(); Itf.NextEdge()) { + int ie = Itf.Edge(); + // if (std::find(used.begin(),used.end(),ie) == used.end()) { //only use an edge once + HLRBRep_EdgeData& edf = DS->EDataArray().ChangeValue(ie); + if(edf.Status().NbVisiblePart() > 0) { + drawEdge(edf, Result, visible); + } +// double first = edf.Geometry().FirstParameter(); +// double last = edf.Geometry().LastParameter(); +// gp_Pnt p0 = edf.Geometry().Value3D(first); +// gp_Pnt p1 = edf.Geometry().Value3D(last); +// qDebug()< &projFaces) const +{ + if(face.IsNull()) + throw Base::Exception("Projected shape is null"); + + gp_Pnt supportCentre = findCentroid(support, direction, xaxis); + + // TODO: We used to invert Y twice here, make sure that wasn't intentional + gp_Trsf mat; + mat.SetMirror(gp_Ax2(supportCentre, gp_Dir(0, 1, 0))); + gp_Trsf matScale; + matScale.SetScale(supportCentre, Scale); + mat.Multiply(matScale); + + BRepBuilderAPI_Transform mkTrfScale(face, mat); + + gp_Ax2 transform; + transform = gp_Ax2(supportCentre, + gp_Dir(direction.x, direction.y, direction.z), + gp_Dir(xaxis.x, xaxis.y, xaxis.z)); + + HLRBRep_Algo *brep_hlr = new HLRBRep_Algo(); + brep_hlr->Add(mkTrfScale.Shape()); + + HLRAlgo_Projector projector( transform ); + brep_hlr->Projector(projector); + brep_hlr->Update(); + brep_hlr->Hide(); + + Base::Console().Log("GeometryObject::projectSurfaces - projecting face\n"); + + // Extract Faces + std::vector projFaceRefs; + + extractFaces(brep_hlr, mkTrfScale.Shape(), true, WithSmooth, projFaces, projFaceRefs); + delete brep_hlr; +} + +Base::BoundBox3d GeometryObject::boundingBoxOfBspline(const BSpline *spline) const +{ + Base::BoundBox3d bb; + for (std::vector::const_iterator segItr( spline->segments.begin() ); + segItr != spline->segments.end(); ++segItr) { + switch (segItr->poles) { + case 0: // Degenerate, but safe ignore + break; + case 2: // Degenerate - straight line + bb.Add(Base::Vector3d( segItr->pnts[1].fX, + segItr->pnts[1].fY, + 0 )); + // fall through + case 1: // Degenerate - just a point + bb.Add(Base::Vector3d( segItr->pnts[0].fX, + segItr->pnts[0].fY, + 0 )); + break; + case 3: { + double + px[3] = { segItr->pnts[0].fX, + segItr->pnts[1].fX, + segItr->pnts[2].fX }, + py[3] = { segItr->pnts[0].fY, + segItr->pnts[1].fY, + segItr->pnts[2].fY }, + slns[4] = { 0, 1 }; // Consider the segment's end points + + // if's are to prevent problems with divide-by-0 + if ((2 * px[1] - px[0] - px[2]) == 0) { + slns[2] = -1; + } else { + slns[2] = (px[1] - px[0]) / (2 * px[1] - px[0] - px[2]); + } + if ((2 * py[1] - py[0] - py[2]) == 0) { + slns[3] = -1; + } else { + slns[3] = (py[1] - py[0]) / (2 * py[1] - py[0] - py[2]); + } + + // evaluate B(t) at the endpoints and zeros + for (int s(0); s < 4; ++s) { + double t( slns[s] ); + if (t < 0 || t > 1) { + continue; + } + double tx( px[0] * (1 - t) * (1 - t) + + px[1] * 2 * (1 - t) * t + + px[2] * t * t ), + ty( py[0] * (1 - t) * (1 - t) + + py[1] * 2 * (1 - t) * t + + py[2] * t * t ); + bb.Add( Base::Vector3d(tx, ty, 0) ); + } + } break; + case 4: { + double + px[4] = { segItr->pnts[0].fX, + segItr->pnts[1].fX, + segItr->pnts[2].fX, + segItr->pnts[3].fX }, + py[4] = { segItr->pnts[0].fY, + segItr->pnts[1].fY, + segItr->pnts[2].fY, + segItr->pnts[3].fY }, + // If B(t) is the cubic Bezier, find t where B'(t) == 0 + // + // For control points P0-P3, B'(t) works out to be: + // B'(t) = t^2 * (-3P0 + 9P1 - 9P2 + 3P3) + + // t * (6P0 - 12P1 + 6P2) + + // 3 * (P1 - P0) + // + // So, we use the quadratic formula! + ax = -3 * px[0] + 9 * px[1] - 9 * px[2] + 3 * px[3], + ay = -3 * py[0] + 9 * py[1] - 9 * py[2] + 3 * py[3], + bx = 6 * px[0] - 12 * px[1] + 6 * px[2], + by = 6 * py[0] - 12 * py[1] + 6 * py[2], + cx = 3 * px[1] - 3 * px[0], + cy = 3 * py[1] - 3 * py[0], + + slns[6] = { 0, 1 }; // Consider the segment's end points + + // if's are to prevent problems with divide-by-0 and NaN + if ( (2 * ax) == 0 || (bx * bx - 4 * ax * cx) < 0 ) { + slns[2] = -1; + slns[3] = -1; + } else { + slns[2] = (-bx + sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); + slns[3] = (-bx - sqrt(bx * bx - 4 * ax * cx)) / (2 * ax); + } + if ((2 * ay) == 0 || (by * by - 4 * ay * cy) < 0 ) { + slns[4] = -1; + slns[5] = -1; + } else { + slns[4] = (-by + sqrt(by * by - 4 * ay * cy)) / (2 * ay); + slns[5] = (-by - sqrt(by * by - 4 * ay * cy)) / (2 * ay); + } + + // evaluate B(t) at the endpoints and zeros + for (int s(0); s < 6; ++s) { + double t( slns[s] ); + if (t < 0 || t > 1) { + continue; + } + double tx( px[0] * (1 - t) * (1 - t) * (1 - t) + + px[1] * 3 * (1 - t) * (1 - t) * t + + px[2] * 3 * (1 - t) * t * t + + px[3] * t * t * t ), + ty( py[0] * (1 - t) * (1 - t) * (1 - t) + + py[1] * 3 * (1 - t) * (1 - t) * t + + py[2] * 3 * (1 - t) * t * t + + py[3] * t * t * t ); + bb.Add( Base::Vector3d(tx, ty, 0) ); + } + + } break; + default: + throw Base::Exception("Invalid degree bezier segment in GeometryObject::calcBoundingBox"); + } + } + return bb; +} + +Base::BoundBox3d GeometryObject::boundingBoxOfAoe(const Ellipse *aoe, + double start, + double end, bool cw) const +{ + // Using the ellipse form: + // (xc, yc) = centre of ellipse + // phi = angle of ellipse major axis off X axis + // a, b = half of major, minor axes + // + // x(theta) = xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi) + // y(theta) = yc + a*cos(theta)*sin(phi) + b*sin(theta)*cos(phi) + + double a (aoe->major / 2.0), + b (aoe->minor / 2.0), + phi (aoe->angle), + xc (aoe->center.fX), + yc (aoe->center.fY); + + if (a == 0 || b == 0) { + // Degenerate case - TODO: handle as line instead of throwing + throw Base::Exception("Ellipse with invalid major axis in GeometryObject::boundingBoxOfAoe()"); + } + + // Calculate points of interest for the bounding box. These are points + // where d(x)/d(theta) and d(y)/d(theta) = 0 (where the x and y extremes + // of the ellipse would be if it were complete), and arc endpoints. + double testAngles[6] = { atan(tan(phi) * (-b / a)), + testAngles[0] + M_PI }; + if (tan(phi) == 0) { + testAngles[2] = M_PI / 2.0; + testAngles[3] = 3.0 * M_PI / 2.0; + } else { + testAngles[2] = atan((1.0 / tan(phi)) * (b / a)); + testAngles[3] = testAngles[2] + M_PI; + } + testAngles[4] = start; + testAngles[5] = end; + + // Add extremes to bounding box, if they are within the arc + Base::BoundBox3d bb; + for (int ai(0); ai < 6; ++ai) { + double theta(testAngles[ai]); + if (isWithinArc(theta, start, end, cw) ) { + bb.Add( Base::Vector3d(xc + a*cos(theta)*cos(phi) - b*sin(theta)*sin(phi), + yc + a*cos(theta)*sin(phi) - b*sin(theta)*cos(phi), + 0) ); + } + } + + return bb; +} + +bool GeometryObject::isWithinArc(double theta, double first, + double last, bool cw) const +{ + if (fabs(last - first) >= 2 * M_PI) { + return true; + } + + // Put params within [0, 2*pi) - not totally sure this is necessary + theta = fmod(theta, 2 * M_PI); + if (theta < 0) { + theta += 2 * M_PI; + } + + first = fmod(first, 2 * M_PI); + if (first < 0) { + first += 2 * M_PI; + } + + last = fmod(last, 2 * M_PI); + if (last < 0) { + last += 2 * M_PI; + } + + if (cw) { + if (first > last) { + return theta <= first && theta >= last; + } else { + return theta <= first || theta >= last; + } + } else { + if (first > last) { + return theta >= first || theta <= last; + } else { + return theta >= first && theta <= last; + } + } +} + +Base::BoundBox3d GeometryObject::calcBoundingBox() const +{ + Base::BoundBox3d bbox; + + // First calculate bounding box based on vertices + for(std::vector::const_iterator it( vertexGeom.begin() ); + it != vertexGeom.end(); ++it) { + bbox.Add( Base::Vector3d((*it)->pnt.fX, (*it)->pnt.fY, 0.) ); + } + + // Now, consider geometry where vertices don't define bounding box eg circles + for (std::vector::const_iterator it( edgeGeom.begin() ); + it != edgeGeom.end(); ++it) { + switch ((*it)->geomType) { + case CIRCLE: { + Circle *c = static_cast(*it); + bbox.Add( Base::BoundBox3d(-c->radius + c->center.fX, + -c->radius + c->center.fY, + 0, + c->radius + c->center.fX, + c->radius + c->center.fY, + 0) ); + } break; + + case ARCOFCIRCLE: { + AOC *arc = static_cast(*it); + + // Endpoints of arc + bbox.Add( Base::Vector3d(arc->radius * cos(arc->startAngle), + arc->radius * sin(arc->startAngle), + 0.0) ); + bbox.Add( Base::Vector3d(arc->radius * cos(arc->endAngle), + arc->radius * sin(arc->endAngle), + 0.0) ); + + // Extreme X and Y values if they're within the arc + for (double theta = 0.0; theta < 6.5; theta += M_PI / 2.0) { + if (isWithinArc(theta, arc->startAngle, arc->endAngle, arc->cw)) { + bbox.Add( Base::Vector3d(arc->radius * cos(theta), + arc->radius * sin(theta), + 0.0) ); + } + } + } break; + + case ELLIPSE: { + bbox.Add( boundingBoxOfAoe(static_cast(*it)) ); + } break; + + case ARCOFELLIPSE: { + AOE *aoe = static_cast(*it); + double start = aoe->startAngle, + end = aoe->endAngle; + bool cw = aoe->cw; + bbox.Add( boundingBoxOfAoe(static_cast(*it), start, end, cw) ); + } break; + + case BSPLINE: { + bbox.Add( boundingBoxOfBspline(static_cast(*it)) ); + } break; + + case GENERIC: { + // this case ends up just drawing line segments between points + Generic *gen = static_cast(*it); + for (std::vector::const_iterator segIt = gen->points.begin(); + segIt != gen->points.end(); ++segIt) { + bbox.Add( Base::Vector3d(segIt->fX, segIt->fY, 0) ); + } + } break; + + default: + throw Base::Exception("Unknown geomType in GeometryObject::calcBoundingBox()"); + } + } + return bbox; +} + +//! only ever called from fvp::getCompleteEdge +DrawingGeometry::BaseGeom * GeometryObject::projectEdge(const TopoDS_Shape &edge, + const TopoDS_Shape &support, + const Base::Vector3d &direction, + const Base::Vector3d &projXAxis) const +{ + if(edge.IsNull()) + throw Base::Exception("Projected edge is null"); + // Invert y function using support to calculate bounding box + + gp_Pnt supportCentre = findCentroid(support, direction, projXAxis); + + gp_Trsf mat; + mat.SetMirror(gp_Ax2(supportCentre, gp_Dir(0, 1, 0))); + gp_Trsf matScale; + matScale.SetScale(supportCentre, Scale); + mat.Multiply(matScale); + BRepBuilderAPI_Transform mkTrfScale(edge, mat); + + const TopoDS_Edge &refEdge = TopoDS::Edge(mkTrfScale.Shape()); + + gp_Ax2 transform; + transform = gp_Ax2(supportCentre, + gp_Dir(direction.x, direction.y, direction.z), + gp_Dir(projXAxis.x, projXAxis.y, projXAxis.z)); + + BRepAdaptor_Curve refCurve(refEdge); + HLRAlgo_Projector projector = HLRAlgo_Projector( transform ); + projector.Scaled(true); + + if (refCurve.GetType() == GeomAbs_Line) { + // Use the simpler algorithm for lines + gp_Pnt p1 = refCurve.Value(refCurve.FirstParameter()); + gp_Pnt p2 = refCurve.Value(refCurve.LastParameter()); + + // Project the points + gp_Pnt2d pnt1, pnt2; + projector.Project(p1, pnt1); + projector.Project(p2, pnt2); + + DrawingGeometry::Generic *line = new DrawingGeometry::Generic(); + + line->points.push_back(Base::Vector2D(pnt1.X(), pnt1.Y())); + line->points.push_back(Base::Vector2D(pnt2.X(), pnt2.Y())); + + return line; + + } else { + + HLRBRep_Curve curve; + curve.Curve(refEdge); + + curve.Projector(&projector); + + DrawingGeometry::BaseGeom *result = 0; + switch(HLRBRep_BCurveTool::GetType(curve.Curve())) + { + case GeomAbs_Line: { + DrawingGeometry::Generic *line = new DrawingGeometry::Generic(); + + gp_Pnt2d pnt1 = curve.Value(curve.FirstParameter()); + gp_Pnt2d pnt2 = curve.Value(curve.LastParameter()); + + line->points.push_back(Base::Vector2D(pnt1.X(), pnt1.Y())); + line->points.push_back(Base::Vector2D(pnt2.X(), pnt2.Y())); + + result = line; + }break; + case GeomAbs_Circle: { + DrawingGeometry::Circle *circle = new DrawingGeometry::Circle(); + gp_Circ2d prjCirc = curve.Circle(); + + double f = curve.FirstParameter(); + double l = curve.LastParameter(); + gp_Pnt2d s = curve.Value(f); + gp_Pnt2d e = curve.Value(l); + + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + circle->radius = prjCirc.Radius(); + circle->center = Base::Vector2D(prjCirc.Location().X(), prjCirc.Location().Y()); + result = circle; + } else { + AOC *aoc = new AOC(); + aoc->radius = prjCirc.Radius(); + aoc->center = Base::Vector2D(prjCirc.Location().X(), prjCirc.Location().Y()); + double ax = s.X() - aoc->center.fX; + double ay = s.Y() - aoc->center.fY; + double bx = e.X() - aoc->center.fX; + double by = e.Y() - aoc->center.fY; + + aoc->startAngle = atan2(ay,ax); + float range = atan2(-ay*bx+ax*by, ax*bx+ay*by); + + aoc->endAngle = aoc->startAngle + range; + result = aoc; + } + } break; + case GeomAbs_Ellipse: { + gp_Elips2d prjEllipse = curve.Ellipse(); + + double f = curve.FirstParameter(); + double l = curve.LastParameter(); + gp_Pnt2d s = curve.Value(f); + gp_Pnt2d e = curve.Value(l); + + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + Ellipse *ellipse = new Ellipse(); + ellipse->major = prjEllipse.MajorRadius(); + ellipse->minor = prjEllipse.MinorRadius(); + ellipse->center = Base::Vector2D(prjEllipse.Location().X(), + prjEllipse.Location().Y()); + result = ellipse; + // TODO: Finish implementing ellipsey stuff + } else { + // TODO implement this correctly + AOE *aoe = new AOE(); + aoe->major = prjEllipse.MajorRadius(); + aoe->minor = prjEllipse.MinorRadius(); + aoe->center = Base::Vector2D(prjEllipse.Location().X(), + prjEllipse.Location().Y()); + result = aoe; + } + } break; + case GeomAbs_BSplineCurve: { + // TODO: Project BSpline here? + } break; + + default: + break; + } + + return result; + } +} + +/* TODO: Clean this up when faces are actually working properly... +void debugEdge(const TopoDS_Edge &e) +{ + gp_Pnt p0 = BRep_Tool::Pnt(TopExp::FirstVertex(e)); + gp_Pnt p1 = BRep_Tool::Pnt(TopExp::LastVertex(e)); + qDebug()< &projFaces, + std::vector &faceRefs) const +{ +#if MOD_TECHDRAW_HANDLE_FACES + if(!myAlgo) + return; + + Handle_HLRBRep_Data DS = myAlgo->DataStructure(); + if (DS.IsNull()) { + Base::Console().Log("TechDraw::GeometryObject::extractFaces - DS is Null\n"); + return; + } + + DS->Projector().Scaled(true); + + int f1 = 1; + int f2 = DS->NbFaces(); + + /* This block seems to set f1 and f2 to indices using a HLRBRep_ShapeBounds + * object based that's based on myAlgo, but DS is also based on myAlgo too, + * so I don't think this is required. IR + if (!S.IsNull()) { + int e1 = 1; + int e2 = DS->NbEdges(); + + Standard_Integer v1,v2; + Standard_Integer index = myAlgo->Index(S); + if(index == 0) { + Base::Console().Log("TechDraw::GeometryObject::extractFaces - myAlgo->Index(S) == 0\n"); + return; + } + + myAlgo->ShapeBounds(index).Bounds(v1, v2, e1, e2, f1, f2); + } */ + + TopTools_IndexedMapOfShape anfIndices; + TopTools_IndexedMapOfShape& Faces = DS->FaceMap(); + TopExp::MapShapes(S, TopAbs_FACE, anfIndices); + + BRep_Builder B; + + /* ----------------- Extract Faces ------------------ */ + for (int iface = f1; iface <= f2; iface++) { + // Why oh why does Hiding() == true mean that a face is visible... + if (! DS->FDataArray().ChangeValue(iface).Hiding()) { + continue; + } + + TopoDS_Shape face; + B.MakeCompound(TopoDS::Compound(face)); + + // Generate a set of new wires based on face + // TODO: Do these end up with input face's geometry as a base? + drawFace(visible, iface, DS, face); + std::vector possibleFaceWires; + createWire(face, possibleFaceWires); + + DrawingGeometry::Face *myFace = NULL; + + // Process each wire - if we can make at least one face with it, then + // send it down the road toward rendering + for (std::vector::iterator wireIt = possibleFaceWires.begin(); + wireIt != possibleFaceWires.end(); ++wireIt) { + + // Try making a face out of the wire, before doing anything else with it + BRepBuilderAPI_MakeFace testFace(*wireIt); + if (testFace.IsDone()) { + if (myFace == NULL) { + myFace = new DrawingGeometry::Face(); + } + DrawingGeometry::Wire *genWire = new DrawingGeometry::Wire(); + + // See createWire regarding BRepTools_WireExplorer vs TopExp_Explorer + BRepTools_WireExplorer explr(*wireIt); + while (explr.More()) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + builder.Add(comp, explr.Current()); + + calculateGeometry(comp, Plain, genWire->geoms); + explr.Next(); + } + myFace->wires.push_back(genWire); + } + } + + if (myFace != NULL) { + projFaces.push_back(myFace); + } + + // I'm pretty sure this doesn't do what it's intended to do. IR + int idxFace; + for (int i = 1; i <= anfIndices.Extent(); i++) { + idxFace = Faces.FindIndex(anfIndices(iface)); + if (idxFace != 0) { + break; + } + } + + if(idxFace == 0) + idxFace = -1; // If Face not found - select hidden + + // Push the found face index onto references stack + faceRefs.push_back(idxFace); + } + + DS->Projector().Scaled(false); +#endif //#if MOD_TECHDRAW_HANDLE_FACES +} + +bool GeometryObject::shouldDraw(const bool inFace, const int typ, HLRBRep_EdgeData& ed) +{ + bool todraw = false; + if(inFace) + todraw = true; + else if (typ == 3) + todraw = ed.Rg1Line() && !ed.RgNLine(); //smooth + !contour? + else if (typ == 4) + todraw = ed.RgNLine(); //contour? + else + todraw =!ed.Rg1Line(); //!smooth? + + return todraw; +} + +void GeometryObject::extractVerts(HLRBRep_Algo *myAlgo, const TopoDS_Shape &S, HLRBRep_EdgeData& ed, int ie, ExtractionType extractionType) +{ + if(!myAlgo) + return; + + Handle_HLRBRep_Data DS = myAlgo->DataStructure(); + + if (DS.IsNull()) + return; + + DS->Projector().Scaled(true); + + TopTools_IndexedMapOfShape anIndices; + TopTools_IndexedMapOfShape anvIndices; + + TopExp::MapShapes(S, TopAbs_EDGE, anIndices); + TopExp::MapShapes(S, TopAbs_VERTEX, anvIndices); + + // Load the edge + if(ie < 0) { + + } else { + TopoDS_Shape shape = anIndices.FindKey(ie); + TopoDS_Edge edge = TopoDS::Edge(shape); + + // Gather a list of points associated with this curve + std::list edgePoints; + + TopExp_Explorer xp; + xp.Init(edge,TopAbs_VERTEX); + while(xp.More()) { + edgePoints.push_back(xp.Current()); + xp.Next(); + } + for(std::list::const_iterator it = edgePoints.begin(); it != edgePoints.end(); ++it) { + + // Should share topological data structure so can reference + int iv = anvIndices.FindIndex(*it); // Index of the found vertex + + if(iv < 0) + continue; + + // Check if vertex has already been addded + std::vector::iterator vert; + vert = std::find(vertexReferences.begin(), vertexReferences.end(), iv); + + if(vert == vertexReferences.end()) { + + // If the index wasnt found and is unique, the point is projected using the HLR Projector Algorithm + gp_Pnt2d prjPnt; + DS->Projector().Project(BRep_Tool::Pnt(TopoDS::Vertex(*it)), prjPnt); + + // Check if this point lies on a visible section of the projected curve + double sta,end; + float tolsta,tolend; + + // There will be multiple edges that form the total edge so collect these + BRep_Builder B; + TopoDS_Compound comp; + B.MakeCompound(comp); + + TopoDS_Edge E; + HLRAlgo_EdgeIterator It; + + for(It.InitVisible(ed.Status()); It.MoreVisible(); It.NextVisible()) { + It.Visible(sta,tolsta,end,tolend); + + E = HLRBRep::MakeEdge(ed.Geometry(),sta,end); + if (!E.IsNull()) { + B.Add(comp,E); + } + } + + bool vertexVisible = false; + TopExp_Explorer exp; + exp.Init(comp,TopAbs_VERTEX); + while(exp.More()) { + + gp_Pnt pnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current())); + gp_Pnt2d edgePnt(pnt.X(), pnt.Y()); + if(edgePnt.SquareDistance(prjPnt) < Precision::Confusion()) { + vertexVisible = true; + break; + } + exp.Next(); + } + + if(vertexVisible) { + Vertex *myVert = new Vertex(prjPnt.X(), prjPnt.Y()); + vertexGeom.push_back(myVert); + vertexReferences.push_back(iv); + } + } + } + } +} + +void GeometryObject::extractEdges(HLRBRep_Algo *myAlgo, const TopoDS_Shape &S, int type, bool visible, ExtractionType extractionType) +{ + if (!myAlgo) + return; + Handle_HLRBRep_Data DS = myAlgo->DataStructure(); + + if (DS.IsNull()) + return; + + DS->Projector().Scaled(true); + + int e1 = 1; + int e2 = DS->NbEdges(); + int f1 = 1; + int f2 = DS->NbFaces(); + + if (!S.IsNull()) { + int v1,v2; + int index = myAlgo->Index(S); + if(index == 0) { + Base::Console().Log("TechDraw::GeometryObject::extractEdges - myAlgo->Index(S) == 0\n"); + return; + } + myAlgo->ShapeBounds(index).Bounds(v1,v2,e1,e2,f1,f2); + } + + HLRBRep_EdgeData* ed = &(DS->EDataArray().ChangeValue(e1 - 1)); + + // Get map of edges and faces from projected geometry + TopTools_IndexedMapOfShape& Edges = DS->EdgeMap(); + TopTools_IndexedMapOfShape anIndices; + + TopExp::MapShapes(S, TopAbs_EDGE, anIndices); + + for (int j = e1; j <= e2; j++) { + ed++; + if (ed->Selected() && !ed->Vertical()) { + ed->Used(false); + ed->HideCount(0); + + } else { + ed->Used(true); + } + } + + BRep_Builder B; + + std::list notFound; + /* ----------------- Extract Edges ------------------ */ + for (int i = 1; i <= anIndices.Extent(); i++) { + int ie = Edges.FindIndex(anIndices(i)); + if (ie != 0) { + + HLRBRep_EdgeData& ed = DS->EDataArray().ChangeValue(ie); + if(!ed.Used()) { + if(true) { + + TopoDS_Shape result; + B.MakeCompound(TopoDS::Compound(result)); + + drawEdge(ed, result, visible); + + // Extract and Project Vertices for current Edge + extractVerts(myAlgo, S, ed, i, extractionType); + + int edgesAdded = calculateGeometry(result, extractionType, edgeGeom); + + // Push the edge references + while(edgesAdded--) + edgeReferences.push_back(i); + } + + ed.Used(Standard_True); + } + } else { + notFound.push_back(i); + } + } + + + + // Add any remaining edges that couldn't be found + int edgeIdx = -1; // Negative index for edge references + for (int ie = e1; ie <= e2; ie++) { + // Co + HLRBRep_EdgeData& ed = DS->EDataArray().ChangeValue(ie); + if (!ed.Used()) { + if(shouldDraw(false, type, ed)) { + const TopoDS_Shape &shp = Edges.FindKey(ie); + + //Compares original shape to see if match + if(!shp.IsNull()) { + const TopoDS_Edge& edge = TopoDS::Edge(shp); + BRepAdaptor_Curve adapt1(edge); + for (std::list::iterator it= notFound.begin(); it!= notFound.end(); ++it){ + BRepAdaptor_Curve adapt2(TopoDS::Edge(anIndices(*it))); + if(isSameCurve(adapt1, adapt2)) { + edgeIdx = *it; +// notFound.erase(it); + break; + } + } + } + + TopoDS_Shape result; + B.MakeCompound(TopoDS::Compound(result)); + + drawEdge(ed, result, visible); + int edgesAdded = calculateGeometry(result, extractionType, edgeGeom); + + // Push the edge references + while(edgesAdded--) + edgeReferences.push_back(edgeIdx); + } + ed.Used(true); + } + } + + DS->Projector().Scaled(false); +} + +/** + * Note projected edges are broken up so start and end parameters differ. + */ +bool GeometryObject::isSameCurve(const BRepAdaptor_Curve &c1, const BRepAdaptor_Curve &c2) const +{ + + + if(c1.GetType() != c2.GetType()) + return false; +#if 0 + const gp_Pnt& p1S = c1.Value(c1.FirstParameter()); + const gp_Pnt& p1E = c1.Value(c1.LastParameter()); + + const gp_Pnt& p2S = c2.Value(c2.FirstParameter()); + const gp_Pnt& p2E = c2.Value(c2.LastParameter()); + + bool state = (p1S.IsEqual(p2S, Precision::Confusion()) && p1E.IsEqual(p2E, Precision::Confusion())); + + if( s || + (p1S.IsEqual(p2E, Precision::Confusion()) && p1E.IsEqual(p2S, Precision::Confusion())) ){ + switch(c1.GetType()) { + case GeomAbs_Circle: { + + gp_Circ circ1 = c1.Circle(); + gp_Circ circ2 = c2.Circle(); + + const gp_Pnt& p = circ1.Location(); + const gp_Pnt& p2 = circ2.Location(); + + double radius1 = circ1.Radius(); + double radius2 = circ2.Radius(); + double f1 = c1.FirstParameter(); + double f2 = c2.FirstParameter(); + double l1 = c1.LastParameter(); + double l2 = c2.LastParameter(); + c1.Curve().Curve()-> + if( p.IsEqual(p2,Precision::Confusion()) && + radius2 - radius1 < Precision::Confusion()) { + return true; + } + } break; + default: break; + } + } +#endif + return false; +} + +//only used by extractFaces +void GeometryObject::createWire(const TopoDS_Shape &input, + std::vector &wiresOut) const +{ + //input is a compound of edges? there is edgesToWire logic in Part? + if (input.IsNull()) { + Base::Console().Log("TechDraw::GeometryObject::createWire input is NULL\n"); + return; // There is no OpenCascade Geometry to be calculated + } + + std::list edgeList; + + // make a list of all the edges in the input shape + TopExp_Explorer edges(input, TopAbs_EDGE); + while (edges.More()) { + edgeList.push_back(TopoDS::Edge(edges.Current())); + edges.Next(); + } + // Combine connected edges into wires. + + // BRepBuilderAPI_MakeWire has an annoying behaviour where the only [sane] + // way to test whether an edge connects to a wire is to attempt adding + // the edge. But, if the last added edge was not connected to the wire, + // BRepBuilderAPI_MakeWire::Wire() will throw an exception. So, we need + // to hang on to the last successfully added edge to "reset" scapegoat. + // + // ...and why do we need scapegoat? Because the resetting adds a duplicate + // edge (which can be problematic down the road), but it's not easy to + // remove the edge from the BRepBuilderAPI_MakeWire. + bool lastAddFailed; + TopoDS_Edge lastGoodAdd; + + while (edgeList.size() > 0) { + // add and erase first edge + BRepBuilderAPI_MakeWire scapegoat, mkWire; + scapegoat.Add(edgeList.front()); + mkWire.Add(edgeList.front()); + lastAddFailed = false; + lastGoodAdd = edgeList.front(); + edgeList.pop_front(); + + // try to connect remaining edges to the wire, the wire is complete if no more egdes are connectible + bool found; + do { + found = false; + for (std::list::iterator pE = edgeList.begin(); pE != edgeList.end(); ++pE) { + // Try adding edge - this doesn't necessarily add it + scapegoat.Add(*pE); + if (scapegoat.Error() != BRepBuilderAPI_DisconnectedWire) { + mkWire.Add(*pE); + // Edge added! Remember it, so we can reset scapegoat + lastAddFailed = false; + lastGoodAdd = *pE; + + // ...remove it from edgeList, + edgeList.erase(pE); + + // ...and start searching for the next edge + found = true; + break; //exit for loop + } else { + lastAddFailed = true; + } + } + } while (found); + + // See note above re: BRepBuilderAPI_MakeWire annoying behaviour + if (lastAddFailed) { + scapegoat.Add(lastGoodAdd); + } + + if (scapegoat.Error() == BRepBuilderAPI_WireDone) { + // BRepTools_WireExplorer finds 1st n connected edges, while + // TopExp_Explorer finds all edges. Since we built mkWire using + // TopExp_Explorer, and want to run BRepTools_WireExplorer over + // it, we need to reorder the wire. + ShapeFix_Wire fix; + fix.Load(mkWire.Wire()); + fix.FixReorder(); + fix.Perform(); + + wiresOut.push_back(fix.Wire()); + } else if(scapegoat.Error() == BRepBuilderAPI_DisconnectedWire) { + Standard_Failure::Raise("Fatal error occurred in GeometryObject::createWire()"); + } + } +} + +gp_Pnt GeometryObject::findCentroid(const TopoDS_Shape &shape, + const Base::Vector3d &direction, + const Base::Vector3d &xAxis) const +{ + gp_Ax2 viewAxis; + viewAxis = gp_Ax2(gp_Pnt(0, 0, 0), + gp_Dir(direction.x, -direction.y, direction.z), + gp_Dir(xAxis.x, -xAxis.y, xAxis.z)); // Y invert warning! + + gp_Trsf tempTransform; + tempTransform.SetTransformation(viewAxis); + BRepBuilderAPI_Transform builder(shape, tempTransform); + + Bnd_Box tBounds; + BRepBndLib::Add(builder.Shape(), tBounds); + + tBounds.SetGap(0.0); + Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; + tBounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); + + Standard_Real x = (xMin + xMax) / 2.0, + y = (yMin + yMax) / 2.0, + z = (zMin + zMax) / 2.0; + + // Get centroid back into object space + tempTransform.Inverted().Transforms(x, y, z); + + return gp_Pnt(x, y, z); +} + +void GeometryObject::extractGeometry(const TopoDS_Shape &input, + const Base::Vector3d &direction, + bool extractHidden, + const Base::Vector3d &xAxis) +{ + // Clear previous Geometry and References that may have been stored + clear(); + + ///TODO: Consider whether it would be possible/beneficial to cache some of this effort (eg don't do scale in OpenCASCADE land) IR + TopoDS_Shape transShape; + HLRBRep_Algo *brep_hlr = NULL; + gp_Pnt inputCentre; + try { + inputCentre = findCentroid(input, direction, xAxis); + } + catch (...) { + Base::Console().Log("GeometryObject::extractGeometry - findCentroid failed.\n"); + return; + } + try { + // Make tempTransform scale the object around it's centre point and + // mirror about the Y axis + gp_Trsf tempTransform; + tempTransform.SetScale(inputCentre, Scale); + gp_Trsf mirrorTransform; + mirrorTransform.SetMirror( gp_Ax2(inputCentre, gp_Dir(0, 1, 0)) ); + tempTransform.Multiply(mirrorTransform); + + // Apply that transform to the shape. This should preserve the centre. + BRepBuilderAPI_Transform mkTrf(input, tempTransform); + transShape = mkTrf.Shape(); + + brep_hlr = new HLRBRep_Algo(); + brep_hlr->Add(transShape); + + // Project the shape into view space with the object's centroid + // at the origin. + gp_Ax2 viewAxis; + viewAxis = gp_Ax2(inputCentre, + gp_Dir(direction.x, direction.y, direction.z), + gp_Dir(xAxis.x, xAxis.y, xAxis.z)); + HLRAlgo_Projector projector( viewAxis ); + brep_hlr->Projector(projector); + brep_hlr->Update(); + brep_hlr->Hide(); + + } + catch (...) { + Standard_Failure::Raise("GeometryObject::extractGeometry - error occurred while projecting shape"); + } + + // extracting the result sets: + + //TODO: What is this? IR + // need HLRBRep_HLRToShape aHLRToShape(shapes); + // then TopoDS_Shape V = shapes.VCompound(); //V is a compound of edges + // V = shapes.VCompound ();// hard edge visibly - real edges in original shape + // V1 = shapes.Rg1LineVCompound();// Smoth edges visibly - "transition edges between two surfaces" + // VN = shapes.RgNLineVCompound();// contour edges visibly - "sewn edges"? + // VO = shapes.OutLineVCompound();// contours apparents visibly - ?edge in projection but not in original shape? + // VI = shapes.IsoLineVCompound();// isoparamtriques visibly - ?constant u,v sort of like lat/long + // H = shapes.HCompound ();// hard edge invisibly + // H1 = shapes.Rg1LineHCompound();// Smoth edges invisibly + // HN = shapes.RgNLineHCompound();// contour edges invisibly + // HO = shapes.OutLineHCompound();// contours apparents invisibly + // HI = shapes.IsoLineHCompound();// isoparamtriques invisibly + + // Extract Hidden Edges + if(extractHidden) + extractEdges(brep_hlr, transShape, 5, false, WithHidden);// Hard Edge +// calculateGeometry(extractCompound(brep_hlr, invertShape, 2, false), WithHidden); // Outline +// calculateGeometry(extractCompound(brep_hlr, invertShape, 3, false), (ExtractionType)(WithSmooth | WithHidden)); // Smooth + + // Extract Visible Edges + extractEdges(brep_hlr, transShape, 5, true, WithSmooth); // Hard Edge + + //get endpoints of visible projected edges and add to vertexGeom with ref = -1 + //this could get slow for big models? + const std::vector &edgeGeom = getEdgeGeometry(); + std::vector::const_iterator iEdge = edgeGeom.begin(); + for (; iEdge != edgeGeom.end(); iEdge++) { + if ((*iEdge)->extractType == DrawingGeometry::WithHidden) { //only use visible edges + continue; + } + std::vector ends = (*iEdge)->findEndPoints(); + if (!ends.empty()) { + if (!findVertex(ends[0])) { + Vertex* v0 = new Vertex(ends[0]); + v0->extractType = DrawingGeometry::Plain; + vertexGeom.push_back(v0); + vertexReferences.push_back(-1); + } + if (!findVertex(ends[1])) { + Vertex* v1 = new Vertex(ends[1]); + v1->extractType = DrawingGeometry::Plain; + vertexGeom.push_back(v1); + vertexReferences.push_back(-1); + } + } + } + +// calculateGeometry(extractCompound(brep_hlr, invertShape, 2, true), Plain); // Outline +// calculateGeometry(extractCompound(brep_hlr, invertShape, 3, true), WithSmooth); // Smooth Edge + + // Extract Faces + //algorithm,shape,visible/hidden,smooth edges(show flat/curve transition,facewires,index of face in shape? + extractFaces(brep_hlr, transShape, true, WithSmooth, faceGeom, faceReferences); + + // House Keeping + delete brep_hlr; +} + +//translate all the edges in "input" into BaseGeoms +int GeometryObject::calculateGeometry(const TopoDS_Shape &input, + const ExtractionType extractionType, + std::vector &geom) const +{ + if(input.IsNull()) { + Base::Console().Log("TechDraw::GeometryObject::calculateGeometry input is NULL\n"); + return 0; // There is no OpenCascade Geometry to be calculated + } + + // build a mesh to explore the shape + //BRepMesh::Mesh(input, Tolerance); //OCC has removed BRepMesh::Mesh() as of v6.8.0.oce-0.17-dev + BRepMesh_IncrementalMesh(input, Tolerance); //making a mesh turns edges into multilines? + + int geomsAdded = 0; + + // Explore all edges of input and calculate base geometry representation + TopExp_Explorer edges(input, TopAbs_EDGE); + for (int i = 1 ; edges.More(); edges.Next(),i++) { + const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); + BRepAdaptor_Curve adapt(edge); + + switch(adapt.GetType()) { + case GeomAbs_Circle: { + double f = adapt.FirstParameter(); + double l = adapt.LastParameter(); + gp_Pnt s = adapt.Value(f); + gp_Pnt e = adapt.Value(l); + + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + Circle *circle = new Circle(adapt); + circle->extractType = extractionType; + geom.push_back(circle); + } else { + AOC *aoc = new AOC(adapt); + aoc->extractType = extractionType; + geom.push_back(aoc); + } + } break; + case GeomAbs_Ellipse: { + double f = adapt.FirstParameter(); + double l = adapt.LastParameter(); + gp_Pnt s = adapt.Value(f); + gp_Pnt e = adapt.Value(l); + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + Ellipse *ellipse = new Ellipse(adapt); + ellipse->extractType = extractionType; + geom.push_back(ellipse); + } else { + AOE *aoe = new AOE(adapt); + aoe->extractType = extractionType; + geom.push_back(aoe); + } + } break; + case GeomAbs_BSplineCurve: { + BSpline *bspline = 0; + Generic* gen = NULL; + try { + bspline = new BSpline(adapt); + bspline->extractType = extractionType; + if (bspline->isLine()) { + Base::Vector2D start,end; + start = bspline->segments.front().pnts[0]; + end = bspline->segments.back().pnts[1]; + gen = new Generic(start,end); + gen->extractType = extractionType; + geom.push_back(gen); + delete bspline; + } else { + geom.push_back(bspline); + } + break; + } + catch (Standard_Failure) { + delete bspline; + delete gen; + bspline = 0; + // Move onto generating a primitive + } + } + default: { + Generic *primitive = new Generic(adapt); + primitive->extractType = extractionType; + geom.push_back(primitive); + } break; + } + geomsAdded++; + } + return geomsAdded; +} + +//! does this GeometryObject already have this vertex +bool GeometryObject::findVertex(Base::Vector2D v) +{ + bool found = false; + std::vector::iterator it = vertexGeom.begin(); + for (; it != vertexGeom.end(); it++) { + double dist = (v - (*it)->pnt).Length(); + if (dist < Precision::Confusion()) { + found = true; + break; + } + } + return found; +} diff --git a/src/Mod/TechDraw/App/GeometryObject.h b/src/Mod/TechDraw/App/GeometryObject.h new file mode 100644 index 0000000000..26b974dc91 --- /dev/null +++ b/src/Mod/TechDraw/App/GeometryObject.h @@ -0,0 +1,163 @@ +/*************************************************************************** + * Copyright (c) 2013 Luke Parry * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _TECHDRAW_GEOMETRYOBJECT_H +#define _TECHDRAW_GEOMETRYOBJECT_H + +#include +#include + +#include +#include +#include + +#include "Geometry.h" + +class HLRBRep_Algo; +class Handle_HLRBRep_Data; +class HLRBRep_EdgeData; +class TopoDS_Wire; + +namespace TechDrawGeometry +{ + +class BaseGeom; +/** Algo class for projecting shapes and creating SVG output of it + */ +class DrawingExport GeometryObject +{ +public: + /// Constructor + GeometryObject(); + virtual ~GeometryObject(); + + void clear(); + + void setTolerance(double value); + void setScale(double value); + + //! Returns 2D bounding box + Base::BoundBox3d calcBoundingBox() const; + + const std::vector & getVertexGeometry() const { return vertexGeom; }; + const std::vector & getEdgeGeometry() const { return edgeGeom; }; + const std::vector & getFaceGeometry() const { return faceGeom; }; + + const std::vector & getVertexRefs() const { return vertexReferences; }; + const std::vector & getEdgeRefs() const { return edgeReferences; }; + const std::vector & getFaceRefs() const { return faceReferences; }; + + DrawingGeometry::BaseGeom * projectEdge(const TopoDS_Shape &edge, + const TopoDS_Shape &support, + const Base::Vector3d &direction, + const Base::Vector3d &projXAxis) const; + DrawingGeometry::Vertex * projectVertex(const TopoDS_Shape &vert, + const TopoDS_Shape &support, + const Base::Vector3d &direction, + const Base::Vector3d &projXAxis) const; + + void projectSurfaces(const TopoDS_Shape &face, + const TopoDS_Shape &support, + const Base::Vector3d &direction, + const Base::Vector3d &xaxis, + std::vector &result) const; + + /// Process 3D shape to get 2D geometry + /*! + * Applies a projection to the input based on direction and vAxis, then + * calls extractEdges (which in turn calls extractVerts) and extractFaces + * to populate vectors used by getVertexRefs(), getEdgeRefs(), and + * getFaceRefs() + */ + void extractGeometry(const TopoDS_Shape &input,const Base::Vector3d &direction, bool extractHidden = false, const Base::Vector3d &vAxis = Base::Vector3d(0.,0.,0.)); + +protected: + bool shouldDraw(const bool inFace, const int typ,HLRBRep_EdgeData& ed); + bool isSameCurve(const BRepAdaptor_Curve &c1, const BRepAdaptor_Curve &c2) const; + + /// Reimplements HLRBRep Drawing Algorithms to satisfy Drawing Workbench requirements + void drawFace(const bool visible, const int iface, Handle_HLRBRep_Data & DS, TopoDS_Shape& Result) const; + + /// Add (visible) intervals of ed to Result as Edges + void drawEdge(HLRBRep_EdgeData& ed, TopoDS_Shape& Result, const bool visible) const; + + /// Helper for calcBoundingBox() + /*! Note that the name of this function isn't totally accurate due to + * TechDraw::Bsplines being composed of BezierSegments. + */ + Base::BoundBox3d boundingBoxOfBspline(const BSpline *spline) const; + + /// Helper for calcBoundingBox() + /*! + * AOE = arc of ellipse. Defaults allow this to be used for regular + * ellipses as well as arcs. + */ + Base::BoundBox3d boundingBoxOfAoe(const Ellipse *aoe, double start = 0, + double end = 2 * M_PI, bool cw = false) const; + + /// Helper for boundingBoxOf(Aoc|Aoe)() + /*! + * Returns true iff angle theta is in [first, last], where the arc goes + * clockwise (cw=true) or counterclockwise (cw=false) from first to last. + */ + bool isWithinArc(double theta, double first, double last, bool cw) const; + + void extractVerts(HLRBRep_Algo *myAlgo, const TopoDS_Shape &S, HLRBRep_EdgeData& ed, int ie, ExtractionType extractionType); + void extractEdges(HLRBRep_Algo *myAlgo, const TopoDS_Shape &S, int type, bool visible, ExtractionType extractionType); + + void extractFaces(HLRBRep_Algo *myAlgo, + const TopoDS_Shape &S, + bool visible, + ExtractionType extractionType, + std::vector &projFaces, + std::vector &faceRefs) const; + + int calculateGeometry(const TopoDS_Shape &input, ExtractionType extractionType, std::vector &geoms) const; + + /// Accumulate edges from input and store them in wires + void createWire(const TopoDS_Shape &input, std::vector &wiresOut) const; + + // Geometry + std::vector edgeGeom; + std::vector vertexGeom; + std::vector faceGeom; + + bool findVertex(Base::Vector2D v); + + // indexes to geometry in Source object + std::vector vertexReferences; + std::vector edgeReferences; + std::vector faceReferences; + + HLRBRep_Algo *brep_hlr; + double Tolerance; + double Scale; + + /// Returns the centroid of shape, as viewed according to direction and xAxis + gp_Pnt findCentroid(const TopoDS_Shape &shape, + const Base::Vector3d &direction, + const Base::Vector3d &xAxis) const; +}; + +} //namespace TechDrawGeometry + +#endif diff --git a/src/Mod/TechDraw/App/Makefile.am b/src/Mod/TechDraw/App/Makefile.am new file mode 100644 index 0000000000..2180befed0 --- /dev/null +++ b/src/Mod/TechDraw/App/Makefile.am @@ -0,0 +1,86 @@ + +lib_LTLIBRARIES=libDrawing.la Drawing.la + +libDrawing_la_SOURCES=\ + AppDrawingPy.cpp \ + DrawingExport.cpp \ + DrawingExport.h \ + DrawPage.cpp \ + DrawPage.h \ + DrawProjection.cpp \ + DrawProjection.h \ + DrawView.cpp \ + DrawView.h \ + DrawViewPart.cpp \ + DrawViewPart.h \ + DrawViewAnnotation.cpp \ + DrawViewAnnotation.h \ + DrawViewClip.cpp \ + DrawViewClip.h \ + PageGroup.cpp \ + PageGroup.h \ + ProjectionAlgos.cpp \ + ProjectionAlgos.h \ + PreCompiled.cpp \ + PreCompiled.h + + +# the library search path. +libDrawing_la_LDFLAGS = -L../../../Base -L../../../App -L../../../Mod/Part/App \ + -L$(OCC_LIB) $(all_libraries) \ + -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ +libDrawing_la_CPPFLAGS = -DDrawingExport= + +libDrawing_la_LIBADD = \ + @BOOST_REGEX_LIB@ @BOOST_SYSTEM_LIB@ \ + -l@PYTHON_LIB@ \ + -lxerces-c \ + -lFreeCADBase \ + -lFreeCADApp \ + -lPart \ + -lTKernel \ + -lTKG2d \ + -lTKG3d \ + -lTKMath \ + -lTKSTEP \ + -lTKIGES \ + -lTKSTL \ + -lTKShHealing \ + -lTKXSBase \ + -lTKBool \ + -lTKBO \ + -lTKBRep \ + -lTKTopAlgo \ + -lTKGeomAlgo \ + -lTKGeomBase \ + -lTKOffset \ + -lTKPrim \ + -lTKHLR \ + -lTKMesh + +#-------------------------------------------------------------------------------------- +# Loader of libDrawing + +Drawing_la_SOURCES=\ + AppDrawing.cpp + +# the library search path. +Drawing_la_LDFLAGS = $(libDrawing_la_LDFLAGS) -module -avoid-version +Drawing_la_CPPFLAGS = $(libDrawing_la_CPPFLAGS) + +Drawing_la_LIBADD = \ + $(libDrawing_la_LIBADD) \ + -lDrawing + +Drawing_la_DEPENDENCIES = libDrawing.la + +#-------------------------------------------------------------------------------------- + +# set the include path found by configure +AM_CXXFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src -I$(OCC_INC) $(all_includes) + + +libdir = $(prefix)/Mod/Drawing + +EXTRA_DIST = \ + CMakeLists.txt diff --git a/src/Mod/TechDraw/App/PreCompiled.cpp b/src/Mod/TechDraw/App/PreCompiled.cpp new file mode 100644 index 0000000000..3139e21f64 --- /dev/null +++ b/src/Mod/TechDraw/App/PreCompiled.cpp @@ -0,0 +1,23 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * * + * 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" diff --git a/src/Mod/TechDraw/App/PreCompiled.h b/src/Mod/TechDraw/App/PreCompiled.h new file mode 100644 index 0000000000..af70d9c33c --- /dev/null +++ b/src/Mod/TechDraw/App/PreCompiled.h @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * * + * 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 * + * * + ***************************************************************************/ + + +#ifndef TECHDRAW_PRECOMPILED_H +#define TECHDRAW_PRECOMPILED_H + +#include + +// Exporting of App classes +#ifdef FC_OS_WIN32 +# define DrawingExport __declspec(dllexport) +# define PartExport __declspec(dllimport) +# define MeasureExport __declspec(dllimport) +# define MeshExport __declspec(dllimport) +#else // for Linux +# define DrawingExport +# define MeasureExport +# define PartExport +# define MeshExport +#endif + +#ifdef _PreComp_ + +// standard +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// OpenCasCade ===================================================================================== +// Base +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if OCC_VERSION_HEX < 0x060700 +#include +#include +#endif + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#endif // _PreComp_ +#endif +