diff --git a/src/Mod/TechDraw/App/AppTechDraw.cpp b/src/Mod/TechDraw/App/AppTechDraw.cpp index 2b981a5ba6..9f046d2ccc 100644 --- a/src/Mod/TechDraw/App/AppTechDraw.cpp +++ b/src/Mod/TechDraw/App/AppTechDraw.cpp @@ -31,6 +31,7 @@ #include "DrawViewSymbol.h" #include "DrawViewClip.h" #include "DrawHatch.h" +#include "DrawGeomHatch.h" #include "DrawViewDraft.h" #include "DrawViewArch.h" #include "DrawViewSpreadsheet.h" @@ -84,6 +85,7 @@ PyMODINIT_FUNC initTechDraw() TechDraw::DrawViewClip ::init(); TechDraw::DrawHatch ::init(); + TechDraw::DrawGeomHatch ::init(); TechDraw::DrawViewDraft ::init(); TechDraw::DrawViewArch ::init(); TechDraw::DrawViewImage ::init(); diff --git a/src/Mod/TechDraw/App/CMakeLists.txt b/src/Mod/TechDraw/App/CMakeLists.txt index 608de84dc6..77b9757ae4 100644 --- a/src/Mod/TechDraw/App/CMakeLists.txt +++ b/src/Mod/TechDraw/App/CMakeLists.txt @@ -37,6 +37,7 @@ generate_from_xml(DrawViewSymbolPy) generate_from_xml(DrawViewClipPy) generate_from_xml(DrawViewDimensionPy) generate_from_xml(DrawHatchPy) +generate_from_xml(DrawGeomHatchPy) generate_from_xml(DrawViewCollectionPy) generate_from_xml(DrawProjGroupPy) generate_from_xml(DrawProjGroupItemPy) @@ -74,6 +75,8 @@ SET(Draw_SRCS DrawViewSection.h DrawHatch.cpp DrawHatch.h + DrawGeomHatch.cpp + DrawGeomHatch.h DrawViewDraft.cpp DrawViewDraft.h DrawViewArch.cpp @@ -92,6 +95,8 @@ SET(TechDraw_SRCS DrawUtil.h Cube.cpp Cube.h + HatchLine.cpp + HatchLine.h PreCompiled.cpp PreCompiled.h EdgeWalker.cpp @@ -128,6 +133,8 @@ SET(Python_SRCS DrawViewDimensionPyImp.cpp DrawHatchPy.xml DrawHatchPyImp.cpp + DrawGeomHatchPy.xml + DrawGeomHatchPyImp.cpp DrawViewCollectionPy.xml DrawViewCollectionPyImp.cpp DrawProjGroupPy.xml @@ -150,6 +157,10 @@ SET(TechDraw_Templates Templates/A4_Portrait_ISO7200TD.svg ) +SET(TechDraw_PATFile + PAT/FCPAT.pat +) + if(MSVC) #add_definitions(-D_PreComp_) #GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" TechDrawCPP_SRCS ${TechDraw_SRCS} ${Draw_SRCS} ) @@ -175,6 +186,11 @@ fc_target_copy_resource(TechDraw ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw ${TechDraw_Templates}) +fc_target_copy_resource(TechDraw + ${CMAKE_SOURCE_DIR}/src/Mod/TechDraw + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw + ${TechDraw_PATFile}) + SET_BIN_DIR(TechDraw TechDraw /Mod/TechDraw) SET_PYTHON_PREFIX_SUFFIX(TechDraw) diff --git a/src/Mod/TechDraw/App/DrawGeomHatch.cpp b/src/Mod/TechDraw/App/DrawGeomHatch.cpp new file mode 100644 index 0000000000..a642155fd6 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawGeomHatch.cpp @@ -0,0 +1,435 @@ +/*************************************************************************** + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "HatchLine.h" +#include "DrawUtil.h" +#include "Geometry.h" +#include "DrawViewPart.h" +#include "DrawViewSection.h" +#include "DrawGeomHatch.h" + +#include // generated from DrawGeomHatchPy.xml + +using namespace TechDraw; +using namespace TechDrawGeometry; +using namespace std; + +PROPERTY_SOURCE(TechDraw::DrawGeomHatch, App::DocumentObject) + + +DrawGeomHatch::DrawGeomHatch(void) +{ + static const char *vgroup = "GeomHatch"; + + ADD_PROPERTY_TYPE(Source,(0),vgroup,(App::PropertyType)(App::Prop_None),"The View + Face to be crosshatched"); + ADD_PROPERTY_TYPE(FilePattern ,(""),vgroup,App::Prop_None,"The crosshatch pattern file for this area"); + ADD_PROPERTY_TYPE(NamePattern,(""),vgroup,App::Prop_None,"The name of the pattern"); + ADD_PROPERTY_TYPE(ScalePattern,(1.0),vgroup,App::Prop_None,"GeomHatch pattern size adjustment"); + + getParameters(); + +} + +DrawGeomHatch::~DrawGeomHatch() +{ +} + +void DrawGeomHatch::onChanged(const App::Property* prop) +{ + if (prop == &Source ) { + if (!isRestoring()) { + DrawGeomHatch::execute(); + } + } + + if (prop == &FilePattern || + prop == &NamePattern ) { + if ((!FilePattern.isEmpty()) && + (!NamePattern.isEmpty())) { + std::vector specs = getDecodedSpecsFromFile(); + m_lineSets.clear(); + for (auto& hl: specs) { + //hl.dump("hl from file"); + LineSet ls; + ls.setHatchLine(hl); + m_lineSets.push_back(ls); + } + + } + } + + App::DocumentObject::onChanged(prop); +} + +short DrawGeomHatch::mustExecute() const +{ + short result = 0; + if (!isRestoring()) { + result = (Source.isTouched() || + FilePattern.isTouched() || + NamePattern.isTouched() ); + } + + if (result) { + return result; + } + return App::DocumentObject::mustExecute(); +} + + +App::DocumentObjectExecReturn *DrawGeomHatch::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +DrawViewPart* DrawGeomHatch::getSourceView(void) const +{ + App::DocumentObject* obj = Source.getValue(); + DrawViewPart* result = dynamic_cast(obj); + return result; +} + +std::vector DrawGeomHatch::getDecodedSpecsFromFile() +{ + std::string fileSpec = FilePattern.getValue(); + std::string myPattern = NamePattern.getValue(); + return getDecodedSpecsFromFile(fileSpec,myPattern); +} + + +//!get all the specification lines and decode them into HatchLine structures +/*static*/ +std::vector DrawGeomHatch::getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern) +{ + std::vector result; + Base::FileInfo fi(fileSpec); + if (!fi.isReadable()) { + Base::Console().Error("DrawGeomHatch::getDecodedSpecsFromFile not able to open %s!\n",fileSpec.c_str()); + return result; + } + result = HatchLine::getSpecsForPattern(fileSpec,myPattern); + + return result; +} + +std::vector DrawGeomHatch::getDrawableLines(int i) //get the drawable lines for face i +{ + std::vector result; + DrawViewPart* source = getSourceView(); + if (!source || + !source->hasGeometry()) { + Base::Console().Message("TRACE - DC::getDrawableLines - no source geometry\n"); + return result; + } + return getDrawableLines(source, m_lineSets,i, ScalePattern.getValue()); +} + +/* static */ +std::vector DrawGeomHatch::getDrawableLines(DrawViewPart* source, std::vector lineSets, int iface, double scale ) +{ + std::vector result; + + //is source is a section? + DrawViewSection* section = dynamic_cast(source); + bool usingSection = false; + if (section != nullptr) { + usingSection = true; + } + + if (lineSets.empty()) { + Base::Console().Log("INFO - DC::getDrawableLines - no LineSets!\n"); + return result; + } + + std::vector faceWires; + if (usingSection) { + faceWires = section->getWireForFace(iface); + } else { + faceWires = source->getWireForFace(iface); + } + + //build face(s) from geometry + gp_Pnt gOrg(0.0,0.0,0.0); + gp_Dir gDir(0.0,0.0,1.0); + gp_Pln plane(gOrg,gDir); + + BRepBuilderAPI_MakeFace mkFace(plane, faceWires.front(), true); + std::vector::iterator itWire = ++faceWires.begin(); //starting with second wire + for (; itWire != faceWires.end(); itWire++) { + mkFace.Add(*itWire); + } + if (!mkFace.IsDone()) { + Base::Console().Log("INFO - DC::getDrawableLines - face creation failed\n"); + return result; + } + TopoDS_Face face = mkFace.Face(); + + Bnd_Box bBox; + BRepBndLib::Add(face, bBox); + bBox.SetGap(0.0); + + for (auto& ls: lineSets) { + HatchLine hl = ls.getHatchLine(); + std::vector candidates = DrawGeomHatch::makeEdgeOverlay(hl, bBox, scale); + + //make Compound for this linespec + BRep_Builder builder; + TopoDS_Compound Comp; + builder.MakeCompound(Comp); + for (auto& c: candidates) { + builder.Add(Comp, c); + } + + //Common Compound with Face + BRepAlgoAPI_Common mkCommon(face, Comp); + if ((!mkCommon.IsDone()) || + (mkCommon.Shape().IsNull()) ) { + Base::Console().Log("INFO - DC::getDrawableLines - Common creation failed\n"); + return result; + } + TopoDS_Shape common = mkCommon.Shape(); + + //Save edges from Common + std::vector resultEdges; + std::vector resultGeoms; + TopTools_IndexedMapOfShape mapOfEdges; + TopExp::MapShapes(common, TopAbs_EDGE, mapOfEdges); + for ( int i = 1 ; i <= mapOfEdges.Extent() ; i++ ) { + const TopoDS_Edge& edge = TopoDS::Edge(mapOfEdges(i)); + if (edge.IsNull()) { + Base::Console().Log("INFO - DC::getDrawableLines - edge: %d is NULL\n",i); + continue; + } + TechDrawGeometry::BaseGeom* base = BaseGeom::baseFactory(edge); + if (base == nullptr) { + Base::Console().Log("FAIL - DC::getDrawableLines - baseFactory failed for edge: %d\n",i); + throw Base::Exception("GeometryObject::addGeomFromCompound - baseFactory failed"); + } + resultGeoms.push_back(base); + resultEdges.push_back(edge); + } + ls.setEdges(resultEdges); + ls.setGeoms(resultGeoms); + result.push_back(ls); + } + return result; +} +/* static */ +std::vector DrawGeomHatch::makeEdgeOverlay(HatchLine hl, Bnd_Box b, double scale) +{ + std::vector result; + + double minX,maxX,minY,maxY,minZ,maxZ; + b.Get(minX,minY,minZ,maxX,maxY,maxZ); + + Base::Vector3d start; + Base::Vector3d end; + Base::Vector3d origin = hl.getOrigin(); +// double interval = hl.getInterval() * ScalePattern.getValue(); + double interval = hl.getInterval() * scale; + double angle = hl.getAngle(); + + //only dealing with angles -180:180 for now + if (angle > 90.0) { + angle = -(180.0 - angle); + } else if (angle < -90.0) { + angle = (180 + angle); + } + angle = -angle; //not sure why this is required? inverted Y? + double slope = tan(angle * M_PI/180.0); + + if (angle == 0.0) { //odd case 1: horizontal lines + double y = origin.y; + double x1 = minX; + double x2 = maxX; + start = Base::Vector3d(x1,y,0); + end = Base::Vector3d(x2,y,0); + int repeatUp = (int) ceil(((maxY - y)/interval) + 1); + int repeatDown = (int) ceil(((y - minY)/interval) + 1); + // make up repeats + int i; + for (i = 1; i < repeatUp; i++) { + Base::Vector3d newStart(minX,y + float(i)*interval,0); + Base::Vector3d newEnd(maxX,y + float(i)*interval,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + // make down repeats + for (i = 1; i < repeatDown; i++) { + Base::Vector3d newStart(minX, y - float(i)*interval,0); + Base::Vector3d newEnd(maxX, y - float(i)*interval,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } else if (angle > 0) { //bottomleft - topright + double xRightAtom = origin.x + ((maxY - origin.y)/slope); + double xLeftAtom = origin.x + ((minY - origin.y)/slope); + start = Base::Vector3d(xLeftAtom,minY,0); + end = Base::Vector3d(xRightAtom,maxY,0); + int repeatRight = (int) ceil(((maxX - xLeftAtom)/interval) + 1); + int repeatLeft = (int) ceil(((xRightAtom - minX)/interval) + 1); + + // make right repeats + int i; + for (i = 1; i < repeatRight; i++) { + Base::Vector3d newStart(start.x + float(i)*interval,minY,0); + Base::Vector3d newEnd(end.x + float(i)*interval,maxY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + // make left repeats + for (i = 1; i < repeatLeft; i++) { + Base::Vector3d newStart(start.x - float(i)*interval,minY,0); + Base::Vector3d newEnd(end.x - float(i)*interval,maxY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } else { //topleft - bottomright + double x2 = origin.x + (maxY - origin.y)/slope; + double x1 = origin.x + (minY - origin.y)/slope; + start = Base::Vector3d(x2,maxY,0); + end = Base::Vector3d(x1,minY,0); + int repeatRight = (int) ceil(((maxX - start.x)/interval) + 1); + int repeatLeft = (int) ceil(((end.x - minX)/interval) + 1); + + // make right repeats + int i; + for (i = 1; i < repeatRight; i++) { + Base::Vector3d newStart(start.x + float(i)*interval,maxY,0); + Base::Vector3d newEnd(end.x + float(i)*interval,minY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + // make left repeats + for (i = 1; i < repeatLeft; i++) { + Base::Vector3d newStart(start.x - float(i)*interval,maxY,0); + Base::Vector3d newEnd(end.x - float(i)*interval,minY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } + //atom is centre line in a set of pattern lines. + TopoDS_Edge atom = makeLine(start,end); + result.push_back(atom); + return result; +} + +TopoDS_Edge DrawGeomHatch::makeLine(Base::Vector3d s, Base::Vector3d e) +{ + TopoDS_Edge result; + gp_Pnt start(s.x,s.y,0.0); + gp_Pnt end(e.x,e.y,0.0); + TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(start); + TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(end); + BRepBuilderAPI_MakeEdge makeEdge1(v1,v2); + result = makeEdge1.Edge(); + return result; +} + +void DrawGeomHatch::getParameters(void) +{ +//this is probably "/build/data/Mod/TechDraw/PAT" + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/PAT"); + + std::string defaultDir = App::Application::getResourceDir() + "Mod/TechDraw/PAT/"; + std::string defaultFileName = defaultDir + "FCPAT.pat"; + QString patternFileName = QString::fromStdString(hGrp->GetASCII("FilePattern",defaultFileName.c_str())); + if (patternFileName.isEmpty()) { + patternFileName = QString::fromStdString(defaultFileName); + } + QFileInfo tfi(patternFileName); + if (tfi.isReadable()) { + FilePattern.setValue(patternFileName.toUtf8().constData()); + } else { + Base::Console().Error("DrawGeomHatch: PAT file: %s Not Found\n",patternFileName.toUtf8().constData()); + } + hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/PAT"); + std::string defaultNamePattern = "Diamond"; + NamePattern.setValue(hGrp->GetASCII("NamePattern",defaultNamePattern.c_str())); + +} + + +PyObject *DrawGeomHatch::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + PythonObject = Py::Object(new DrawGeomHatchPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawGeomHatchPython, TechDraw::DrawGeomHatch) +template<> const char* TechDraw::DrawGeomHatchPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderGeomHatch"; +} +/// @endcond + +// explicit template instantiation +template class TechDrawExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawGeomHatch.h b/src/Mod/TechDraw/App/DrawGeomHatch.h new file mode 100644 index 0000000000..767fb62910 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawGeomHatch.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (c) 2017 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 _TechDraw_DrawGeomHatch_h_ +#define _TechDraw_DrawGeomHatch_h_ + +# include +# include +# include +#include + +class TopoDS_Edge; +class Bnd_Box; + +namespace TechDrawGeometry +{ +class BaseGeom; +} + +namespace TechDraw +{ +class DrawViewPart; +class HatchLine; +class LineSet; +class DashSet; + +class TechDrawExport DrawGeomHatch : public App::DocumentObject +{ + PROPERTY_HEADER(TechDraw::DrawGeomHatch); + +public: + DrawGeomHatch(); + virtual ~DrawGeomHatch(); + + App::PropertyLinkSub Source; //the dvX & face(s) this crosshatch belongs to + App::PropertyFile FilePattern; + App::PropertyString NamePattern; + App::PropertyFloat ScalePattern; + + virtual short mustExecute() const; + virtual App::DocumentObjectExecReturn *execute(void); + virtual void onChanged(const App::Property* prop); + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderGeomHatch"; + } + virtual PyObject *getPyObject(void); + + DrawViewPart* getSourceView(void) const; + + std::vector getDrawableLines(int i = 0); + static std::vector getDrawableLines(DrawViewPart* dvp, std::vector lineSets, int iface, double scale); + + static std::vector makeEdgeOverlay(HatchLine hl, Bnd_Box bBox, double scale); + static TopoDS_Edge makeLine(Base::Vector3d s, Base::Vector3d e); + static std::vector getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern); + +protected: + void getParameters(void); + std::vector getDecodedSpecsFromFile(); + std::vector m_lineSets; + +private: +}; + +typedef App::FeaturePythonT DrawGeomHatchPython; + + + +} //namespace TechDraw +#endif diff --git a/src/Mod/TechDraw/App/DrawGeomHatchPy.xml b/src/Mod/TechDraw/App/DrawGeomHatchPy.xml new file mode 100644 index 0000000000..8cedf84241 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawGeomHatchPy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for creating and manipulating Technical Drawing GeomHatch areas + + + + diff --git a/src/Mod/TechDraw/App/DrawGeomHatchPyImp.cpp b/src/Mod/TechDraw/App/DrawGeomHatchPyImp.cpp new file mode 100644 index 0000000000..327ae70524 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawGeomHatchPyImp.cpp @@ -0,0 +1,32 @@ + +#include "PreCompiled.h" + +#include "DrawGeomHatch.h" + +// inclusion of the generated files (generated out of DrawGeomHatchPy.xml) +#include +#include + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawGeomHatchPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *DrawGeomHatchPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawGeomHatchPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/TechDraw/App/DrawHatch.cpp b/src/Mod/TechDraw/App/DrawHatch.cpp index 44587f4203..81e8437a95 100644 --- a/src/Mod/TechDraw/App/DrawHatch.cpp +++ b/src/Mod/TechDraw/App/DrawHatch.cpp @@ -61,13 +61,15 @@ DrawHatch::DrawHatch(void) ADD_PROPERTY_TYPE(Source,(0),vgroup,(App::PropertyType)(App::Prop_None),"The View + Face to be hatched"); ADD_PROPERTY_TYPE(HatchPattern ,(""),vgroup,App::Prop_None,"The hatch pattern file for this area"); ADD_PROPERTY_TYPE(HatchColor,(fcColor),vgroup,App::Prop_None,"The color of the hatch pattern"); + ADD_PROPERTY_TYPE(HatchScale,(1.0),vgroup,App::Prop_None,"Hatch pattern size adjustment"); + DirProjection.setStatus(App::Property::ReadOnly,true); hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Files"); std::string defaultDir = App::Application::getResourceDir() + "Mod/Drawing/patterns/"; std::string defaultFileName = defaultDir + "simple.svg"; - QString patternFileName = QString::fromStdString(hGrp->GetASCII("PatternFile",defaultFileName.c_str())); + QString patternFileName = QString::fromStdString(hGrp->GetASCII("FileHatch",defaultFileName.c_str())); if (patternFileName.isEmpty()) { patternFileName = QString::fromStdString(defaultFileName); } @@ -84,7 +86,8 @@ DrawHatch::~DrawHatch() void DrawHatch::onChanged(const App::Property* prop) { if (prop == &Source || - prop == &HatchPattern || + prop == &HatchPattern || //sb VP property? + prop == &HatchScale || prop == &HatchColor) { if (!isRestoring()) { DrawHatch::execute(); diff --git a/src/Mod/TechDraw/App/DrawHatch.h b/src/Mod/TechDraw/App/DrawHatch.h index 5219bb1e5b..496cc15a4d 100644 --- a/src/Mod/TechDraw/App/DrawHatch.h +++ b/src/Mod/TechDraw/App/DrawHatch.h @@ -44,6 +44,7 @@ public: App::PropertyLinkSub Source; //the dvp & face this hatch belongs to App::PropertyFile HatchPattern; App::PropertyColor HatchColor; + App::PropertyFloat HatchScale; //short mustExecute() const; diff --git a/src/Mod/TechDraw/App/DrawPage.cpp b/src/Mod/TechDraw/App/DrawPage.cpp index 86a8ff2c3c..b03b03cf40 100644 --- a/src/Mod/TechDraw/App/DrawPage.cpp +++ b/src/Mod/TechDraw/App/DrawPage.cpp @@ -66,6 +66,7 @@ const char* DrawPage::ProjectionTypeEnums[] = { "First Angle", DrawPage::DrawPage(void) { static const char *group = "Page"; + nowDeleting = false; 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"); @@ -101,11 +102,13 @@ void DrawPage::onBeforeChange(const App::Property* prop) void DrawPage::onChanged(const App::Property* prop) { if (prop == &Template) { - if (!isRestoring()) { + if (!isRestoring() && + !isDeleting()) { //TODO: reload if Template prop changes (ie different Template) } } else if (prop == &Views) { - if (!isRestoring()) { + if (!isRestoring() && + !isDeleting() ) { //TODO: reload if Views prop changes (ie adds/deletes) } } else if(prop == &Scale) { @@ -130,7 +133,7 @@ void DrawPage::onChanged(const App::Property* prop) // TODO: Also update Template graphic. } - App::DocumentObject::onChanged(prop); + App::DocumentObject::onChanged(prop); //<<<< } App::DocumentObjectExecReturn *DrawPage::execute(void) @@ -289,6 +292,10 @@ void DrawPage::onDocumentRestored() if (part != nullptr && !part->hasGeometry()) { part->execute(); +// std::vector parent = part->getInList(); +// for (auto& p: parent) { +// p->touch(); +// } } } //second, make sure all the Dimensions have been executed so Measurements have References @@ -302,3 +309,28 @@ void DrawPage::onDocumentRestored() recompute(); App::DocumentObject::onDocumentRestored(); } + +void DrawPage::unsetupObject() +{ + nowDeleting = true; + + // Remove the Page's views & template from document + App::Document* doc = getDocument(); + std::string docName = doc->getName(); + + const std::vector currViews = Views.getValues(); + std::vector emptyViews; + std::vector::const_iterator it = currViews.begin(); + for (; it != currViews.end(); it++) { + std::string viewName = (*it)->getNameInDocument(); + Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")", + docName.c_str(), viewName.c_str()); + } + Views.setValues(emptyViews); + + std::string templateName = Template.getValue()->getNameInDocument(); + Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")", + docName.c_str(), templateName.c_str()); + Template.setValue(nullptr); +} + diff --git a/src/Mod/TechDraw/App/DrawPage.h b/src/Mod/TechDraw/App/DrawPage.h index 8f9865a33f..cc6b1ff922 100644 --- a/src/Mod/TechDraw/App/DrawPage.h +++ b/src/Mod/TechDraw/App/DrawPage.h @@ -81,14 +81,20 @@ public: */ double getPageHeight() const; const char* getPageOrientation() const; + bool isDeleting(void) { return nowDeleting; } + protected: void onBeforeChange(const App::Property* prop); void onChanged(const App::Property* prop); virtual void onDocumentRestored(); + virtual void unsetupObject(); + private: static const char* ProjectionTypeEnums[]; + bool nowDeleting; + }; } //namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawProjGroup.cpp b/src/Mod/TechDraw/App/DrawProjGroup.cpp index a3da8149f2..d17a8c0193 100644 --- a/src/Mod/TechDraw/App/DrawProjGroup.cpp +++ b/src/Mod/TechDraw/App/DrawProjGroup.cpp @@ -176,7 +176,9 @@ void DrawProjGroup::onChanged(const App::Property* prop) TechDraw::DrawPage *page = getPage(); if (!isRestoring() && page) { if ( prop == &Views ) { - recompute(); + if (!isDeleting()) { + recompute(); + } } else if (prop == &Scale) { updateChildren(Scale.getValue()); //resetPositions(); @@ -185,7 +187,8 @@ void DrawProjGroup::onChanged(const App::Property* prop) App::DocumentObject* sourceObj = Source.getValue(); if (sourceObj != nullptr) { if (!hasAnchor()) { - addProjection("Front"); + // if we have a Source, but no Anchor, make an anchor + Anchor.setValue(addProjection("Front")); } } else { //Source has been changed to null! Why? What to do? @@ -214,9 +217,9 @@ App::DocumentObjectExecReturn *DrawProjGroup::execute(void) return DrawViewCollection::execute(); } - docObj = Anchor.getValue(); //must have an anchor, so create one as soon as we have a Page and Source + docObj = Anchor.getValue(); if (docObj == nullptr) { - docObj = addProjection("Front"); + return DrawViewCollection::execute(); } double newScale = Scale.getValue(); @@ -441,8 +444,6 @@ bool DrawProjGroup::hasProjection(const char *viewProjType) const App::DocumentObject * DrawProjGroup::addProjection(const char *viewProjType) { - //if this is the first Projection added, it should automatically be the Anchor/front view - // or if viewProjType == "Front" Anchor.setValue(view) DrawProjGroupItem *view( nullptr ); if ( checkViewProjType(viewProjType) && !hasProjection(viewProjType) ) { @@ -460,21 +461,8 @@ App::DocumentObject * DrawProjGroup::addProjection(const char *viewProjType) view->Type.setValue( viewProjType ); view->Label.setValue( viewProjType ); view->Source.setValue( Source.getValue() ); - if( strcmp(viewProjType,"Front") == 0 ) { - - Anchor.setValue(docObj); - view->Direction.setValue(m_frameToStdDir.at("Front")); //just (Base::Vector3d(0.0,-1.0,0.0)) - view->RotationVector.setValue(m_frameToStdRot.at("Front")); - } else { - //TODO: really need to check with Cube to get current dir & rot this uses initial values from table - //if (DPGI(front) and DPGI(right) exist) config = front.face + right.face - // - //else - // use start up values (m_frameToStdDir/m_frameToStdRot) - view->Direction.setValue(m_frameToStdDir.at(viewProjType)); - view->RotationVector.setValue(m_frameToStdRot.at(viewProjType)); - } - + view->Direction.setValue(m_frameToStdDir.at(viewProjType)); + view->RotationVector.setValue(m_frameToStdRot.at(viewProjType)); addView(view); //from DrawViewCollection - add to ProjGroup Views moveToCentre(); view->recomputeFeature(); @@ -483,6 +471,7 @@ App::DocumentObject * DrawProjGroup::addProjection(const char *viewProjType) return view; } +//NOTE: projections can be deleted without using removeProjection - ie regular DocObject deletion process. int DrawProjGroup::removeProjection(const char *viewProjType) { // TODO: shouldn't be able to delete "Front" unless deleting whole group @@ -508,6 +497,7 @@ int DrawProjGroup::removeProjection(const char *viewProjType) return -1; } +//removes all DPGI - used when deleting DPG int DrawProjGroup::purgeProjections() { while (!Views.getValues().empty()) { @@ -803,7 +793,9 @@ TechDraw::DrawProjGroupItem* DrawProjGroup::getAnchor(void) App::DocumentObject* docObj = Anchor.getValue(); if (docObj == nullptr) { //explode! DPG w/o anchor - Base::Console().Error("Error - DPG::getAnchor - DPG has no Anchor!!!\n"); + if (!isDeleting()) { + Base::Console().Error("Error - DPG::getAnchor - DPG has no Anchor!!!\n"); + } } else { result = static_cast(docObj); } @@ -1033,6 +1025,7 @@ void DrawProjGroup::onDocumentRestored() } std::string viewRot = Cube::dirToView(rotFront); std::string config = viewDir + viewRot; + //find(config) or try/catch try { config = m_dirRotToConfig.at(config); setConfig(config); diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.cpp b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp index e53f0069ce..5f2e107ab8 100644 --- a/src/Mod/TechDraw/App/DrawProjGroupItem.cpp +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp @@ -140,7 +140,7 @@ double DrawProjGroupItem::getRotateAngle() gp_Ax2 viewAxis; Base::Vector3d x = RotationVector.getValue(); //current rotation Base::Vector3d nx = x; - x.Normalize(); + nx.Normalize(); Base::Vector3d na = Direction.getValue(); na.Normalize(); Base::Vector3d org(0.0,0.0,0.0); @@ -160,6 +160,21 @@ double DrawProjGroupItem::getRotateAngle() return angle; } +void DrawProjGroupItem::unsetupObject() +{ + if (getGroup() != nullptr) { + if (getGroup()->hasProjection(Type.getValueAsString()) ) { + if ((getGroup()->getAnchor() == this) && + !getGroup()->isDeleting() ) { + Base::Console().Warning("Warning - DPG (%s/%s) may be corrupt - Anchor deleted\n", + getGroup()->getNameInDocument(),getGroup()->Label.getValue()); + getGroup()->Anchor.setValue(nullptr); //this catches situation where DPGI is deleted w/o DPG::removeProjection + } + } + } + DrawViewPart::unsetupObject(); +} + PyObject *DrawProjGroupItem::getPyObject(void) { if (PythonObject.is(Py::_None())) { diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.h b/src/Mod/TechDraw/App/DrawProjGroupItem.h index ac831f82a3..8916594dd2 100644 --- a/src/Mod/TechDraw/App/DrawProjGroupItem.h +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.h @@ -59,12 +59,8 @@ public: App::PropertyVector RotationVector; 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 - //@} + virtual void unsetupObject(); DrawProjGroup* getGroup(void) const; double getRotateAngle(); diff --git a/src/Mod/TechDraw/App/DrawProjectSplit.cpp b/src/Mod/TechDraw/App/DrawProjectSplit.cpp index 32eb721310..15741db62e 100644 --- a/src/Mod/TechDraw/App/DrawProjectSplit.cpp +++ b/src/Mod/TechDraw/App/DrawProjectSplit.cpp @@ -127,7 +127,7 @@ std::vector DrawProjectSplit::getEdgesForWalker(TopoDS_Shape shape, TechDrawGeometry::GeometryObject* DrawProjectSplit::buildGeometryObject(TopoDS_Shape shape, const gp_Ax2& viewAxis) { - TechDrawGeometry::GeometryObject* geometryObject = new TechDrawGeometry::GeometryObject("DrawProjectSplit"); + TechDrawGeometry::GeometryObject* geometryObject = new TechDrawGeometry::GeometryObject("DrawProjectSplit",nullptr); geometryObject->projectShape(shape, viewAxis); diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index 685824bbae..f4cd1d0c6e 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -277,6 +277,16 @@ std::string DrawUtil::formatVector(const Base::Vector3d& v) return result; } +std::string DrawUtil::formatVector(const Base::Vector2d& v) +{ + std::string result; + std::stringstream builder; + builder << std::fixed << std::setprecision(3) ; + builder << " (" << v.x << "," << v.y << ") "; + result = builder.str(); + return result; +} + //! compare 2 vectors for sorting - true if v1 < v2 bool DrawUtil::vectorLess(const Base::Vector3d& v1, const Base::Vector3d& v2) { @@ -293,7 +303,6 @@ bool DrawUtil::vectorLess(const Base::Vector3d& v1, const Base::Vector3d& v2) return result; } - //!convert fromPoint in coordinate system fromSystem to reference coordinate system Base::Vector3d DrawUtil::toR3(const gp_Ax2 fromSystem, const Base::Vector3d fromPoint) { diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index 41059cfdb6..06ea4078ab 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -59,6 +60,7 @@ class TechDrawExport DrawUtil { static bool fpCompare(const double& d1, const double& d2); static Base::Vector3d vertex2Vector(const TopoDS_Vertex& v); static std::string formatVector(const Base::Vector3d& v); + static std::string formatVector(const Base::Vector2d& v); static bool vectorLess(const Base::Vector3d& v1, const Base::Vector3d& v2); static Base::Vector3d toR3(const gp_Ax2 fromSystem, const Base::Vector3d fromPoint); static bool checkParallel(const Base::Vector3d v1, const Base::Vector3d v2); diff --git a/src/Mod/TechDraw/App/DrawViewCollection.cpp b/src/Mod/TechDraw/App/DrawViewCollection.cpp index 47e6b79227..a0f158d2d5 100644 --- a/src/Mod/TechDraw/App/DrawViewCollection.cpp +++ b/src/Mod/TechDraw/App/DrawViewCollection.cpp @@ -26,6 +26,8 @@ # include #endif +#include + #include #include @@ -42,6 +44,7 @@ PROPERTY_SOURCE(TechDraw::DrawViewCollection, TechDraw::DrawView) DrawViewCollection::DrawViewCollection() { + nowDeleting = false; 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"); @@ -165,6 +168,26 @@ void DrawViewCollection::onChanged(const App::Property* prop) TechDraw::DrawView::onChanged(prop); } +void DrawViewCollection::unsetupObject() +{ + nowDeleting = true; + + // Remove the collection's views from document + App::Document* doc = getDocument(); + std::string docName = doc->getName(); + + const std::vector currViews = Views.getValues(); + std::vector emptyViews; + std::vector::const_iterator it = currViews.begin(); + for (; it != currViews.end(); it++) { + std::string viewName = (*it)->getNameInDocument(); + Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")", + docName.c_str(), viewName.c_str()); + } + Views.setValues(emptyViews); +} + + App::DocumentObjectExecReturn *DrawViewCollection::execute(void) { if (ScaleType.isValue("Page")) { diff --git a/src/Mod/TechDraw/App/DrawViewCollection.h b/src/Mod/TechDraw/App/DrawViewCollection.h index 4b1c85d546..d0e0ea029c 100644 --- a/src/Mod/TechDraw/App/DrawViewCollection.h +++ b/src/Mod/TechDraw/App/DrawViewCollection.h @@ -50,14 +50,13 @@ public: int addView(DrawView *view); int removeView(DrawView *view); void rebuildViewList(void); + bool isDeleting(void) { return nowDeleting; } int countChildren(); - /** @name methods overide Feature */ - //@{ - /// recalculate the Feature + virtual void onDocumentRestored(); virtual App::DocumentObjectExecReturn *execute(void); - //@} + virtual void unsetupObject(); /// returns the type name of the ViewProvider virtual const char* getViewProviderName(void) const { @@ -67,6 +66,7 @@ public: protected: void onChanged(const App::Property* prop); + bool nowDeleting; }; } //namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawViewDetail.cpp b/src/Mod/TechDraw/App/DrawViewDetail.cpp index 1a108813ad..ffd126f84e 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.cpp +++ b/src/Mod/TechDraw/App/DrawViewDetail.cpp @@ -103,6 +103,7 @@ DrawViewDetail::DrawViewDetail() ADD_PROPERTY_TYPE(Reference ,("1"),dgroup,App::Prop_None,"An identifier for this detail"); getParameters(); + m_fudge = 1.1; } DrawViewDetail::~DrawViewDetail() @@ -165,8 +166,7 @@ App::DocumentObjectExecReturn *DrawViewDetail::execute(void) Base::Vector3d anchor = AnchorPoint.getValue(); //this is a 2D point anchor = Base::Vector3d(anchor.x,anchor.y, 0.0); - double radiusFudge = 1.1; - double radius = Radius.getValue() * radiusFudge; + double radius = getFudgeRadius(); Base::Vector3d dirDetail = dvp->Direction.getValue(); double scale = Scale.getValue(); gp_Ax2 viewAxis = getViewAxis(Base::Vector3d(0.0,0.0,0.0), dirDetail, false); @@ -204,11 +204,11 @@ App::DocumentObjectExecReturn *DrawViewDetail::execute(void) BRepAlgoAPI_Common mkCommon(myShape,tool); if (!mkCommon.IsDone()) { - Base::Console().Message("TRACE - DVD::execute - mkCommon not done\n"); + Base::Console().Log("DVD::execute - mkCommon not done\n"); return new App::DocumentObjectExecReturn("DVD::execute - mkCommon not done"); } if (mkCommon.Shape().IsNull()) { - Base::Console().Message("TRACE - DVD::execute - mkCommon.Shape is Null\n"); + Base::Console().Log("DVD::execute - mkCommon.Shape is Null\n"); return new App::DocumentObjectExecReturn("DVD::execute - mkCommon.Shape is Null"); } @@ -216,7 +216,7 @@ App::DocumentObjectExecReturn *DrawViewDetail::execute(void) TopExp_Explorer xp; xp.Init(mkCommon.Shape(),TopAbs_SOLID); if (!(xp.More() == Standard_True)) { - Base::Console().Message("TRACE - DVD::execute - mkCommon.Shape is not a solid!\n"); + Base::Console().Log("DVD::execute - mkCommon.Shape is not a solid!\n"); } TopoDS_Shape detail = mkCommon.Shape(); Bnd_Box testBox; @@ -267,6 +267,11 @@ App::DocumentObjectExecReturn *DrawViewDetail::execute(void) return App::DocumentObject::StdReturn; } +double DrawViewDetail::getFudgeRadius() +{ + return Radius.getValue() * m_fudge; +} + void DrawViewDetail::getParameters() { // what parameters are useful? diff --git a/src/Mod/TechDraw/App/DrawViewDetail.h b/src/Mod/TechDraw/App/DrawViewDetail.h index e8a8561811..6e30179866 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.h +++ b/src/Mod/TechDraw/App/DrawViewDetail.h @@ -69,12 +69,12 @@ public: } public: - //int getMattingStyle() const {return m_mattingStyle;} + double getFudgeRadius(void); protected: Base::Vector3d toR3(const gp_Ax2 fromSystem, const Base::Vector3d fromPoint); void getParameters(void); - //int m_mattingStyle; + double m_fudge; }; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index 9e24f121ce..ad442ce87e 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -119,6 +119,7 @@ DrawViewDimension::DrawViewDimension(void) Rotation.setStatus(App::Property::Hidden,true); measurement = new Measure::Measurement(); + //TODO: should have better initial datumLabel position than (0,0) in the DVP?? something closer to the object being measured? } DrawViewDimension::~DrawViewDimension() @@ -131,16 +132,12 @@ void DrawViewDimension::onChanged(const App::Property* prop) { if (!isRestoring()) { if (prop == &MeasureType) { -// Base::Console().Message("TRACE -DVD::onChanged(MeasureType) - MeasureType: %d Measurehas3D: %d thisHas3D: %d\n", -// MeasureType.getValue(),measurement->has3DReferences(),has3DReferences()); if (MeasureType.isValue("True") && !measurement->has3DReferences()) { Base::Console().Warning("Dimension %s missing Reference to 3D model. Must be Projected.\n", getNameInDocument()); MeasureType.setValue("Projected"); } } if (prop == &References3D) { //have to rebuild the Measurement object -// Base::Console().Message("TRACE -DVD::onChanged(References3D) - MeasureType: %d has3D: %d thisHas3D: %d\n", -// MeasureType.getValue(),measurement->has3DReferences(),has3DReferences()); clear3DMeasurements(); //Measurement object if (!(References3D.getValues()).empty()) { setAll3DMeasurement(); @@ -189,7 +186,7 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute(void) return App::DocumentObject::execute();; } -std::string DrawViewDimension::getFormatedValue() const +std::string DrawViewDimension::getFormatedValue() { QString str = QString::fromUtf8(FormatSpec.getStrValue().data(),FormatSpec.getStrValue().size()); double val = std::abs(getDimValue()); @@ -230,16 +227,16 @@ std::string DrawViewDimension::getFormatedValue() const } -double DrawViewDimension::getDimValue() const +double DrawViewDimension::getDimValue() { double result = 0.0; if (!has2DReferences()) { //happens during Dimension creation - Base::Console().Message("INFO - DVD::getDimValue - Dimension has no References\n"); + Base::Console().Log("INFO - DVD::getDimValue - Dimension has no References\n"); return result; } if (!getViewPart()->hasGeometry()) { //happens when loading saved document - Base::Console().Message("INFO - DVD::getDimValue ViewPart has no Geometry yet\n"); + Base::Console().Log("INFO - DVD::getDimValue ViewPart has no Geometry yet\n"); return result; } @@ -273,6 +270,12 @@ double DrawViewDimension::getDimValue() const // Projected Values const std::vector &objects = References2D.getValues(); const std::vector &subElements = References2D.getSubValues(); + + if (!checkReferences2D()) { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } if ( Type.isValue("Distance") || Type.isValue("DistanceX") || Type.isValue("DistanceY") ) { @@ -280,7 +283,14 @@ double DrawViewDimension::getDimValue() const //TODO: Check for straight line Edge? int idx = DrawUtil::getIndexFromName(subElements[0]); TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Generic* gen = static_cast(geom); + TechDrawGeometry::Generic* gen; + if (geom && geom->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen = static_cast(geom); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } Base::Vector2d start = gen->points[0]; Base::Vector2d end = gen->points[1]; Base::Vector2d line = end - start; @@ -296,9 +306,23 @@ double DrawViewDimension::getDimValue() const int idx0 = DrawUtil::getIndexFromName(subElements[0]); int idx1 = DrawUtil::getIndexFromName(subElements[1]); TechDrawGeometry::BaseGeom* geom0 = getViewPart()->getProjEdgeByIndex(idx0); + TechDrawGeometry::Generic* gen0; + if (geom0 && geom0->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen0 = static_cast(geom0); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } TechDrawGeometry::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1); - TechDrawGeometry::Generic* gen0 = static_cast(geom0); - TechDrawGeometry::Generic* gen1 = static_cast(geom1); + TechDrawGeometry::Generic* gen1; + if (geom1 && geom1->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen1 = static_cast(geom1); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } Base::Vector2d s0 = gen0->points[0]; Base::Vector2d e0 = gen0->points[1]; Base::Vector2d s1 = gen1->points[0]; @@ -319,7 +343,13 @@ double DrawViewDimension::getDimValue() const int idx1 = DrawUtil::getIndexFromName(subElements[1]); TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); - Base::Vector2d start = v0->pnt; + if ((v0 == nullptr) || + (v1 == nullptr) ) { + Base::Console().Error("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } + Base::Vector2d start = v0->pnt; //v0 != nullptr, but v0->pnt is invalid Base::Vector2d end = v1->pnt; Base::Vector2d line = end - start; if (Type.isValue("Distance")) { @@ -341,6 +371,12 @@ double DrawViewDimension::getDimValue() const e = getViewPart()->getProjEdgeByIndex(idx1); v = getViewPart()->getProjVertexByIndex(idx0); } + if ((v == nullptr) || + (e == nullptr) ) { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } Base::Vector2d nearPoint = e->nearPoint(v->pnt); Base::Vector2d line = nearPoint - v->pnt; if (Type.isValue("Distance")) { @@ -355,76 +391,99 @@ double DrawViewDimension::getDimValue() const //only 1 reference for a Radius int idx = DrawUtil::getIndexFromName(subElements[0]); TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Circle* circle = static_cast (base); + TechDrawGeometry::Circle* circle; + if( (base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || + (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { + circle = static_cast (base); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } 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]); TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Circle* circle = static_cast (base); + TechDrawGeometry::Circle* circle; + if ((base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || + (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { + circle = static_cast (base); + } else { + return result; + } 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"); + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; } int idx0 = DrawUtil::getIndexFromName(subElements[0]); int idx1 = DrawUtil::getIndexFromName(subElements[1]); auto viewPart( dynamic_cast(objects[0]) ); if( viewPart == nullptr ) { - Base::Console().Message("INFO - DVD::getDimValue - References2D not DrawViewPart\n"); - return 0.0; + Base::Console().Log("INFO - DVD::getDimValue - References2D not DrawViewPart\n"); + return result; } TechDrawGeometry::BaseGeom* edge0 = viewPart->getProjEdgeByIndex(idx0); TechDrawGeometry::BaseGeom* edge1 = viewPart->getProjEdgeByIndex(idx1); - - // Only can find angles with straight line edges - if(edge0->geomType == TechDrawGeometry::GENERIC && - edge1->geomType == TechDrawGeometry::GENERIC) { - TechDrawGeometry::Generic *gen1 = static_cast(edge0); - TechDrawGeometry::Generic *gen2 = static_cast(edge1); - - Base::Vector3d p1S(gen1->points.at(0).x, gen1->points.at(0).y, 0.); - Base::Vector3d p1E(gen1->points.at(1).x, gen1->points.at(1).y, 0.); - - Base::Vector3d p2S(gen2->points.at(0).x, gen2->points.at(0).y, 0.); - Base::Vector3d p2E(gen2->points.at(1).x, gen2->points.at(1).y, 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).x - dir1.x*gen1->points.at(0).y; - double c2 = dir2.y*gen2->points.at(1).x - dir2.x*gen2->points.at(1).y; - 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; + TechDrawGeometry::Generic *gen1; + TechDrawGeometry::Generic *gen2; + if (edge0 && edge0->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen1 = static_cast(edge0); } else { - throw Base::Exception("getDimValue() - Unknown Dimension Type (2)"); + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; } + if (edge1 && edge1->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen2 = static_cast(edge1); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + References2D.setValue(nullptr,""); + return result; + } + + Base::Vector3d p1S(gen1->points.at(0).x, gen1->points.at(0).y, 0.); + Base::Vector3d p1E(gen1->points.at(1).x, gen1->points.at(1).y, 0.); + + Base::Vector3d p2S(gen2->points.at(0).x, gen2->points.at(0).y, 0.); + Base::Vector3d p2E(gen2->points.at(1).x, gen2->points.at(1).y, 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).x - dir1.x*gen1->points.at(0).y; + double c2 = dir2.y*gen2->points.at(1).x - dir2.x*gen2->points.at(1).y; + 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; @@ -481,6 +540,33 @@ int DrawViewDimension::getRefType2(const std::string g1, const std::string g2) return refType; } +//! validate 2D references - only checks if they exist, not if they are the right type +bool DrawViewDimension::checkReferences2D() const +{ + bool result = true; + //const std::vector &objects = References2D.getValues(); + const std::vector &subElements = References2D.getSubValues(); + + for (auto& s: subElements) { + int idx = DrawUtil::getIndexFromName(s); + if (DrawUtil::getGeomTypeFromName(s) == "Edge") { + TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); + if (geom == nullptr) { + result = false; + break; + } + } else if (DrawUtil::getGeomTypeFromName(s) == "Vertex") { + TechDrawGeometry::Vertex* v = getViewPart()->getProjVertexByIndex(idx); + if (v == nullptr) { + result = false; + break; + } + } + } + return result; +} + + //!add Dimension 3D references to measurement void DrawViewDimension::setAll3DMeasurement() { @@ -535,7 +621,7 @@ double DrawViewDimension::dist2Segs(Base::Vector2d s1, BRepExtrema_DistShapeShape extss(edge1, edge2); if (!extss.IsDone()) { - throw Base::Exception("FVD - BRepExtrema_DistShapeShape failed"); + throw Base::Exception("DVD - BRepExtrema_DistShapeShape failed"); } int count = extss.NbSolution(); double minDist = 0.0; @@ -548,7 +634,18 @@ double DrawViewDimension::dist2Segs(Base::Vector2d s1, bool DrawViewDimension::has2DReferences(void) const { - return (References2D.getSize() > 0); + bool result = false; + const std::vector &objects = References2D.getValues(); + const std::vector &SubNames = References2D.getSubValues(); + if (!objects.empty()) { + App::DocumentObject* testRef = objects.at(0); + if (testRef != nullptr) { + if (!SubNames.empty()) { + result = true; + } + } + } + return result; } bool DrawViewDimension::has3DReferences(void) const diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index 78420fa4ce..8330c09d9c 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -65,9 +65,6 @@ public: App::PropertyFloat LineWidth; //App::PropertyBool CentreLines; - //TODO: do we need a property for the actual dimension value? how else to access from Py? - //wf: expose getValue & getFormatedValue - short mustExecute() const; bool has2DReferences(void) const; bool has3DReferences(void) const; @@ -85,8 +82,8 @@ public: //return PyObject as DrawViewDimensionPy virtual PyObject *getPyObject(void); - virtual std::string getFormatedValue() const; - virtual double getDimValue() const; + virtual std::string getFormatedValue(); + virtual double getDimValue(); DrawViewPart* getViewPart() const; virtual QRectF getRect() const { return QRectF(0,0,1,1);} //pretend dimensions always fit! static int getRefType1(const std::string s); @@ -94,11 +91,11 @@ public: int getRefType() const; //Vertex-Vertex, Edge, Edge-Edge void setAll3DMeasurement(); void clear3DMeasurements(void); + bool checkReferences2D(void) const; protected: void onChanged(const App::Property* prop); virtual void onDocumentRestored(); - int getIndexFromName(std::string geomName) const; bool showUnits() const; protected: diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index ca58c4855a..a280f33d22 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -57,18 +58,23 @@ #include #include #include +#include +#include +#include + #include #include #include +#include #endif #include #include #include -#include #include +#include #include #include #include @@ -78,10 +84,12 @@ #include "DrawUtil.h" #include "DrawViewSection.h" +#include "DrawProjectSplit.h" #include "Geometry.h" #include "GeometryObject.h" #include "DrawViewPart.h" #include "DrawHatch.h" +#include "DrawGeomHatch.h" #include "EdgeWalker.h" @@ -103,6 +111,7 @@ DrawViewPart::DrawViewPart(void) : geometryObject(0) static const char *group = "Projection"; static const char *fgroup = "Format"; static const char *sgroup = "Show"; + nowDeleting = false; //properties that affect Geometry ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"3D Shape to view"); @@ -145,19 +154,17 @@ App::DocumentObjectExecReturn *DrawViewPart::execute(void) { App::DocumentObject *link = Source.getValue(); if (!link) { - return new App::DocumentObjectExecReturn("FVP - No Source object linked"); + return new App::DocumentObjectExecReturn("DVP - No Source object linked"); } if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - return new App::DocumentObjectExecReturn("FVP - Linked object is not a Part object"); + return new App::DocumentObjectExecReturn("DVP - Linked object is not a Part object"); } TopoDS_Shape shape = static_cast(link)->Shape.getShape().getShape(); if (shape.IsNull()) { - return new App::DocumentObjectExecReturn("FVP - Linked shape object is empty"); + return new App::DocumentObjectExecReturn("DVP - Linked shape object is empty"); } - //Base::Console().Message("TRACE - DVP::execute() - %s - %s - dir: %s\n",getNameInDocument(), Label.getValue(),DrawUtil::formatVector(Direction.getValue()).c_str()); - (void) DrawView::execute(); //make sure Scale is up to date @@ -223,7 +230,7 @@ void DrawViewPart::onChanged(const App::Property* prop) //note: slightly different than routine with same name in DrawProjectSplit TechDrawGeometry::GeometryObject* DrawViewPart::buildGeometryObject(TopoDS_Shape shape, gp_Ax2 viewAxis) { - TechDrawGeometry::GeometryObject* go = new TechDrawGeometry::GeometryObject(getNameInDocument()); + TechDrawGeometry::GeometryObject* go = new TechDrawGeometry::GeometryObject(getNameInDocument(), this); go->setIsoCount(IsoCount.getValue()); Base::Vector3d baseProjDir = Direction.getValue(); @@ -389,7 +396,6 @@ void DrawViewPart::extractFaces() } } - std::vector DrawViewPart::getHatches() const { std::vector result; @@ -403,6 +409,19 @@ std::vector DrawViewPart::getHatches() const return result; } +std::vector DrawViewPart::getGeomHatches() const +{ + std::vector result; + std::vector children = getInList(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawGeomHatch::getClassTypeId())) { + TechDraw::DrawGeomHatch* geom = dynamic_cast(*it); + result.push_back(geom); + } + } + return result; +} + const std::vector & DrawViewPart::getVertexGeometry() const { return geometryObject->getVertexGeometry(); @@ -426,7 +445,11 @@ TechDrawGeometry::BaseGeom* DrawViewPart::getProjEdgeByIndex(int idx) const Base::Console().Log("INFO - getProjEdgeByIndex(%d) - no Edge Geometry. Probably restoring?\n",idx); return NULL; } - return geoms[idx]; + if ((unsigned)idx >= geoms.size()) { + Base::Console().Log("INFO - getProjEdgeByIndex(%d) - invalid index\n",idx); + return NULL; + } + return geoms.at(idx); } //! returns existing geometry of 2D Vertex(idx) @@ -437,13 +460,20 @@ TechDrawGeometry::Vertex* DrawViewPart::getProjVertexByIndex(int idx) const Base::Console().Log("INFO - getProjVertexByIndex(%d) - no Vertex Geometry. Probably restoring?\n",idx); return NULL; } - return geoms[idx]; + if ((unsigned)idx >= geoms.size()) { + Base::Console().Log("INFO - getProjVertexByIndex(%d) - invalid index\n",idx); + return NULL; + } + return geoms.at(idx); } + +//this is never used!! //! returns existing geometry of 2D Face(idx) //version 1 Face has 1 wire -std::vector DrawViewPart::getProjFaceByIndex(int /*idx*/) const +std::vector DrawViewPart::getProjFaceByIndex(int idx) const { + (void) idx; std::vector result; const std::vector& faces = getFaceGeometry(); for (auto& f:faces) { @@ -456,6 +486,29 @@ std::vector DrawViewPart::getProjFaceByIndex(int /* return result; } +std::vector DrawViewPart::getWireForFace(int idx) const +{ +// Base::Console().Message("TRACE - DVP::getWireForFace(%d)\n",idx); + std::vector result; + std::vector edges; + const std::vector& faces = getFaceGeometry(); + TechDrawGeometry::Face * ourFace = faces.at(idx); + for (auto& w:ourFace->wires) { + edges.clear(); + int i = 0; + for (auto& g:w->geoms) { + edges.push_back(g->occEdge); +// DrawUtil::dumpEdge("DVP Face edge",i,g->occEdge); + i++; + } + TopoDS_Wire occwire = EdgeWalker::makeCleanWire(edges); +// BRepLib::BuildCurves3d(occwire); //probably don't need this + result.push_back(occwire); + } + +// Base::Console().Message("TRACE - DVP::getWireForFace(%d) returns %d wires\n",idx,result.size()); + return result; +} Base::BoundBox3d DrawViewPart::getBoundingBox() const { @@ -559,12 +612,24 @@ const std::vector DrawViewPart::getVisibleFaceEdg return geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue()); } +//is this really the projection plane?? +gp_Pln DrawViewPart::getProjPlane() const +{ + Base::Vector3d plnPnt(0.0,0.0,0.0); + Base::Vector3d plnNorm = Direction.getValue(); + gp_Ax2 viewAxis = getViewAxis(plnPnt,plnNorm,false); + gp_Ax3 viewAxis3(viewAxis); + + return gp_Pln(viewAxis3); +} + void DrawViewPart::getRunControl() { Base::Reference hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/General"); - m_sectionEdges = hGrp->GetBool("ShowSectionEdges", 1l); + m_sectionEdges = hGrp->GetBool("ShowSectionEdges", 0l); m_handleFaces = hGrp->GetBool("HandleFaces", 1l); + //Base::Console().Message("TRACE - DVP::getRunControl - handleFaces: %d\n",m_handleFaces); } bool DrawViewPart::handleFaces(void) @@ -577,6 +642,25 @@ bool DrawViewPart::showSectionEdges(void) return m_sectionEdges; } +void DrawViewPart::unsetupObject() +{ + nowDeleting = true; + + // Remove the View's Hatches from document + App::Document* doc = getDocument(); + std::string docName = doc->getName(); + + std::vector hatches = getHatches(); + + std::vector::iterator it = hatches.begin(); + for (; it != hatches.end(); it++) { + std::string viewName = (*it)->getNameInDocument(); + Base::Interpreter().runStringArg("App.getDocument(\"%s\").removeObject(\"%s\")", + docName.c_str(), viewName.c_str()); + } +} + + PyObject *DrawViewPart::getPyObject(void) { if (PythonObject.is(Py::_None())) { diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index 9abc812479..12fef1c539 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -37,9 +37,14 @@ #include #include "DrawView.h" -#include "DrawProjectSplit.h" class gp_Pnt; +class gp_Pln; +class gp_Ax2; +//class TopoDS_Edge; +//class TopoDS_Vertex; +//class TopoDS_Wire; +//class TopoDS_Shape; namespace TechDrawGeometry { @@ -51,6 +56,9 @@ class Face; namespace TechDraw { class DrawHatch; +class DrawGeomHatch; +class DrawProjectSplit; +class DrawViewSection; } namespace TechDraw @@ -91,6 +99,7 @@ public: std::vector getHatches(void) const; + std::vector getGeomHatches(void) const; //TODO: are there use-cases for Python access to TechDrawGeometry??? @@ -135,12 +144,19 @@ public: } //return PyObject as DrawViewPartPy virtual PyObject *getPyObject(void); + bool isDeleting(void) { return nowDeleting; } + + gp_Pln getProjPlane(void) const; + virtual std::vector getWireForFace(int idx) const; + protected: TechDrawGeometry::GeometryObject *geometryObject; Base::BoundBox3d bbox; void onChanged(const App::Property* prop); + virtual void unsetupObject(); + virtual TechDrawGeometry::GeometryObject* buildGeometryObject(TopoDS_Shape shape, gp_Ax2 viewAxis); void extractFaces(); @@ -156,6 +172,7 @@ protected: bool m_handleFaces; private: + bool nowDeleting; }; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index 55dbd10ce0..d22753b1f4 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -63,20 +64,24 @@ # include #include +#include #include #include #include #include +#include #include #include #include "Geometry.h" #include "GeometryObject.h" +#include "HatchLine.h" #include "EdgeWalker.h" #include "DrawUtil.h" #include "DrawProjGroupItem.h" #include "DrawProjectSplit.h" +#include "DrawGeomHatch.h" #include "DrawViewSection.h" using namespace TechDraw; @@ -110,11 +115,17 @@ DrawViewSection::DrawViewSection() SectionDirection.setEnums(SectionDirEnums); ADD_PROPERTY_TYPE(SectionDirection,((long)0),sgroup, App::Prop_None, "Direction in Base View for this Section"); - ADD_PROPERTY_TYPE(ShowCutSurface ,(true),fgroup,App::Prop_None,"Shade the cut surface"); - ADD_PROPERTY_TYPE(CutSurfaceColor,(0.0,0.0,0.0),fgroup,App::Prop_None,"The color to shade the cut surface"); - ADD_PROPERTY_TYPE(HatchCutSurface ,(false),fgroup,App::Prop_None,"Hatch the cut surface"); - ADD_PROPERTY_TYPE(HatchPattern ,(""),fgroup,App::Prop_None,"The hatch pattern file for the cut surface"); - ADD_PROPERTY_TYPE(HatchColor,(0.0,0.0,0.0),fgroup,App::Prop_None,"The color of the hatch pattern"); + ADD_PROPERTY_TYPE(FileHatchPattern ,(""),fgroup,App::Prop_None,"The hatch pattern file for the cut surface"); + ADD_PROPERTY_TYPE(NameGeomPattern ,(""),fgroup,App::Prop_None,"The pattern name for geometric hatching"); + ADD_PROPERTY_TYPE(HatchScale,(1.0),fgroup,App::Prop_None,"Hatch pattern size adjustment"); + +// ADD_PROPERTY_TYPE(ShowCutSurface ,(true),fgroup,App::Prop_None,"Show/hide the cut surface"); +// ADD_PROPERTY_TYPE(CutSurfaceColor,(0.0,0.0,0.0),fgroup,App::Prop_None,"The color to shade the cut surface"); +// ADD_PROPERTY_TYPE(HatchCutSurface ,(false),fgroup,App::Prop_None,"Hatch the cut surface"); +// ADD_PROPERTY_TYPE(FileHatchPattern ,(""),fgroup,App::Prop_None,"The hatch pattern file for the cut surface"); +// ADD_PROPERTY_TYPE(NameGeomPattern ,(""),fgroup,App::Prop_None,"The pattern name for geometric hatching"); +// ADD_PROPERTY_TYPE(HatchColor,(0.0,0.0,0.0),fgroup,App::Prop_None,"The color of the hatch pattern"); + getParameters(); @@ -158,6 +169,23 @@ void DrawViewSection::onChanged(const App::Property* prop) } } } + if (prop == &FileHatchPattern || + prop == &NameGeomPattern ) { + if ((!FileHatchPattern.isEmpty()) && + (!NameGeomPattern.isEmpty())) { + std::vector specs = + DrawGeomHatch::getDecodedSpecsFromFile(FileHatchPattern.getValue(),NameGeomPattern.getValue()); + m_lineSets.clear(); + for (auto& hl: specs) { + //hl.dump("hl from section"); + LineSet ls; + ls.setHatchLine(hl); + m_lineSets.push_back(ls); + } + + } + } + DrawView::onChanged(prop); } @@ -248,10 +276,12 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void) inputCenter, Scale.getValue()); + sectionFaceWires.clear(); TopoDS_Compound newFaces; BRep_Builder builder; builder.MakeCompound(newFaces); TopExp_Explorer expl(mirroredSection, TopAbs_FACE); + int idb = 0; for (; expl.More(); expl.Next()) { const TopoDS_Face& face = TopoDS::Face(expl.Current()); TopoDS_Face pFace = projectFace(face, @@ -259,8 +289,9 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void) Direction.getValue()); if (!pFace.IsNull()) { builder.Add(newFaces,pFace); + sectionFaceWires.push_back(ShapeAnalysis::OuterWire(pFace)); } - + idb++; } sectionFaces = newFaces; } @@ -505,6 +536,25 @@ Base::Vector3d DrawViewSection::getSectionVector (const std::string sectionName) return adjResult; } +std::vector DrawViewSection::getDrawableLines(int i) +{ + std::vector result; + result = DrawGeomHatch::getDrawableLines(this,m_lineSets,i,HatchScale.getValue()); + return result; +} + +std::vector DrawViewSection::getWireForFace(int idx) const +{ + std::vector result; + result.push_back(sectionFaceWires.at(idx)); + return result; +} + +void DrawViewSection::unsetupObject() +{ + getBaseDVP()->touch(); +} + TechDraw::DrawViewPart* DrawViewSection::getBaseDVP() { TechDraw::DrawViewPart* baseDVP = nullptr; @@ -528,26 +578,20 @@ TechDraw::DrawProjGroupItem* DrawViewSection::getBaseDPGI() void DrawViewSection::getParameters() { Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors"); - App::Color cutColor = App::Color((uint32_t) hGrp->GetUnsigned("CutSurfaceColor", 0xC8C8C800)); - CutSurfaceColor.setValue(cutColor); - App::Color hatchColor = App::Color((uint32_t) hGrp->GetUnsigned("SectionHatchColor", 0x00000000)); - HatchColor.setValue(hatchColor); - - hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw"); std::string defaultDir = App::Application::getResourceDir() + "Mod/Drawing/patterns/"; std::string defaultFileName = defaultDir + "simple.svg"; - QString patternFileName = QString::fromStdString(hGrp->GetASCII("PatternFile",defaultFileName.c_str())); + QString patternFileName = QString::fromStdString(hGrp->GetASCII("FileHatch",defaultFileName.c_str())); if (patternFileName.isEmpty()) { patternFileName = QString::fromStdString(defaultFileName); } QFileInfo tfi(patternFileName); if (tfi.isReadable()) { - HatchPattern.setValue(patternFileName.toUtf8().constData()); + FileHatchPattern.setValue(patternFileName.toUtf8().constData()); } - + std::string patternName = hGrp->GetASCII("PatternName","Diamond"); + NameGeomPattern.setValue(patternName); } // Python Drawing feature --------------------------------------------------------- diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index 5096ef1d08..bbabec8297 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -45,16 +45,16 @@ class Face; namespace TechDraw { class DrawProjGroupItem; +class DrawGeomHatch; +class HatchLine; +class LineSet; +class DashSet; - -/** Base class of all View Features in the drawing module - */ class TechDrawExport DrawViewSection : public DrawViewPart { PROPERTY_HEADER(Part::DrawViewSection); public: - /// Constructor DrawViewSection(void); virtual ~DrawViewSection(); @@ -62,23 +62,16 @@ public: App::PropertyVector SectionNormal; App::PropertyVector SectionOrigin; App::PropertyEnumeration SectionDirection; - App::PropertyBool ShowCutSurface; - App::PropertyColor CutSurfaceColor; - App::PropertyBool HatchCutSurface; - App::PropertyFile HatchPattern; - App::PropertyColor HatchColor; + App::PropertyFile FileHatchPattern; + App::PropertyString NameGeomPattern; + App::PropertyFloat HatchScale; App::PropertyString SectionSymbol; virtual short mustExecute() const; bool isReallyInBox (const Base::Vector3d v, const Base::BoundBox3d bb) 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"; } @@ -88,11 +81,22 @@ public: Base::Vector3d getSectionVector (const std::string sectionName); TechDraw::DrawViewPart* getBaseDVP(); TechDraw::DrawProjGroupItem* getBaseDPGI(); + virtual void unsetupObject(); + + virtual std::vector getWireForFace(int idx) const; + TopoDS_Compound getSectionFaces() { return sectionFaces;}; + std::vector getSectionFaceWires(void) { return sectionFaceWires; } + + std::vector getDrawableLines(int i = 0); + std::vector getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern); static const char* SectionDirEnums[]; protected: TopoDS_Compound sectionFaces; + std::vector sectionFaceWires; + std::vector m_lineSets; + gp_Pln getSectionPlane() const; TopoDS_Compound findSectionPlaneIntersections(const TopoDS_Shape& shape); diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.cpp b/src/Mod/TechDraw/App/DrawViewSymbol.cpp index afec6bc3fc..2a63f39bd8 100644 --- a/src/Mod/TechDraw/App/DrawViewSymbol.cpp +++ b/src/Mod/TechDraw/App/DrawViewSymbol.cpp @@ -35,6 +35,7 @@ #include #include +#include "DrawPage.h" #include "DrawViewSymbol.h" using namespace TechDraw; @@ -117,29 +118,43 @@ App::DocumentObjectExecReturn *DrawViewSymbol::execute(void) QRectF DrawViewSymbol::getRect() const { - std::string svg = Symbol.getValue(); double w = 64.0; //must default to something double h = 64.0; - string::const_iterator begin, end; - begin = svg.begin(); - end = svg.end(); - boost::match_results what; + return (QRectF(0,0,w,h)); +// std::string svg = Symbol.getValue(); +// string::const_iterator begin, end; +// begin = svg.begin(); +// end = svg.end(); +// boost::match_results what; - boost::regex e1 ("width=\"([0-9.]*?)[a-zA-Z]*?\""); - if (boost::regex_search(begin, end, what, e1)) { - //std::string wText = what[0].str(); //this is the whole match 'width="100"' - std::string wNum = what[1].str(); //this is just the number 100 - w = std::stod(wNum); - } - boost::regex e2 ("Height=\"([0-9.]*?)[a-zA-Z]*?\""); - if (boost::regex_search(begin, end, what, e1)) { - //std::string hText = what[0].str(); - std::string hNum = what[1].str(); - h = std::stod(hNum); - } - return (QRectF(0,0,Scale.getValue() * w,Scale.getValue() * h)); +// boost::regex e1 ("width=\"([0-9.]*?)[a-zA-Z]*?\""); +// if (boost::regex_search(begin, end, what, e1)) { +// //std::string wText = what[0].str(); //this is the whole match 'width="100"' +// std::string wNum = what[1].str(); //this is just the number 100 +// w = std::stod(wNum); +// } +// +// boost::regex e2 ("height=\"([0-9.]*?)[a-zA-Z]*?\""); +// if (boost::regex_search(begin, end, what, e2)) { +// //std::string hText = what[0].str(); +// std::string hNum = what[1].str(); +// h = std::stod(hNum); +// } +// return (QRectF(0,0,Scale.getValue() * w,Scale.getValue() * h)); +//we now have a w x h, but we don't really know what it means - px,mm,in,... + } +//!Assume all svg files fit the page and/or the user will scale manually +//see getRect() above +bool DrawViewSymbol::checkFit(TechDraw::DrawPage* p) const +{ + (void)p; + bool result = true; + return result; +} + + // Python Drawing feature --------------------------------------------------------- diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.h b/src/Mod/TechDraw/App/DrawViewSymbol.h index 665b42fcb3..da7e049c23 100644 --- a/src/Mod/TechDraw/App/DrawViewSymbol.h +++ b/src/Mod/TechDraw/App/DrawViewSymbol.h @@ -32,6 +32,7 @@ namespace TechDraw { +class DrawPage; class TechDrawExport DrawViewSymbol : public TechDraw::DrawView @@ -57,6 +58,8 @@ public: return "TechDrawGui::ViewProviderSymbol"; } virtual QRectF getRect() const; + virtual bool checkFit(TechDraw::DrawPage* p) const override; + protected: virtual void onChanged(const App::Property* prop); diff --git a/src/Mod/TechDraw/App/EdgeWalker.cpp b/src/Mod/TechDraw/App/EdgeWalker.cpp index 1507f419c8..bd6c3b6e98 100644 --- a/src/Mod/TechDraw/App/EdgeWalker.cpp +++ b/src/Mod/TechDraw/App/EdgeWalker.cpp @@ -265,7 +265,7 @@ std::vector EdgeWalker::getResultNoDups() return fw; } - +//* static *// //! make a clean wire with sorted, oriented, connected, etc edges TopoDS_Wire EdgeWalker::makeCleanWire(std::vector edges, double tol) { diff --git a/src/Mod/TechDraw/App/EdgeWalker.h b/src/Mod/TechDraw/App/EdgeWalker.h index 2eeb493336..6556e3d78d 100644 --- a/src/Mod/TechDraw/App/EdgeWalker.h +++ b/src/Mod/TechDraw/App/EdgeWalker.h @@ -175,7 +175,7 @@ public: int findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert); std::vector sortStrip(std::vector fw, bool includeBiggest); std::vector sortWiresBySize(std::vector& w, bool reverse = false); - TopoDS_Wire makeCleanWire(std::vector edges, double tol = 0.10); + static TopoDS_Wire makeCleanWire(std::vector edges, double tol = 0.10); std::vector getEmbeddingRowIx(int v); std::vector getEmbeddingRow(int v); diff --git a/src/Mod/TechDraw/App/GeometryObject.cpp b/src/Mod/TechDraw/App/GeometryObject.cpp index e630d805df..42ee5619ed 100644 --- a/src/Mod/TechDraw/App/GeometryObject.cpp +++ b/src/Mod/TechDraw/App/GeometryObject.cpp @@ -67,6 +67,7 @@ #include "DrawUtil.h" #include "GeometryObject.h" #include "DrawViewPart.h" +#include "DrawViewDetail.h" using namespace TechDrawGeometry; using namespace TechDraw; @@ -77,9 +78,9 @@ struct EdgePoints { TopoDS_Edge edge; }; -GeometryObject::GeometryObject(const string& parent) : - Scale(1.f), +GeometryObject::GeometryObject(const string& parent, TechDraw::DrawView* parentObj) : m_parentName(parent), + m_parent(parentObj), m_isoCount(0) { } @@ -89,12 +90,6 @@ GeometryObject::~GeometryObject() clear(); } -void GeometryObject::setScale(double value) -{ - Scale = value; -} - - const std::vector GeometryObject::getVisibleFaceEdges(const bool smooth, const bool seam) const { std::vector result; @@ -157,17 +152,6 @@ void GeometryObject::projectShape(const TopoDS_Shape& input, // Clear previous Geometry clear(); -//******* - gp_Dir x = viewAxis.XDirection(); - gp_Dir y = viewAxis.YDirection(); - gp_Dir z = viewAxis.Direction(); - Base::Vector3d vx(x.X(),x.Y(),x.Z()); - Base::Vector3d vy(y.X(),y.Y(),y.Z()); - Base::Vector3d vz(z.X(),z.Y(),z.Z()); -// Base::Console().Message("TRACE - GO::projectShape - %s viewAxis x: %s y: %s Z: %s\n",m_parentName.c_str(), -// DrawUtil::formatVector(vx).c_str(), DrawUtil::formatVector(vy).c_str(), DrawUtil::formatVector(vz).c_str()); -//******* - auto start = chrono::high_resolution_clock::now(); Handle_HLRBRep_Algo brep_hlr = NULL; @@ -177,7 +161,8 @@ void GeometryObject::projectShape(const TopoDS_Shape& input, HLRAlgo_Projector projector( viewAxis ); brep_hlr->Projector(projector); brep_hlr->Update(); - brep_hlr->Hide(); + brep_hlr->Hide(); //XXXX: what happens if we don't call Hide()?? and only look at VCompound? + // WF: you get back all the edges in the shape, but very fast!! } catch (...) { Standard_Failure::Raise("GeometryObject::projectShape - error occurred while projecting shape"); @@ -301,6 +286,7 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca edgeGeom.push_back(base); //add vertices of new edge if not already in list + bool skipDetail = false; if (visible) { BaseGeom* lastAdded = edgeGeom.back(); bool v1Add = true, v2Add = true; @@ -310,9 +296,23 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca TechDrawGeometry::Circle* circle = dynamic_cast(lastAdded); TechDrawGeometry::Vertex* c1 = nullptr; if (circle) { - c1 = new TechDrawGeometry::Vertex(circle->center); - c1->isCenter = true; - c1->visible = true; + // if this is the center of a detail view, skip it + TechDraw::DrawViewDetail* detail = isParentDetail(); + if (detail != nullptr) { + double scale = m_parent->Scale.getValue(); + if ( ((circle->center - Base::Vector2d(0.0,0.0)).Length() < Precision::Confusion()) && + (DrawUtil::fpCompare(circle->radius, scale * detail->getFudgeRadius())) ) { + skipDetail = true; + } else { + c1 = new TechDrawGeometry::Vertex(circle->center); + c1->isCenter = true; + c1->visible = true; + } + } else { + c1 = new TechDrawGeometry::Vertex(circle->center); + c1->isCenter = true; + c1->visible = true; + } } std::vector::iterator itVertex = vertexGeom.begin(); @@ -323,7 +323,7 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca if ((*itVertex)->isEqual(v2,Precision::Confusion())) { v2Add = false; } - if (circle) { + if (circle && !skipDetail) { if ((*itVertex)->isEqual(c1,Precision::Confusion())) { c1Add = false; } @@ -343,7 +343,7 @@ void GeometryObject::addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass ca delete v2; } - if (circle) { + if (circle && !skipDetail) { if (c1Add) { vertexGeom.push_back(c1); c1->visible = true; @@ -367,6 +367,18 @@ void GeometryObject::addFaceGeom(Face* f) faceGeom.push_back(f); } +TechDraw::DrawViewDetail* GeometryObject::isParentDetail() +{ + TechDraw::DrawViewDetail* result = nullptr; + if (m_parent != nullptr) { + TechDraw::DrawViewDetail* detail = dynamic_cast(m_parent); + if (detail != nullptr) { + result = detail; + } + } + return result; +} + bool GeometryObject::isWithinArc(double theta, double first, double last, bool cw) const @@ -439,16 +451,6 @@ bool GeometryObject::findVertex(Base::Vector2d v) return found; } - -//"Top" X should == "Front" X for front = [front,rear] -//"Top" X should == "Front" X for front = [right] -//"Top" X should == "Front" -X for front = [left] -//"Top" X should == "Front" X for front = [top,bottom] -//view XAxis == anchor XAxis except -// anchor.ProjDir = (-1,0,0) then -// view XAxis == -Anchor XAxis - - /// utility non-class member functions //! gets a coordinate system that matches view system used in 3D with +Z up (or +Y up if neccessary) //! used for individual views, but not secondary views in projection groups @@ -464,9 +466,9 @@ gp_Ax2 TechDrawGeometry::getViewAxis(const Base::Vector3d origin, } Base::Vector3d cross = flipDirection; //special cases - if (flipDirection == stdZ) { + if ((flipDirection - stdZ).Length() < Precision::Confusion()) { cross = Base::Vector3d(1.0,0.0,0.0); - } else if (flipDirection == (stdZ * -1.0)) { + } else if ((flipDirection - (stdZ * -1.0)).Length() < Precision::Confusion()) { cross = Base::Vector3d(1.0,0.0,0.0); } else { cross.Normalize(); diff --git a/src/Mod/TechDraw/App/GeometryObject.h b/src/Mod/TechDraw/App/GeometryObject.h index 36d58c1475..5461a4de16 100644 --- a/src/Mod/TechDraw/App/GeometryObject.h +++ b/src/Mod/TechDraw/App/GeometryObject.h @@ -34,14 +34,20 @@ #include "Geometry.h" + namespace TechDraw { class DrawViewPart; +class DrawViewDetail; class DrawView; } namespace TechDrawGeometry { +class BaseGeom; +class Vector; +class Face; +class Vertex; //! scales & mirrors a shape about a center TopoDS_Shape TechDrawExport mirrorShape(const TopoDS_Shape &input, @@ -66,13 +72,11 @@ class TechDrawExport GeometryObject { public: /// Constructor - GeometryObject(const std::string& parent); + GeometryObject(const std::string& parent, TechDraw::DrawView* parentObj); virtual ~GeometryObject(); void clear(); - void setScale(double value); - //! Returns 2D bounding box Base::BoundBox3d calcBoundingBox() const; @@ -104,7 +108,7 @@ protected: TopoDS_Shape hidIso; void addGeomFromCompound(TopoDS_Shape edgeCompound, edgeClass category, bool visible); - + TechDraw::DrawViewDetail* isParentDetail(void); //similar function in Geometry? /*! @@ -120,9 +124,8 @@ protected: bool findVertex(Base::Vector2d v); - double Scale; - std::string m_parentName; + TechDraw::DrawView* m_parent; int m_isoCount; }; diff --git a/src/Mod/TechDraw/App/HatchLine.cpp b/src/Mod/TechDraw/App/HatchLine.cpp new file mode 100644 index 0000000000..3f36c9b2ae --- /dev/null +++ b/src/Mod/TechDraw/App/HatchLine.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (c) 2017 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 +#endif + +#include + +#include +#include + +#include "Geometry.h" + +#include "DrawUtil.h" +#include "HatchLine.h" + +using namespace TechDraw; + +HatchLine::HatchLine() +{ + init(); +} + +HatchLine::HatchLine(std::string& lineSpec) +{ + init(); + load(lineSpec); +} + + +HatchLine::~HatchLine() +{ +} + +void HatchLine::init(void) +{ + m_angle = 0.0; + m_origin = Base::Vector3d(0.0,0.0,0.0); + m_interval = 1.0; + m_offset = 0.0; +} + +void HatchLine::load(std::string& lineSpec) +{ + std::vector values = split(lineSpec); + if (values.size() < 5) { + Base::Console().Message( "HatchLine::load(%s) invalid entry in pattern\n",lineSpec.c_str() ); + return; + } + m_angle = values[0]; + m_origin = Base::Vector3d(values[1],values[2],0.0); + m_offset = values[3]; + m_interval = values[4]; + if (values.size() > 5) { + m_dashParms.insert(std::end(m_dashParms), std::begin(values) + 5, std::end(values)); + } +} + +std::vector HatchLine::split(std::string line) +{ + std::vector result; + std::stringstream lineStream(line); + std::string cell; + + while(std::getline(lineStream,cell, ',')) + { + try { + result.push_back(std::stod(cell)); + } + catch (const std::invalid_argument& ia) { + Base::Console().Warning("Invalid number in cell: %s (%s) \n",cell.c_str(),ia.what()); + result.push_back(0.0); + } + } + return result; +} + +void HatchLine::dump(char* title) +{ + Base::Console().Message( "DUMP: %s\n",title); + Base::Console().Message( "Angle: %.3f\n", m_angle); + Base::Console().Message( "Origin: %s\n",DrawUtil::formatVector(m_origin).c_str()); + Base::Console().Message( "Offset: %.3f\n",m_offset); + Base::Console().Message( "Interval: %.3f\n",m_interval); + std::stringstream ss; + for (auto& d: m_dashParms) { + ss << d << ", "; + } + ss << "end"; + Base::Console().Message( "DashSpec: %s\n",ss.str().c_str()); +} + +//static class methods +std::vector HatchLine::getSpecsForPattern(std::string& parmFile, std::string& parmName) +{ + std::vector result; + std::vector lineSpecs; + std::ifstream inFile; + inFile.open (parmFile, std::ifstream::in); + if(!inFile.is_open()) { + Base::Console().Message( "Cannot open input file.\n"); + return result; + } + + //get all the definition lines for this pattern + bool status = findPatternStart(inFile, parmName); + if (status) { + lineSpecs = loadPatternDef(inFile); + } else { + Base::Console().Message( "Could not find pattern: %s\n",parmName.c_str() ); + return result; + } + + //decode definition lines into HatchLine objects + for (auto& l: lineSpecs) { + HatchLine hl(l); + result.push_back(hl); + } + return result; +} + +bool HatchLine::findPatternStart(std::ifstream& inFile, std::string& parmName) +{ + bool result = false; + while ( inFile.good() ){ + std::string line; + std::getline(inFile,line); + std::string nameTag = line.substr(0,1); + std::string patternName; + unsigned long int commaPos; + if ((nameTag == ";") || + (nameTag == " ") || + (line.empty()) ) { //is cr/lf empty? + continue; + } else if (nameTag == "*") { + commaPos = line.find(",",1); + if (commaPos != std::string::npos) { + patternName = line.substr(1,commaPos-1); + } else { + patternName = line.substr(1); + } + if (patternName == parmName) { + //this is our pattern + result = true; + break; + } + } + } //endwhile + return result; +} + +//get the definition lines for this pattern +std::vector HatchLine::loadPatternDef(std::ifstream& inFile) +{ + std::vector result; + while ( inFile.good() ){ + std::string line; + std::getline(inFile,line); + std::string nameTag = line.substr(0,1); + if ((nameTag == ";") || + (nameTag == " ") || + (line.empty()) ) { //is cr/lf empty? + continue; + } else if (nameTag == "*") { + break; + } else { //dataline + result.push_back(line); + } + } + return result; +} + +std::vector HatchLine::getPatternList(std::string& parmFile) +{ + std::vector result; + std::ifstream inFile; + inFile.open (parmFile, std::ifstream::in); + if(!inFile.is_open()) { + Base::Console().Message( "Cannot open input file.\n"); + return result; + } + + while ( inFile.good() ){ + std::string line; + std::getline(inFile,line); + std::string nameTag = line.substr(0,1); //dupl code here + unsigned long int commaPos; + if (nameTag == "*") { //found a pattern + commaPos = line.find(",",1); + std::string patternName; + if (commaPos != std::string::npos) { + patternName = line.substr(1,commaPos-1); + } else { + patternName = line.substr(1); + } + result.push_back(patternName); + } + } + return result; +} + +//******************************************************** +void DashSpec::dump(char* title) +{ + std::stringstream ss; + ss << title << ": " ; + for (auto& p: m_parms) { + ss << p << ", "; + } + Base::Console().Message("DUMP - DashSpec - %s\n",ss.str().c_str()); +} + + + + + diff --git a/src/Mod/TechDraw/App/HatchLine.h b/src/Mod/TechDraw/App/HatchLine.h new file mode 100644 index 0000000000..6a686605f8 --- /dev/null +++ b/src/Mod/TechDraw/App/HatchLine.h @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (c) 2017 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 _TechDraw_HATCHLINE_H_ +#define _TechDraw_HATCHLINE_H_ + +#include +#include +#include +#include +#include + +#include + +class TopoDS_Edge; + +namespace TechDrawGeometry +{ +class BaseGeom; +} + +namespace TechDraw +{ +class DrawViewPart; +class DrawUtil; + + +// HatchLine is the result of parsing a line from PAT file into accessible parameters +// e /HatchLine/PATSpecLine/ +class HatchLine +{ +public: + HatchLine(); + HatchLine(std::string& lineSpec); + ~HatchLine(); + + void load(std::string& lineSpec); + + double getAngle(void) {return m_angle;} + Base::Vector3d getOrigin(void) {return m_origin;} + double getInterval(void) {return m_interval;} + double getOffset(void) {return m_offset;} + std::vector getDashParms(void) {return m_dashParms;}; + + static std::vector getSpecsForPattern(std::string& parmFile, std::string& parmName); + static bool findPatternStart(std::ifstream& inFile, std::string& parmName); + static std::vector loadPatternDef(std::ifstream& inFile); + static std::vector getPatternList(std::string& parmFile); + + void dump(char* title); + +private: + void init(void); + std::vector split(std::string line); + //PAT line extracted tokens + double m_angle; + Base::Vector3d m_origin; + double m_interval; + double m_offset; + std::vector m_dashParms; //why isn't this a DashSpec object? +}; + +// a LineSet is all the generated edges for 1 HatchLine for 1 Face +class LineSet +{ +public: + LineSet() {} + ~LineSet() {} + + void setHatchLine(HatchLine s) { m_hatchLine = s; } + void setEdges(std::vector e) {m_edges = e;} + void setGeoms(std::vector g) {m_geoms = g;} + + HatchLine getHatchLine(void) { return m_hatchLine; } + std::vector getDashSpec(void) { return m_hatchLine.getDashParms();} + std::vector getEdges(void) { return m_edges; } + std::vector getGeoms(void) { return m_geoms; } + //void clearGeom(void); + +private: + std::vector m_edges; + std::vector m_geoms; + HatchLine m_hatchLine; +}; + +class DashSpec +{ +public: + DashSpec() {} + DashSpec(std::vector p) { m_parms = p; } + ~DashSpec() {} + + double get(int i) {return m_parms.at(i); } + std::vector get(void) {return m_parms;} + bool empty(void) {return m_parms.empty();} + int size(void) {return m_parms.size();} + void dump(char* title); + +private: + std::vector m_parms; +}; + +} //end namespace + +#endif diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp index 8030942013..1388e4fe72 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp @@ -48,6 +48,7 @@ #include "ViewProviderSymbol.h" #include "ViewProviderViewClip.h" #include "ViewProviderHatch.h" +#include "ViewProviderGeomHatch.h" #include "ViewProviderSpreadsheet.h" #include "ViewProviderImage.h" @@ -102,6 +103,7 @@ void TechDrawGuiExport initTechDrawGui() TechDrawGui::ViewProviderDraft::init(); TechDrawGui::ViewProviderArch::init(); TechDrawGui::ViewProviderHatch::init(); + TechDrawGui::ViewProviderGeomHatch::init(); TechDrawGui::ViewProviderSpreadsheet::init(); TechDrawGui::ViewProviderImage::init(); diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index a0221bc8b5..7ce4ee9cf8 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -36,6 +36,7 @@ set(TechDrawGui_MOC_HDRS TaskLinkDim.h DlgTemplateField.h TaskSectionView.h + TaskGeomHatch.h ) fc_wrap_cpp(TechDrawGui_MOC_SRCS ${TechDrawGui_MOC_HDRS}) @@ -54,6 +55,7 @@ set(TechDrawGui_UIC_SRCS TaskLinkDim.ui DlgTemplateField.ui TaskSectionView.ui + TaskGeomHatch.ui ) if(BUILD_QT5) @@ -92,8 +94,13 @@ SET(TechDrawGui_SRCS TaskSectionView.ui TaskSectionView.cpp TaskSectionView.h + TaskGeomHatch.ui + TaskGeomHatch.cpp + TaskGeomHatch.h DrawGuiUtil.cpp DrawGuiUtil.h + Rez.cpp + Rez.h ) SET(TechDrawGuiView_SRCS MDIViewPage.cpp @@ -197,6 +204,8 @@ SET(TechDrawGuiViewProvider_SRCS ViewProviderViewClip.h ViewProviderHatch.cpp ViewProviderHatch.h + ViewProviderGeomHatch.cpp + ViewProviderGeomHatch.h ViewProviderImage.cpp ViewProviderImage.h ) @@ -209,6 +218,7 @@ SET(TechDrawGuiTaskDlgs_SRCS TaskProjGroup.ui TaskLinkDim.ui TaskSectionView.ui + TaskGeomHatch.ui ) SOURCE_GROUP("TaskDialogs" FILES ${TechDrawGuiTaskDlgs_SRCS}) diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp index e970bcd9da..8b6df3dffe 100644 --- a/src/Mod/TechDraw/Gui/Command.cpp +++ b/src/Mod/TechDraw/Gui/Command.cpp @@ -350,9 +350,12 @@ void CmdTechDrawNewViewSection::activated(int iMsg) std::string FeatName = getUniqueObjectName("Section"); std::string SourceName = dvp->Source.getValue()->getNameInDocument(); + std::string BaseName = (dObj)->getNameInDocument(); doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawViewSection','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Source = App.activeDocument().%s",FeatName.c_str(),SourceName.c_str()); - doCommand(Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s",FeatName.c_str(),(dObj)->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.BaseView = App.activeDocument().%s",FeatName.c_str(),BaseName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Scale = App.activeDocument().%s.Scale",FeatName.c_str(),BaseName.c_str()); + doCommand(Doc,"App.activeDocument().%s.ScaleType = App.activeDocument().%s.ScaleType",FeatName.c_str(),BaseName.c_str()); doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); App::DocumentObject *docObj = getDocument()->getObject(FeatName.c_str()); TechDraw::DrawViewSection* dsv = dynamic_cast(docObj); @@ -453,7 +456,7 @@ CmdTechDrawProjGroup::CmdTechDrawProjGroup() sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Insert Projection Group"); - sToolTipText = QT_TR_NOOP("Insert 2D Projections of a 3D part into the active drawing"); + sToolTipText = QT_TR_NOOP("Insert multiple views of a single part into the active drawing"); sWhatsThis = "TechDraw_ProjGroup"; sStatusTip = sToolTipText; sPixmap = "actions/techdraw-projgroup"; @@ -478,7 +481,7 @@ void CmdTechDrawProjGroup::activated(int iMsg) Gui::WaitCursor wc; openCommand("Create Projection Group"); - std::string multiViewName = getUniqueObjectName("cView"); + std::string multiViewName = getUniqueObjectName("ProjGroup"); std::string SourceName = (*shapes.begin())->getNameInDocument(); doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawProjGroup','%s')",multiViewName.c_str()); doCommand(Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)",PageName.c_str(),multiViewName.c_str()); diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp index 322499d156..2b38bdc87e 100644 --- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp +++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp @@ -49,12 +49,15 @@ #include #include #include +#include #include #include #include #include "DrawGuiUtil.h" #include "MDIViewPage.h" +#include "TaskGeomHatch.h" +#include "ViewProviderGeomHatch.h" #include "ViewProviderPage.h" using namespace TechDrawGui; @@ -75,8 +78,8 @@ CmdTechDrawNewHatch::CmdTechDrawNewHatch() { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); - sMenuText = QT_TR_NOOP("Insert a hatched area into a view"); - sToolTipText = QT_TR_NOOP("Insert a hatched area into a view"); + sMenuText = QT_TR_NOOP("Hatch a Face using image file"); + sToolTipText = QT_TR_NOOP("Hatch a Face using image file"); sWhatsThis = "TechDraw_NewHatch"; sStatusTip = sToolTipText; sPixmap = "actions/techdraw-hatch"; @@ -126,6 +129,73 @@ bool CmdTechDrawNewHatch::isActive(void) return (havePage && haveView); } +//=========================================================================== +// TechDraw_NewGeomHatch +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawNewGeomHatch); + +CmdTechDrawNewGeomHatch::CmdTechDrawNewGeomHatch() + : Command("TechDraw_NewGeomHatch") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Apply geometric hatch to a Face"); + sToolTipText = QT_TR_NOOP("Apply geometric hatch to a Face"); + sWhatsThis = "TechDraw_NewGeomHatch"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-geomhatch"; +} + +void CmdTechDrawNewGeomHatch::activated(int iMsg) +{ + Q_UNUSED(iMsg); + if (!_checkSelectionHatch(this)) { //same requirements as hatch - page, DrawViewXXX, face + return; + } + + std::vector selection = getSelection().getSelectionEx(); + auto objFeat( dynamic_cast(selection[0].getObject()) ); + if( objFeat == nullptr ) { + return; + } + const std::vector &subNames = selection[0].getSubNames(); + TechDraw::DrawPage* page = objFeat->findParentPage(); + std::string PageName = page->getNameInDocument(); + + std::string FeatName = getUniqueObjectName("GeomHatch"); + std::stringstream featLabel; + featLabel << FeatName << "FX" << TechDraw::DrawUtil::getIndexFromName(subNames.at(0)); + + openCommand("Create GeomHatch"); + doCommand(Doc,"App.activeDocument().addObject('TechDraw::DrawGeomHatch','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Label = '%s'",FeatName.c_str(),featLabel.str().c_str()); + + auto geomhatch( static_cast(getDocument()->getObject(FeatName.c_str())) ); + geomhatch->Source.setValue(objFeat, subNames); + Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(geomhatch); + TechDrawGui::ViewProviderGeomHatch* hvp = dynamic_cast(vp); +// if (!hvp) { + + // dialog to fill in hatch values + Gui::Control().showDialog(new TaskDlgGeomHatch(geomhatch,hvp)); + + + commitCommand(); + + //Horrible hack to force Tree update ??still required?? + double x = objFeat->X.getValue(); + objFeat->X.setValue(x); + getDocument()->recompute(); +} + +bool CmdTechDrawNewGeomHatch::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + return (havePage && haveView); +} + //=========================================================================== // TechDraw_Image //=========================================================================== @@ -230,6 +300,7 @@ void CreateTechDrawCommandsDecorate(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdTechDrawNewHatch()); + rcCmdMgr.addCommand(new CmdTechDrawNewGeomHatch()); rcCmdMgr.addCommand(new CmdTechDrawImage()); rcCmdMgr.addCommand(new CmdTechDrawToggleFrame()); } diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw.ui index d026baeb1a..f270f9b239 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw.ui @@ -7,525 +7,640 @@ 0 0 558 - 610 + 648 TechDraw 1 - - - - 10 - 450 - 531 - 151 - - - - Files - - - - - 20 - 30 - 491 - 118 - - - - - - - Template Directory - - - - - - - Default Template - - - - - - - Gui::FileChooser::Directory - - - TemplateDir - - - /Mod/TechDraw/Files - - - - - - - Default Pattern File - - - - - - - TemplateFile - - - /Mod/TechDraw/Files - - - - - - - PatternFile - - - /Mod/TechDraw/Files - - - - - - - - - - 10 - 330 - 541 - 121 - - - - - 0 - 0 - - - - Labels - - - - - 20 - 30 - 491 - 71 - - - - - - - 0.100000000000000 - - - LabelSize - - - /Mod/TechDraw/Labels - - - - - - - Label Font - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - osifont - - - LabelFont - - - Mod/TechDraw/Labels - - - - - - - Label Size - - - - - - - - - - 10 - 10 - 521 - 141 - - - - General - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - Projection Angle + + + + + General + + + + + + QFormLayout::AllNonFixedFieldsGrow - + + + + Projection Angle + + + + + + + ProjectionAngle + + + /Mod/TechDraw/General + + + + First + + + + + Third + + + + + + + + Hidden Line + + + + + + + 1 + + + HiddenLine + + + Mod/TechDraw/General + + + + NeverShow + + + + + Solid + + + + + Dash + + + + + Dot + + + + + DashDot + + + + + DashDotDot + + + + + + + + Detect Faces + + + true + + + HandleFaces + + + /Mod/TechDraw/General + + + + + + + Show Section Edges + + + ShowSectionEdges + + + /Mod/TechDraw/General + + + + - - - - ProjectionAngle + + + + Qt::Vertical - - /Mod/TechDraw/General + + + 20 + 40 + - - - First - - - - - Third - - - - - - - - Hidden Line - - - - - - - 1 - - - HiddenLine - - - Mod/TechDraw/General - - - - NeverShow - - - - - Solid - - - - - Dash - - - - - Dot - - - - - DashDot - - - - - DashDotDot - - - - - - - - Detect Faces - - - true - - - HandleFaces - - - /Mod/TechDraw/General - - - - - - - Show Section Edges - - - ShowSectionEdges - - - /Mod/TechDraw/General - - + - - - - - - - 10 - 160 - 521 - 164 - - - - Colors - - - - - - - - Section Hatch - - + + + + + + Colors + + + + + + + + Section Hatch + + + + + + + Section Face + + + + + + + + 80 + 80 + 80 + + + + Background + + + /Mod/TechDraw/Colors + + + + + + + + 255 + 255 + 20 + + + + PreSelectColor + + + Mod/TechDraw/Colors + + + + + + + Normal + + + + + + + HiddenColor + + + Mod/TechDraw/Colors + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 28 + 173 + 28 + + + + SelectColor + + + Mod/TechDraw/Colors + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + 0 + + + + NormalColor + + + Mod/TechDraw/Colors + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PreSelected + + + + + + + Hidden Line + + + + + + + + 225 + 225 + 225 + + + + CutSurfaceColor + + + Mod/TechDraw/Colors + + + + + + + Selected + + + + + + + + 0 + 0 + 0 + + + + Hatch + + + /Mod/TechDraw/Colors + + + + + + + Background + + + + + + + Geom Hatch + + + + + + + + 0 + 0 + 0 + + + + GeomHatch + + + /Mod/TechDraw/Colors + + + + - - - - Section Face - - - - - - - - 80 - 80 - 80 - - - - Background - - - /Mod/TechDraw/Colors - - - - - - - - 255 - 255 - 20 - - - - PreSelectColor - - - Mod/TechDraw/Colors - - - - - - - Normal - - - - - - - HiddenColor - - - Mod/TechDraw/Colors - - - - - + + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 - - - - - 28 - 173 - 28 - - - - SelectColor - - - Mod/TechDraw/Colors - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - 0 - - - - NormalColor - - - Mod/TechDraw/Colors - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - PreSelected - - - - - - - Hidden Line - - - - - - - - 225 - 225 - 225 - - - - CutSurfaceColor - - - Mod/TechDraw/Colors - - - - - - - Selected - - - - - - - - 0 - 0 - 0 - - - - Hatch - - - /Mod/TechDraw/Colors - - - - - - - Background - - - - - - + + + + + + Files + + + + + + + + Template Directory + + + + + + + Default Template + + + + + + + Gui::FileChooser::Directory + + + TemplateDir + + + /Mod/TechDraw/Files + + + + + + + Hatch Image + + + + + + + TemplateFile + + + /Mod/TechDraw/Files + + + + + + + Location of default svg/png fill file + + + FileHatch + + + /Mod/TechDraw/Files + + + + + + + PAT File + + + + + + + Default location for PAT file + + + FilePattern + + + /Mod/TechDraw/PAT + + + + + + + + + + + Default PAT pattern + + + NamePattern + + + /Mod/TechDraw/PAT + + + + + + + Pattern Name + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + + + + Labels + + + + + + + + 0.100000000000000 + + + LabelSize + + + /Mod/TechDraw/Labels + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Label Font + + + + + + + osifont + + + LabelFont + + + Mod/TechDraw/Labels + + + + + + + Label Size + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2.ui index 973785771f..0e56034a06 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2.ui @@ -7,351 +7,473 @@ 0 0 521 - 420 + 463 TechDraw 2 - - - - 10 - 20 - 501 - 161 - - - - Dimensions - - - - - 20 - 30 - 471 - 125 - - - - - - - Show Units - - - ShowUnits - - - /Mod/TechDraw/Dimensions - - - - - - - Color - - - - - - - Font Size - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 1 - - - 4.000000000000000 - - - FontSize - - - /Mod/TechDraw/Dimensions - - - - - - - - 0 - 0 - 0 - - - - Color - - - /Mod/TechDraw/Dimensions - - - - - - - Diameter Symbol - - - - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - DiameterSymbol - - - /Mod/TechDraw/Dimensions - - - - - - - - - - 10 - 190 - 501 - 201 - - - - Decorations - - - - - 20 - 30 - 471 - 161 - - - - - - - MattingStyle - - - /Mod/TechDraw/Decorations - - - - Round + + + + + Dimensions + + + + + + + + Show Units + + + ShowUnits + + + /Mod/TechDraw/Dimensions + + + + + + + Color + + + + + + + Font Size + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 4.000000000000000 + + + FontSize + + + /Mod/TechDraw/Dimensions + + + + + + + + 0 + 0 + 0 + + + + Color + + + /Mod/TechDraw/Dimensions + + + + + + + Diameter Symbol + + + + + + + + 12 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + DiameterSymbol + + + /Mod/TechDraw/Dimensions + + + + + + + + + Qt::Vertical - - - - Square + + + 20 + 40 + - - - - - - - Section Line Style - - - - - - - Center Line Style - - - - - - - Matting Style - - - - - - - - 175 - 175 - 175 - - - - CenterColor - - - /Mod/TechDraw/Decorations - - - - - - - 2 - - - CenterLine - - - /Mod/TechDraw/Decorations - - - - NeverShow + + + + + + + + + Decorations + + + + + + + + MattingStyle + + + /Mod/TechDraw/Decorations + + + + Round + + + + + Square + + + + + + + + Section Line Style + + + + + + + Center Line Style + + + + + + + Matting Style + + + + + + + + 175 + 175 + 175 + + + + CenterColor + + + /Mod/TechDraw/Decorations + + + + + + + 2 + + + CenterLine + + + /Mod/TechDraw/Decorations + + + + NeverShow + + + + + Sollid + + + + + Dash + + + + + Dot + + + + + DashDot + + + + + DashDotDot + + + + + + + + 2 + + + SectionLine + + + /Mod/TechDraw/Decorations + + + + NeverShow + + + + + Solid + + + + + Dash + + + + + Dot + + + + + DashDot + + + + + DashDotDot + + + + + + + + Center Line Color + + + + + + + Section Line Color + + + + + + + + 175 + 175 + 175 + + + + SectionColor + + + /Mod/TechDraw/Decorations + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Arrow Style + + + + + + + Preferred arrowhead style + + + 0 + + + 5 + + + ArrowStyle + + + Mod/TechDraw/Decorations + + + + 0 - Filled Triangle + + + + :/icons/arrowfilled.svg + + + + + + 1 - Open Arrowhead + + + + :/icons/arrowopen.svg + + + + + + 2 - Tick + + + + :/icons/arrowtick.svg + + + + + + 3 - Dot + + + + :/icons/arrowdot.svg + + + + + + 4 - Open Circle + + + + :/icons/arrowopendot.svg + + + + + + + + + Default weight for GeomHatch lines + + + Hatch Weight + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1.000000000000000 + + + GeomWeight + + + Mod/TechDraw/PAT + + + + + + + + + Qt::Vertical - - - - Sollid + + + 20 + 40 + - - - - Dash - - - - - Dot - - - - - DashDot - - - - - DashDotDot - - - - - - - - 2 - - - SectionLine - - - /Mod/TechDraw/Decorations - - - - NeverShow - - - - - Solid - - - - - Dash - - - - - Dot - - - - - DashDot - - - - - DashDotDot - - - - - - - - Center Line Color - - - - - - - Section Line Color - - - - - - - - 175 - 175 - 175 - - - - SectionColor - - - /Mod/TechDraw/Decorations - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + @@ -385,6 +507,8 @@
Gui/PrefWidgets.h
- + + + diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2Imp.cpp b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2Imp.cpp index f94478eb8c..b34d35526c 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2Imp.cpp +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDraw2Imp.cpp @@ -52,6 +52,7 @@ void DlgPrefsTechDraw2Imp::saveSettings() colCenterLine->onSave(); pcbSectionStyle->onSave(); colSectionLine->onSave(); + pcbArrow->onSave(); } void DlgPrefsTechDraw2Imp::loadSettings() @@ -65,6 +66,7 @@ void DlgPrefsTechDraw2Imp::loadSettings() colCenterLine->onRestore(); pcbSectionStyle->onRestore(); colSectionLine->onRestore(); + pcbArrow->onRestore(); } /** diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index 741989f814..ad07b724cf 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -38,6 +38,9 @@ #include #include #include + #include + #include + #endif // #ifndef _PreComp_ #include @@ -77,6 +80,7 @@ #include #include +#include "Rez.h" #include "QGIDrawingTemplate.h" #include "QGIView.h" #include "QGIViewPart.h" @@ -145,6 +149,12 @@ MDIViewPage::MDIViewPage(ViewProviderPage *pageVp, Gui::Document* doc, QWidget* m_view->scene(), SIGNAL(selectionChanged()), this , SLOT (selectionChanged()) ); + + //get informed by App side about deleted DocumentObjects + App::Document* appDoc = m_vpPage->getDocument()->getDocument(); + auto bnd = boost::bind(&MDIViewPage::onDeleteObject, this, _1); + connectDeletedObject = appDoc->signalDeletedObject.connect(bnd); + // A fresh page is added and we iterate through its collected children and add these to Canvas View -MLP // if docobj is a featureviewcollection (ex orthogroup), add its child views. if there are ever children that have children, @@ -169,8 +179,8 @@ MDIViewPage::MDIViewPage(ViewProviderPage *pageVp, Gui::Document* doc, QWidget* auto pageTemplate( dynamic_cast(obj) ); if( pageTemplate ) { //make sceneRect 1 pagesize bigger in every direction - double width = pageTemplate->Width.getValue(); - double height = pageTemplate->Height.getValue(); + double width = Rez::guiX(pageTemplate->Width.getValue()); + double height = Rez::guiX(pageTemplate->Height.getValue()); m_view->scene()->setSceneRect(QRectF(-width,-2.0 * height,3.0*width,3.0*height)); attachTemplate(pageTemplate); viewAll(); @@ -180,6 +190,7 @@ MDIViewPage::MDIViewPage(ViewProviderPage *pageVp, Gui::Document* doc, QWidget* MDIViewPage::~MDIViewPage() { + connectDeletedObject.disconnect(); } @@ -254,8 +265,8 @@ void MDIViewPage::attachTemplate(TechDraw::DrawTemplate *obj) QPointF MDIViewPage::getTemplateCenter(TechDraw::DrawTemplate *obj) { - double cx = obj->Width.getValue()/2.0; - double cy = -obj->Height.getValue()/2.0; + double cx = Rez::guiX(obj->Width.getValue())/2.0; + double cy = -Rez::guiX(obj->Height.getValue())/2.0; QPointF result(cx,cy); return result; } @@ -317,7 +328,23 @@ bool MDIViewPage::attachView(App::DocumentObject *obj) return (qview != nullptr); } +void MDIViewPage::removeView(QGIView *view) +{ + (void) m_view->removeView(view); +} +void MDIViewPage::onDeleteObject(const App::DocumentObject& obj) +{ + if (obj.isDerivedFrom(TechDraw::DrawView::getClassTypeId())) { + const App::DocumentObject* objPtr = &obj; + const TechDraw::DrawView* dv = static_cast(objPtr); + TechDraw::DrawPage* dvPg = dv->findParentPage(); + if (dvPg == m_vpPage->getDrawPage()) { + //this is a DV that is on our page + (void) m_view->removeView(dv); + } + } +} void MDIViewPage::updateTemplate(bool forceUpdate) { @@ -347,10 +374,19 @@ void MDIViewPage::updateTemplate(bool forceUpdate) void MDIViewPage::updateDrawing(bool forceUpdate) { - // We cannot guarantee if the number of graphical representations (QGIVxxxx) have changed so check the number (MLP) + // We cannot guarantee if the number of graphical representations (QGIVxxxx) have changed so check the number (MLP) + // WF: this should be fixed now with onDeletedObject signal from App side? + // WF: the QGVP views list may still not be 100% reliable + // TODO: build list of QGIV's from scene everytime? + //logging counters +// int qgvpIn = 0; +// int qgvpValid = 0; +// int qgvpClean = 0; +// int dpIn = 0; const std::vector &graphicsList = m_view->getViews(); +// qgvpIn = graphicsList.size(); const std::vector &pageChildren = m_vpPage->getDrawPage()->Views.getValues(); - + // Count total # DocumentObjects in Page unsigned int docObjCount = 0; for(std::vector::const_iterator it = pageChildren.begin(); it != pageChildren.end(); ++it) { @@ -361,7 +397,12 @@ void MDIViewPage::updateDrawing(bool forceUpdate) } docObjCount += 1; } - +// dpIn = docObjCount; + + + //TODO: should prune QGVP.views first always, then check if view in Page missing QGIVP + // this makes assumption that = numbers mean everythign is OK, but could be double failure - 1 extra QGIV, 1 DV missing graphics! + if(graphicsList.size() < docObjCount) { // there are more DocumentObjects than graphical representations (QGIVxxxx's) // Find which DocumentObjects have no graphical representation (QGIVxxxx) @@ -373,31 +414,50 @@ void MDIViewPage::updateDrawing(bool forceUpdate) attachView(*it); } } else if(graphicsList.size() > docObjCount) { - // There are more graphical representations (QGIVxxxx) than DocumentObjects - // Remove the orphans - std::vector::const_iterator itGraphics = graphicsList.begin(); + // prune any invalid entries in QGVP.views + // TODO: revisit this mess. is it still required with onDeletedItem signal implementation? std::vector newGraphicsList; - bool fnd = false; - while(itGraphics != graphicsList.end()) { - fnd = orphanExists((*itGraphics)->getViewName(), pageChildren); - if(fnd) { - newGraphicsList.push_back(*itGraphics); - } else { - if (m_view->scene() == (*itGraphics)->scene()) { - (*itGraphics)->hide(); - m_view->scene()->removeItem(*itGraphics); - } else { // this "shouldn't" happen, but it does - Base::Console().Log("ERROR - MDIViewPage::updateDrawing - %s already removed from QGraphicsScene\n", - (*itGraphics)->getViewName()); + QList items = m_view->scene()->items(); + for (auto& v: graphicsList) { //check that everything in QGVP views is valid + for (auto& i:items) { + if (v == i) { //this one is OK + newGraphicsList.push_back(v); + break; } } - itGraphics++; } - - // Update the QGVPage (QGraphicsView) list of QGIVxxxx - m_view->setViews(newGraphicsList); +// qgvpValid = newGraphicsList.size(); + //newGraphicsList now only contains valid QGIV's + //now prune the ones without docObjs + std::vector cleanItems; + for (auto& i: newGraphicsList) { + std::string viewName = (i->data(1).toString()).toStdString(); + App::DocumentObject* dObj = getAppDocument()->getObject(viewName.c_str()); + if (dObj == nullptr) { + //need to remove from group/scene + QGraphicsItemGroup* grp = i->group(); + if (grp) { + grp->removeFromGroup(i); + } + if (i->parentItem()) { //not top level + i->setParentItem(0); + } + if (i->scene()) { + i->scene()->removeItem(i); + } + //should delete i too to prevent leak? might be garbage pointer, though. + //add to delete list and delete outside of loop + } else { + QGIView* v = static_cast(i); + cleanItems.push_back(v); + } + } +// qgvpClean = cleanItems.size(); + m_view->setViews(cleanItems); +// Base::Console().Message("Log - MDIVP::updateDrawing pruning: docObjs: %d views in: %d valid views: %d views out: %d\n", +// dpIn,qgvpIn,qgvpValid, qgvpClean); } - + // Update all the QGIVxxxx const std::vector &upviews = m_view->getViews(); for(std::vector::const_iterator it = upviews.begin(); it != upviews.end(); ++it) { @@ -421,7 +481,7 @@ void MDIViewPage::redraw1View(TechDraw::DrawView* dv) std::string dvName = dv->getNameInDocument(); const std::vector &upviews = m_view->getViews(); for(std::vector::const_iterator it = upviews.begin(); it != upviews.end(); ++it) { - std::string qgivName = (*it)->getViewObject()->getNameInDocument(); + std::string qgivName = (*it)->getViewName(); if(dvName == qgivName) { (*it)->updateView(true); } @@ -457,7 +517,7 @@ bool MDIViewPage::hasQView(App::DocumentObject *obj) while(qview != views.end()) { // Unsure if we can compare pointers so rely on name - if(strcmp((*qview)->getViewObject()->getNameInDocument(), obj->getNameInDocument()) == 0) { + if(strcmp((*qview)->getViewName(), obj->getNameInDocument()) == 0) { return true; } qview++; @@ -731,8 +791,8 @@ void MDIViewPage::print(QPrinter* printer) double width = 0.0; double height = 0.0; if( pageTemplate ) { - width = pageTemplate->Width.getValue(); - height = pageTemplate->Height.getValue(); + width = Rez::guiX(pageTemplate->Width.getValue()); + height = Rez::guiX(pageTemplate->Height.getValue()); } QRectF sourceRect(0.0,-height,width,height); diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.h b/src/Mod/TechDraw/Gui/MDIViewPage.h index 29ff8ac2d3..13fab0db8d 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.h +++ b/src/Mod/TechDraw/Gui/MDIViewPage.h @@ -65,7 +65,8 @@ public: void attachTemplate(TechDraw::DrawTemplate *obj); void updateTemplate(bool force = false); void updateDrawing(bool force = false); - + void removeView(QGIView *view); + bool onMsg(const char* pMsg,const char** ppReturn); bool onHasMsg(const char* pMsg) const; void onRelabel(Gui::Document *pDoc); @@ -110,6 +111,11 @@ protected: QPrinter::PaperSize getPaperSize(int w, int h) const; void setDimensionGroups(void); void showStatusMsg(const char* s1, const char* s2, const char* s3) const; + + void onDeleteObject(const App::DocumentObject& obj); + + typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; + Connection connectDeletedObject; private: QAction *m_nativeAction; diff --git a/src/Mod/TechDraw/Gui/QGCustomLabel.cpp b/src/Mod/TechDraw/Gui/QGCustomLabel.cpp index ef72c42341..c2b5db434b 100644 --- a/src/Mod/TechDraw/Gui/QGCustomLabel.cpp +++ b/src/Mod/TechDraw/Gui/QGCustomLabel.cpp @@ -40,6 +40,7 @@ #include #include +#include "Rez.h" #include "QGCustomLabel.h" using namespace TechDrawGui; @@ -75,5 +76,24 @@ void QGCustomLabel::centerAt(double cX, double cY) void QGCustomLabel::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; + + //see QGCustomText for explanation of this code + double dppt = 3.53; + double svgMagicX = Rez::guiX(8.0); + double svgMagicY = Rez::guiX(12.0); + double svgMagicYoffset = Rez::guiX(3.0); + double fontSize = Rez::appX(font().pointSizeF()); + double ty = svgMagicY + (svgMagicYoffset*fontSize)/dppt; + QPointF svgMove(-svgMagicX/dppt,ty); + + QPaintDevice* hw = painter->device(); + QSvgGenerator* svg = dynamic_cast(hw); + if (svg) { + painter->scale(Rez::appX(dppt),Rez::appX(dppt)); + painter->translate(svgMove); + } else { + painter->scale(1.0,1.0); + } + QGraphicsTextItem::paint (painter, &myOption, widget); } diff --git a/src/Mod/TechDraw/Gui/QGCustomLabel.h b/src/Mod/TechDraw/Gui/QGCustomLabel.h index e34d4b2887..75f13e9e6f 100644 --- a/src/Mod/TechDraw/Gui/QGCustomLabel.h +++ b/src/Mod/TechDraw/Gui/QGCustomLabel.h @@ -54,6 +54,6 @@ private: }; -} // namespace MDIViewPageGui +} #endif // DRAWINGGUI_QGCUSTOMLABEL_H diff --git a/src/Mod/TechDraw/Gui/QGCustomText.cpp b/src/Mod/TechDraw/Gui/QGCustomText.cpp index 5bed7c15db..c52aecf3f7 100644 --- a/src/Mod/TechDraw/Gui/QGCustomText.cpp +++ b/src/Mod/TechDraw/Gui/QGCustomText.cpp @@ -40,6 +40,7 @@ #include #include +#include "Rez.h" #include "QGIView.h" #include "QGCustomText.h" @@ -124,28 +125,27 @@ void QGCustomText::paint ( QPainter * painter, const QStyleOptionGraphicsItem * QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; - //svg text is much larger than screen text. scene units(mm) vs points. + //svg text is much larger than screen text. scene units(mm or 0.1mm in hirez) vs points. //need to scale text if going to svg. - //TODO: magic translation happens? approx: right ~8mm down: 12mm + (3mm per mm of text height) + //TODO: magic translation happens. why? approx: right ~8mm down: 12mm + (3mm per mm of text height) //SVG transform matrix translation values are different for same font size + different fonts (Sans vs Ubuntu vs Arial)??? // scale values are same for same font size + different fonts. - //double svgScale = 2.835; //72dpi/(25.4mm/in) - //double svgScale = 3.84; //96dpi/(25mm/in) - //double svgScale = 3.6; //90dpi/(25mm/in) more/less CSS standard? - double svgScale = 2.88; //72dpi/(25mm/in) Qt logicalDpiY() is int - double svgMagicX = 8.0; - //double svgMagicY = 7.5; //idk - double fontSize = font().pointSizeF(); - //double ty = (12.0/svgScale + 3.0*fontSize/svgScale) + (svgMagicY/svgScale); - double ty = (12.0/svgScale + 3.0*fontSize/svgScale); - QPointF svgMove(-svgMagicX/svgScale,-ty); + //calculate dots/mm + //in hirez - say factor = 10, we have 10 dpmm in scene space. + // so 254dpi / 72pts/in => 3.53 dppt + double dpmm = 3.53; //dots/pt + double svgMagicX = Rez::guiX(8.0); //8mm -> 80 gui dots + double svgMagicY = Rez::guiX(12.0); + double svgMagicYoffset = Rez::guiX(3.0); // 3mm per mm of font size => 30gunits / mm of font size + double fontSize = Rez::appX(font().pointSizeF()); //gui pts 4mm text * 10 scunits/mm = size 40 text but still only 4mm + double ty = svgMagicY + (svgMagicYoffset*fontSize)/dpmm; + // 12mm (in gunits) + [3mm (in gunits) * (# of mm)]/ [dots per mm] works out to dots? + QPointF svgMove(-svgMagicX/dpmm,ty); QPaintDevice* hw = painter->device(); - //QPaintDeviceMetrics hwm(hw); - //QPrinter* pr = dynamic_cast(hw); //printer does not rescale vs screen? QSvgGenerator* svg = dynamic_cast(hw); if (svg) { - painter->scale(svgScale,svgScale); + painter->scale(Rez::appX(dpmm),Rez::appX(dpmm)); painter->translate(svgMove); } else { painter->scale(1.0,1.0); diff --git a/src/Mod/TechDraw/Gui/QGIArrow.cpp b/src/Mod/TechDraw/Gui/QGIArrow.cpp index ab06a0ecfd..1d5037f120 100644 --- a/src/Mod/TechDraw/Gui/QGIArrow.cpp +++ b/src/Mod/TechDraw/Gui/QGIArrow.cpp @@ -32,6 +32,11 @@ #include #endif +#include +#include +#include + +#include "Rez.h" #include "QGIArrow.h" using namespace TechDrawGui; @@ -56,39 +61,102 @@ void QGIArrow::flip(bool state) { } void QGIArrow::draw() { - // the center is the end point on a dimension QPainterPath path; - //QPen pen(Qt::black); - //pen.setWidth(1); - - //QBrush brush(Qt::black); - //setPen(pen); - //setBrush(brush); - - float length = -m_size; //TODO: Arrow heads sb preference? size & type? - - if(isFlipped) - length *= -1; - path.moveTo(QPointF(0.,0.)); - path.lineTo(QPointF(length,-0.6)); - path.lineTo(QPointF(length, 0.6)); - - path.closeSubpath(); -// path.moveTo(QPointF(-1,1)); -// path.lineTo(QPointF(1,-1)); + if (m_style == 0) { + path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //"arrow l/w sb 3/1" ?? + } else if (m_style == 1) { + path = makeOpenArrow(m_size,m_size/3.0,isFlipped); //broad arrow? + } else if (m_style == 2) { + path = makeHashMark(m_size/2.0,m_size/2.0,isFlipped); //big enough? + } else if (m_style == 3) { + path = makeDot(m_size/2.0,m_size/2.0,isFlipped); + } else if (m_style == 4) { + path = makeOpenDot(m_size/2.0,m_size/2.0,isFlipped); + } else { + path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //sb a question mark or ??? + } setPath(path); } void QGIArrow::setSize(double s) { m_size = s; - //??? } -void QGIArrow::setStyle(int s) + +QPainterPath QGIArrow::makeFilledTriangle(double length, double width, bool flipped) { - m_style = s; - //??? +//(0,0) is tip of arrow + if (!flipped) { + length *= -1; + } + + QPainterPath path; + path.moveTo(QPointF(0.,0.)); + path.lineTo(QPointF(Rez::guiX(length),Rez::guiX(-width))); + path.lineTo(QPointF(Rez::guiX(length),Rez::guiX(width))); + path.closeSubpath(); + m_fill = Qt::SolidPattern; + return path; +} + +QPainterPath QGIArrow::makeOpenArrow(double length, double width, bool flipped) +{ +//(0,0) is tip of arrow + if (!flipped) { + length *= -1; + } + + QPainterPath path; + path.moveTo(QPointF(Rez::guiX(length),Rez::guiX(-width))); + path.lineTo(QPointF(0.,0.)); + path.lineTo(QPointF(Rez::guiX(length),Rez::guiX(width))); + m_fill = Qt::NoBrush; + return path; +} + +QPainterPath QGIArrow::makeHashMark(double length, double width, bool flipped) //Arch tick +{ + double adjWidth = 1.0; +//(0,0) is tip of arrow + if (!flipped) { + length *= -1; + adjWidth *= -1; + } + QPainterPath path; + path.moveTo(QPointF(Rez::guiX(length),Rez::guiX(adjWidth * (-width)))); + path.lineTo(QPointF(Rez::guiX(-length),Rez::guiX(adjWidth * width))); + m_fill = Qt::NoBrush; + return path; +} + +QPainterPath QGIArrow::makeDot(double length, double width, bool flipped) //closed dot +{ + Q_UNUSED(flipped); + QPainterPath path; + path.moveTo(0.0,0.0); ////(0,0) is Center of dot + path.addEllipse(Rez::guiX(-length/2.0), Rez::guiX(-width/2.0), Rez::guiX(length), Rez::guiX(width)); + m_fill = Qt::SolidPattern; + return path; +} + +QPainterPath QGIArrow::makeOpenDot(double length, double width, bool flipped) +{ + Q_UNUSED(flipped); + QPainterPath path; + path.moveTo(0.0,0.0); ////(0,0) is Center of dot + path.addEllipse(Rez::guiX(-length/2.0), Rez::guiX(-width/2.0), Rez::guiX(length), Rez::guiX(width)); + m_fill = Qt::NoBrush; + return path; +} + + +int QGIArrow::getPrefArrowStyle() +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Decorations"); + int style = hGrp->GetInt("ArrowStyle", 0); + return style; } void QGIArrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -96,6 +164,7 @@ void QGIArrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; + setPen(m_pen); m_brush.setColor(m_colCurrent); m_brush.setStyle(m_fill); setBrush(m_brush); diff --git a/src/Mod/TechDraw/Gui/QGIArrow.h b/src/Mod/TechDraw/Gui/QGIArrow.h index 2fef9a3173..f3f6764067 100644 --- a/src/Mod/TechDraw/Gui/QGIArrow.h +++ b/src/Mod/TechDraw/Gui/QGIArrow.h @@ -44,18 +44,22 @@ public: public: void draw(); - //void setHighlighted(bool state); void flip(bool state); double getSize() { return m_size; } void setSize(double s); int getStyle() { return m_style; } - void setStyle(int s); - //QPainterPath shape() const; + void setStyle(int s) { m_style = s; } + static int getPrefArrowStyle(); + virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); protected: - //QVariant itemChange(GraphicsItemChange change, const QVariant &value); - + QPainterPath makeFilledTriangle(double length, double width, bool flipped); + QPainterPath makeOpenArrow(double length, double width, bool flipped); + QPainterPath makeHashMark(double length, double width, bool flipped); + QPainterPath makeDot(double length, double width, bool flipped); + QPainterPath makeOpenDot(double length, double width, bool flipped); + private: QBrush m_brush; Qt::BrushStyle m_fill; @@ -64,6 +68,6 @@ private: bool isFlipped; }; -} // namespace MDIViewPageGui +} #endif // DRAWINGGUI_QGRAPHICSITEMARROW_H diff --git a/src/Mod/TechDraw/Gui/QGIFace.cpp b/src/Mod/TechDraw/Gui/QGIFace.cpp index 551b7e7065..36dfb2cccc 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.cpp +++ b/src/Mod/TechDraw/Gui/QGIFace.cpp @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #endif #include @@ -45,11 +48,15 @@ #include #include +#include + +#include "Rez.h" #include "QGCustomSvg.h" #include "QGCustomRect.h" #include "QGIFace.h" using namespace TechDrawGui; +using namespace TechDraw; QGIFace::QGIFace(int index) : projIndex(index), @@ -57,15 +64,21 @@ QGIFace::QGIFace(int index) : m_styleDef(Qt::SolidPattern), m_styleSelect(Qt::SolidPattern) { + setFillMode(NoFill); + isHatched(false); setFlag(QGraphicsItem::ItemClipsChildrenToShape,true); - //setFiltersChildEvents(true); - //setStyle(Qt::NoPen); //don't draw face lines, just fill + //setStyle(Qt::NoPen); //don't draw face lines, just fill for debugging setStyle(Qt::DashLine); m_styleNormal = m_styleDef; + m_fillStyle = m_styleDef; m_colNormalFill = m_colDefFill; + m_geomColor = QColor(Qt::black); + setLineWeight(0.5); //0 = cosmetic + setPrettyNormal(); + m_texture = nullptr; //empty texture m_svg = new QGCustomSvg(); @@ -73,6 +86,7 @@ QGIFace::QGIFace(int index) : m_rect->setParentItem(this); m_svgCol = SVGCOLDEFAULT; + m_fillScale = 1.0; } QGIFace::~QGIFace() @@ -80,34 +94,83 @@ QGIFace::~QGIFace() //nothing to do. every item is a child of QGIFace & will get removed/deleted when QGIF is deleted } +void QGIFace::draw() +{ + setPath(m_outline); //Face boundary + + if (isHatched()) { + if (m_mode == GeomHatchFill) { //crosshatch + if (!m_geomHatchPaths.empty()) { //surrogate for LineSets.empty + m_brush.setTexture(nullptr); + m_fillStyle = m_styleDef; + m_styleNormal = m_fillStyle; + int pathNo = 0; + for (auto& pp: m_geomHatchPaths) { + QGraphicsPathItem* fillItem = m_fillItems.at(pathNo); + fillItem->setPath(pp); + QPen geomPen = setGeomPen(pathNo); + fillItem->setPen(geomPen); + pathNo++; + } + } + } else if ((m_mode == FromFile) || + (m_mode == SvgFill) || + (m_mode == BitmapFill)) { + QFileInfo hfi(QString::fromUtf8(m_fileSpec.data(),m_fileSpec.size())); + if (hfi.isReadable()) { + QString ext = hfi.suffix(); + if (ext.toUpper() == QString::fromUtf8("SVG")) { + setFillMode(SvgFill); + m_brush.setTexture(nullptr); + m_fillStyle = m_styleDef; + m_styleNormal = m_fillStyle; + loadSvgHatch(m_fileSpec); + buildSvgHatch(); + toggleSvg(true); + } else if ((ext.toUpper() == QString::fromUtf8("JPG")) || + (ext.toUpper() == QString::fromUtf8("PNG")) || + (ext.toUpper() == QString::fromUtf8("JPEG")) || + (ext.toUpper() == QString::fromUtf8("BMP")) ) { + setFillMode(BitmapFill); + toggleSvg(false); + m_fillStyle = Qt::TexturePattern; + m_texture = textureFromBitmap(m_fileSpec); + m_brush.setTexture(m_texture); + } + } + } + } + show(); +} + void QGIFace::setPrettyNormal() { - m_fillStyle = m_styleNormal; - m_fillColor = m_colNormalFill; + if (isHatched() && + (m_mode == BitmapFill) ) { //hatch with bitmap fill + m_fillStyle = Qt::TexturePattern; + m_brush.setTexture(m_texture); + } else { + m_fillStyle = m_styleNormal; + m_brush.setTexture(nullptr); + m_brush.setStyle(m_fillStyle); + m_fillColor = m_colNormalFill; + } QGIPrimPath::setPrettyNormal(); } void QGIFace::setPrettyPre() { + m_brush.setTexture(nullptr); m_fillStyle = m_styleSelect; m_fillColor = getPreColor(); QGIPrimPath::setPrettyPre(); } void QGIFace::setPrettySel() { + m_brush.setTexture(nullptr); m_fillStyle = m_styleSelect; m_fillColor = getSelectColor(); QGIPrimPath::setPrettySel(); } -void QGIFace::setFill(QColor c, Qt::BrushStyle s) { - m_colNormalFill = c; - m_styleNormal = s; -} - -void QGIFace::setFill(QBrush b) { - m_colNormalFill = b.color(); - m_styleNormal = b.style(); -} - void QGIFace::setDrawEdges(bool b) { if (b) { setStyle(Qt::DashLine); @@ -116,14 +179,14 @@ void QGIFace::setDrawEdges(bool b) { } } -void QGIFace::resetFill() { - m_colNormalFill = m_colDefFill; - m_styleNormal = m_styleDef; -} - -void QGIFace::setHatch(std::string fileSpec) +void QGIFace::setHatchFile(std::string fileSpec) { - QString qfs(QString::fromStdString(fileSpec)); + m_fileSpec = fileSpec; +} + +void QGIFace::loadSvgHatch(std::string fileSpec) +{ + QString qfs(QString::fromUtf8(fileSpec.data(),fileSpec.size())); QFile f(qfs); if (!f.open(QFile::ReadOnly | QFile::Text)) { Base::Console().Error("QGIFace could not read %s\n",fileSpec.c_str()); @@ -134,29 +197,112 @@ void QGIFace::setHatch(std::string fileSpec) Base::Console().Error("Error - Could not load hatch into SVG renderer for %s\n", fileSpec.c_str()); return; } - - buildHatch(); } -void QGIFace::setPath(const QPainterPath & path) +void QGIFace::setFillMode(QGIFace::fillMode m) { - QGraphicsPathItem::setPath(path); - if (!m_svgXML.isEmpty()) { - buildHatch(); + m_mode = m; + if ((m_mode == NoFill) || + (m_mode == PlainFill)) { + isHatched(false); + } else { + isHatched(true); } } -void QGIFace::buildHatch() +void QGIFace::setOutline(const QPainterPath & path) { - m_styleNormal = Qt::NoBrush; - double w = boundingRect().width(); - double h = boundingRect().height(); - QRectF r = boundingRect(); + m_outline = path; +} + +void QGIFace::clearLineSets(void) +{ + m_geomHatchPaths.clear(); + m_dashSpecs.clear(); + clearFillItems(); +} + +//each line set needs a painterpath, a dashspec and a QGPItem to show them +void QGIFace::addLineSet(QPainterPath pp, std::vector dp) +{ + m_geomHatchPaths.push_back(pp); + m_dashSpecs.push_back(DashSpec(dp)); + addFillItem(); +} + +QGraphicsPathItem* QGIFace::addFillItem() +{ + QGraphicsPathItem* fillItem = new QGraphicsPathItem(); + fillItem->setParentItem(this); + m_fillItems.push_back(fillItem); + return fillItem; +} + +void QGIFace::clearFillItems(void) +{ + for (auto& f: m_fillItems) { + f->setParentItem(nullptr); + this->scene()->removeItem(f); + delete f; + } +} + +//convert from PAT style "-1,0,-1,+1" to Qt style "mark,space,mark,space" +QVector QGIFace::decodeDashSpec(DashSpec patDash) +{ + //Rez::guiX(something)? + double dotLength = 3.0; + double unitLength = 6.0; +// double penWidth = m_geomWeight; //mark, space and dot lengths are to be in terms of penWidth(Qt) or mm(PAT)?? +// //if we want it in terms of mm, we need to divide by penWidth? +// double minPen = 0.01; //avoid trouble with cosmetic pen (zero width) + std::vector result; + std::string prim; + for (auto& d: patDash.get()) { + double strokeLength; + if (DrawUtil::fpCompare(d,0.0)) { //pat dot + strokeLength = dotLength; + } else if (Rez::guiX(d) < 0) { //pat space + strokeLength = fabs(Rez::guiX(d)) * unitLength; + } else { //pat dash + strokeLength = Rez::guiX(d) * unitLength; + } + result.push_back(strokeLength); + } + return QVector::fromStdVector( result ); +} + + +QPen QGIFace::setGeomPen(int i) +{ + //m_dashSpecs[i].dump("spec test"); + DashSpec ourSpec = m_dashSpecs.at(i); + //ourSpec.dump("our spec"); + + QPen result; + result.setWidthF(Rez::guiX(m_geomWeight)); //Rez::guiX() ?? line weights are in mm? + result.setColor(m_geomColor); + if (ourSpec.empty()) { + result.setStyle(Qt::SolidLine); + } else { + result.setStyle(Qt::CustomDashLine); + result.setDashPattern(decodeDashSpec(ourSpec)); + } + return result; +} + +void QGIFace::buildSvgHatch() +{ + double wTile = SVGSIZEW * m_fillScale; + double hTile = SVGSIZEH * m_fillScale; + double w = m_outline.boundingRect().width(); + double h = m_outline.boundingRect().height(); + QRectF r = m_outline.boundingRect(); QPointF fCenter = r.center(); - double nw = ceil(w / SVGSIZEW); - double nh = ceil(h / SVGSIZEH); - w = nw * SVGSIZEW; - h = nh * SVGSIZEW; + double nw = ceil(w / wTile); + double nh = ceil(h / hTile); + w = nw * wTile; + h = nh * hTile; m_rect->setRect(0.,0.,w,-h); m_rect->centerAt(fCenter); r = m_rect->rect(); @@ -167,20 +313,46 @@ void QGIFace::buildHatch() for (int iw = 0; iw < int(nw); iw++) { for (int ih = 0; ih < int(nh); ih++) { QGCustomSvg* tile = new QGCustomSvg(); + tile->setScale(m_fillScale); if (tile->load(&colorXML)) { tile->setParentItem(m_rect); - tile->setPos(iw*SVGSIZEW,-h + ih*SVGSIZEH); + tile->setPos(iw*wTile,-h + ih*hTile); } } } - } -//c is a CSS color ie "#000000" -//set hatch color before building hatch -void QGIFace::setHatchColor(std::string c) +void QGIFace::clearSvg() { - m_svgCol = c; + toggleSvg(false); +} + +//this isn't used currently +QPixmap QGIFace::textureFromSvg(std::string fileSpec) +{ + QPixmap result; + QString qs(QString::fromStdString(fileSpec)); + QFileInfo ffi(qs); + if (ffi.isReadable()) { + QSvgRenderer renderer(qs); + QPixmap pixMap(renderer.defaultSize()); + pixMap.fill(Qt::white); //try Qt::transparent? + QPainter painter(&pixMap); + renderer.render(&painter); //svg texture -> bitmap + result = pixMap.scaled(m_fillScale,m_fillScale); + } //else return empty pixmap + return result; +} + +void QGIFace::setHatchColor(App::Color c) +{ + m_svgCol = c.asCSSString(); + m_geomColor = c.asValue(); +} + +void QGIFace::setHatchScale(double s) +{ + m_fillScale = s; } //QtSvg does not handle clipping, so we must be able to turn the hatching on/off @@ -194,6 +366,39 @@ void QGIFace::toggleSvg(bool b) update(); } +QPixmap QGIFace::textureFromBitmap(std::string fileSpec) +{ + QPixmap pix; + QString qs = QString::fromUtf8(fileSpec.data(),fileSpec.size()); + QFileInfo ffi(qs); + if (ffi.isReadable()) { + QImage img = QImage(qs); + img = img.scaled(Rez::guiX(m_fillScale),Rez::guiX(m_fillScale)); + pix = QPixmap::fromImage(img); + } + return pix; +} + +void QGIFace::setFill(QColor c, Qt::BrushStyle s) { + m_colNormalFill = c; + m_styleNormal = s; +} + +void QGIFace::setFill(QBrush b) { + m_colNormalFill = b.color(); + m_styleNormal = b.style(); +} + +void QGIFace::resetFill() { + m_colNormalFill = m_colDefFill; + m_styleNormal = m_styleDef; +} + +void QGIFace::setLineWeight(double w) { + m_geomWeight = w; +} + + QRectF QGIFace::boundingRect() const { return shape().controlPointRect(); @@ -213,3 +418,4 @@ void QGIFace::paint ( QPainter * painter, const QStyleOptionGraphicsItem * optio setBrush(m_brush); QGIPrimPath::paint (painter, &myOption, widget); } + diff --git a/src/Mod/TechDraw/Gui/QGIFace.h b/src/Mod/TechDraw/Gui/QGIFace.h index 99f21c652f..3fd980bfc5 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.h +++ b/src/Mod/TechDraw/Gui/QGIFace.h @@ -27,9 +27,15 @@ #include #include #include +#include +#include + +#include #include "QGIPrimPath.h" +using namespace TechDraw; + namespace TechDrawGui { class QGCustomSvg; @@ -53,30 +59,77 @@ public: virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); public: + enum fillMode { + NoFill, + FromFile, + SvgFill, + BitmapFill, + GeomHatchFill, + PlainFill + }; + + int getProjIndex() const { return projIndex; } + void draw(); void setPrettyNormal(); void setPrettyPre(); void setPrettySel(); + void setDrawEdges(bool b); + virtual void setOutline(const QPainterPath& path); + + //shared fill parms + void isHatched(bool s) {m_isHatched = s; } + bool isHatched(void) {return m_isHatched;} + void setFillMode(fillMode m); + + //plain color fill parms void setFill(QColor c, Qt::BrushStyle s); void setFill(QBrush b); - void setHatch(std::string fileSpec); - void resetFill(void); - void setPath(const QPainterPath & path); - void buildHatch(void); - void setHatchColor(std::string c); - void setDrawEdges(bool b); - void toggleSvg(bool b); + void resetFill(); -protected: - bool load(QByteArray *svgBytes); + //general hatch parms & methods + void setHatchColor(App::Color c); + void setHatchScale(double s); + + //svg fill parms & methods + void setHatchFile(std::string fileSpec); + void loadSvgHatch(std::string fileSpec); + void buildSvgHatch(void); + void toggleSvg(bool b); + void clearSvg(void); + + //PAT fill parms & methods + void setGeomHatchWeight(double w) { m_geomWeight = w; } + void clearLineSets(void); + void addLineSet(QPainterPath pp, std::vector dp); + QGraphicsPathItem* addFillItem(); + void clearFillItems(void); + void setLineWeight(double w); + + //bitmap texture fill parms method + QPixmap textureFromBitmap(std::string fileSpec); + QPixmap textureFromSvg(std::string fillSpec); protected: int projIndex; //index of face in Projection. -1 for SectionFace. QGCustomRect *m_rect; + QGCustomSvg *m_svg; QByteArray m_svgXML; std::string m_svgCol; + std::string m_fileSpec; //for svg & bitmaps + + double m_fillScale; + bool m_isHatched; + QGIFace::fillMode m_mode; + + QPen setGeomPen(int i); + QVector decodeDashSpec(DashSpec d); + std::vector m_fillItems; + std::vector m_geomHatchPaths; // 0/1 dashspec per hatchpath + std::vector m_dashSpecs; + private: QBrush m_brush; @@ -88,6 +141,15 @@ private: Qt::BrushStyle m_styleDef; //default Normal fill style Qt::BrushStyle m_styleNormal; //current Normal fill style Qt::BrushStyle m_styleSelect; //Select/preSelect fill style + + QPixmap m_texture; // + + QPainterPath m_outline; // + + QPainterPath m_geomhatch; //crosshatch fill lines + + QColor m_geomColor; //color for crosshatch lines + double m_geomWeight; //lineweight for crosshatch lines }; } diff --git a/src/Mod/TechDraw/Gui/QGIProjGroup.cpp b/src/Mod/TechDraw/Gui/QGIProjGroup.cpp index 3a4a72026a..b4f22b0695 100644 --- a/src/Mod/TechDraw/Gui/QGIProjGroup.cpp +++ b/src/Mod/TechDraw/Gui/QGIProjGroup.cpp @@ -41,6 +41,7 @@ #include #include +#include "Rez.h" #include "QGIProjGroup.h" using namespace TechDrawGui; @@ -180,9 +181,9 @@ void QGIProjGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) Gui::Command::openCommand("Drag Projection Group"); //TODO: See if these commands actually handle the horizontal/vertical constraints properly... Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.X = %f", - getViewObject()->getNameInDocument(), x()); + getViewName(), Rez::appX(x())); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Y = %f", - getViewObject()->getNameInDocument(), getY());// inverts Y + getViewName(), Rez::appX(getY()));// inverts Y Gui::Command::commitCommand(); //Gui::Command::updateActive(); } diff --git a/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp b/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp index 6317c86a73..7ee5b0f3c1 100644 --- a/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp +++ b/src/Mod/TechDraw/Gui/QGISVGTemplate.cpp @@ -40,6 +40,7 @@ #include #include +#include "Rez.h" #include "ZVALUE.h" #include "TemplateTextField.h" #include "QGISVGTemplate.h" @@ -100,15 +101,15 @@ void QGISVGTemplate::load(const QString &fileName) firstTime = false; } - //This is probably first time only logic too. + //convert from pixels or mm or inches in svg file to mm page size TechDraw::DrawSVGTemplate *tmplte = getSVGTemplate(); double xaspect, yaspect; xaspect = tmplte->getWidth() / (double) size.width(); yaspect = tmplte->getHeight() / (double) size.height(); QTransform qtrans; - qtrans.translate(0.f, -tmplte->getHeight()); - qtrans.scale(xaspect , yaspect); + qtrans.translate(0.f, Rez::guiX(-tmplte->getHeight())); + qtrans.scale(Rez::guiX(xaspect) , Rez::guiX(yaspect)); m_svgItem->setTransform(qtrans); } @@ -190,11 +191,11 @@ void QGISVGTemplate::createClickHandles(void) QString yStr = QString::fromStdString(yMatch[1].str()); QString editableName = QString::fromStdString(nameMatch[1].str()); - double x = xStr.toDouble(); - double y = yStr.toDouble(); + double x = Rez::guiX(xStr.toDouble()); + double y = Rez::guiX(yStr.toDouble()); //TODO: this should probably be configurable without a code change - double editClickBoxSize = 1.5; + double editClickBoxSize = Rez::guiX(1.5); QColor editClickBoxColor = Qt::green; double width = editClickBoxSize; @@ -202,7 +203,7 @@ void QGISVGTemplate::createClickHandles(void) TemplateTextField *item = new TemplateTextField(this, tmplte, nameMatch[1].str(), qgview); float pad = 1; - item->setRect(x - pad, -tmplte->getHeight() + y - height - pad, + item->setRect(x - pad, Rez::guiX(-tmplte->getHeight()) + y - height - pad, width + 2 * pad, height + 2 * pad); QPen myPen; diff --git a/src/Mod/TechDraw/Gui/QGISectionLine.cpp b/src/Mod/TechDraw/Gui/QGISectionLine.cpp index b3022f0c1d..8350ccc3b8 100644 --- a/src/Mod/TechDraw/Gui/QGISectionLine.cpp +++ b/src/Mod/TechDraw/Gui/QGISectionLine.cpp @@ -33,6 +33,7 @@ #include #include +#include "Rez.h" #include "QGIView.h" #include "QGISectionLine.h" @@ -40,7 +41,7 @@ using namespace TechDrawGui; QGISectionLine::QGISectionLine() { - m_extLen = 8.0; + m_extLen = Rez::guiX(8.0); m_arrowSize = 0.0; m_line = new QGraphicsPathItem(); @@ -54,7 +55,7 @@ QGISectionLine::QGISectionLine() m_symbol2 = new QGCustomText(); addToGroup(m_symbol2); - setWidth(0.75); + setWidth(Rez::guiX(0.75)); setStyle(getSectionStyle()); setColor(getSectionColor()); @@ -74,7 +75,7 @@ void QGISectionLine::makeLine() QPainterPath pp; QPointF extLineStart,extLineEnd; QPointF offset(m_arrowDir.x,-m_arrowDir.y); - offset = 0.80 * m_extLen * offset; //0.80 is hack to hide line end behind arrowhead + offset = 0.75 * m_extLen * offset; //0.75 is hack to hide line end behind arrowhead extLineStart = m_start + offset; extLineEnd = m_end + offset; pp.moveTo(extLineStart); @@ -100,6 +101,8 @@ void QGISectionLine::makeArrows() extLineStart = m_start + offset; extLineEnd = m_end + offset; + m_arrow1->setStyle(0); + m_arrow2->setStyle(0); m_arrow1->setPos(extLineStart); //m_arrow1->flip(true); m_arrow1->draw(); @@ -121,9 +124,15 @@ void QGISectionLine::makeSymbols() m_symFont.setPointSize(m_symSize); m_symbol1->setFont(m_symFont); m_symbol1->setPlainText(QString::fromUtf8(m_symbol)); + if (m_arrowDir.y < 0.0) { //pointing down + extLineStart -= QPointF (0.0,m_symSize); //move text up a bit + } m_symbol1->centerAt(extLineStart); m_symbol2->setFont(m_symFont); m_symbol2->setPlainText(QString::fromUtf8(m_symbol)); + if (m_arrowDir.y < 0.0) { //pointing down + extLineEnd -= QPointF (0.0,m_symSize); + } m_symbol2->centerAt(extLineEnd); } diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index e06122a7e5..f22708c400 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -44,7 +44,12 @@ #include #include #include +#include +#include +#include + +#include "Rez.h" #include "QGCustomBorder.h" #include "QGCustomLabel.h" #include "QGIView.h" @@ -188,13 +193,9 @@ void QGIView::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) if (!isInnerView()) { double tempX = x(), tempY = getY(); -// getViewObject()->X.setValue(tempX); -// getViewObject()->Y.setValue(tempY); - getViewObject()->setPosition(tempX,tempY); + getViewObject()->setPosition(Rez::appX(tempX),Rez::appX(tempY)); } else { -// getViewObject()->X.setValue(x()); -// getViewObject()->Y.setValue(getYInClip(y())); - getViewObject()->setPosition(x(),getYInClip(y())); + getViewObject()->setPosition(Rez::appX(x()),Rez::appX(getYInClip(y()))); } getViewObject()->setMouseMove(false); } @@ -244,7 +245,7 @@ double QGIView::getYInClip(double y) if (parentView) { auto parentFeat( dynamic_cast(parentView->getViewObject()) ); if (parentFeat) { - return parentFeat->Height.getValue() - y; + return Rez::guiX(parentFeat->Height.getValue()) - y; } } } @@ -259,8 +260,8 @@ void QGIView::updateView(bool update) if (update || getViewObject()->X.isTouched() || getViewObject()->Y.isTouched()) { - double featX = getViewObject()->X.getValue(); - double featY = getViewObject()->Y.getValue(); + double featX = Rez::guiX(getViewObject()->X.getValue()); + double featY = Rez::guiX(getViewObject()->Y.getValue()); setPosition(featX,featY); } @@ -269,6 +270,7 @@ void QGIView::updateView(bool update) //NOTE: QPainterPaths have to be rotated individually. This transform handles Rotation for everything else. //Scale is handled in GeometryObject for DVP & descendents //Objects not descended from DVP must setScale for themselves + //note that setTransform(,,rotation,,) is not the same as setRotation!!! double rot = getViewObject()->Rotation.getValue(); QPointF centre = boundingRect().center(); setTransform(QTransform().translate(centre.x(), centre.y()).rotate(-rot).translate(-centre.x(), -centre.y())); @@ -295,11 +297,10 @@ void QGIView::setViewFeature(TechDraw::DrawView *obj) viewObj = obj; viewName = obj->getNameInDocument(); - - // Set the QGIGroup initial position based on the DrawView ( wrong. new views are always at Page center) -// float x = obj->X.getValue(); -// float y = obj->Y.getValue(); -// setPosition(x, y); + + //mark the actual QGraphicsItem so we can check what's in the scene later + setData(0,QString::fromUtf8("QGIV")); + setData(1,QString::fromUtf8(obj->getNameInDocument())); } void QGIView::toggleCache(bool state) @@ -408,7 +409,7 @@ void QGIView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; - //painter->drawRect(boundingRect()); + //painter->drawRect(boundingRect()); //good for debugging QGraphicsItemGroup::paint(painter, &myOption, widget); } @@ -454,6 +455,15 @@ QGIView* QGIView::getQGIVByName(std::string name) return 0; } +/* static */ +Gui::ViewProvider* QGIView::getViewProvider(App::DocumentObject* obj) +{ + Gui::Document* guiDoc = Gui::Application::Instance->getDocument(obj->getDocument()); + Gui::ViewProvider* result = guiDoc->getViewProvider(obj); + return result; +} + + QColor QGIView::getNormalColor() { Base::Reference hGrp = getParmGroupCol(); @@ -501,7 +511,7 @@ double QGIView::getPrefFontSize() Base::Reference hGrp = App::GetApplication().GetUserParameter(). GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Labels"); double fontSize = hGrp->GetFloat("LabelSize", 5.0); - return fontSize; + return Rez::guiX(fontSize); } void QGIView::dumpRect(char* text, QRectF r) { diff --git a/src/Mod/TechDraw/Gui/QGIView.h b/src/Mod/TechDraw/Gui/QGIView.h index 008dd5c4c8..eb217b32f5 100644 --- a/src/Mod/TechDraw/Gui/QGIView.h +++ b/src/Mod/TechDraw/Gui/QGIView.h @@ -27,8 +27,10 @@ #include #include +#include #include #include +#include #include @@ -87,6 +89,8 @@ public: virtual QColor getNormalColor(void); virtual QColor getPreColor(void); virtual QColor getSelectColor(void); + + static Gui::ViewProvider* getViewProvider(App::DocumentObject* obj); protected: QGIView* getQGIVByName(std::string name); diff --git a/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp b/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp index b21cd5ebb5..e1b0801230 100644 --- a/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewAnnotation.cpp @@ -50,6 +50,7 @@ #include #include +#include "Rez.h" #include "QGIViewAnnotation.h" #include "QGCustomText.h" @@ -115,6 +116,8 @@ void QGIViewAnnotation::draw() } } +//TODO: text is position slightly high (and left??) on page save to SVG file + void QGIViewAnnotation::drawAnnotation() { auto viewAnno( dynamic_cast(getViewObject()) ); @@ -129,7 +132,7 @@ void QGIViewAnnotation::drawAnnotation() ss << "\n\n