From 3a42205cb44807ef3451b9a7fb97bcb39e2396d2 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Tue, 11 Feb 2020 06:50:42 -0500 Subject: [PATCH] [TD]fix autoscale for DPG --- src/Mod/TechDraw/App/DrawProjGroup.cpp | 119 ++++++++++------------- src/Mod/TechDraw/App/DrawProjGroup.h | 4 +- src/Mod/TechDraw/App/DrawProjGroupItem.h | 3 + src/Mod/TechDraw/App/DrawView.cpp | 60 +++++++++--- src/Mod/TechDraw/App/DrawView.h | 4 +- src/Mod/TechDraw/App/DrawViewPart.cpp | 66 ++++++++----- src/Mod/TechDraw/App/DrawViewPart.h | 1 + 7 files changed, 146 insertions(+), 111 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawProjGroup.cpp b/src/Mod/TechDraw/App/DrawProjGroup.cpp index 7225bdf4d9..9d1e1a8e8d 100644 --- a/src/Mod/TechDraw/App/DrawProjGroup.cpp +++ b/src/Mod/TechDraw/App/DrawProjGroup.cpp @@ -60,7 +60,8 @@ const char* DrawProjGroup::ProjectionTypeEnums[] = {"Default", PROPERTY_SOURCE(TechDraw::DrawProjGroup, TechDraw::DrawViewCollection) -DrawProjGroup::DrawProjGroup(void) +DrawProjGroup::DrawProjGroup(void) : + m_lockScale(false) { static const char *group = "Base"; static const char *agroup = "Distribute"; @@ -97,20 +98,12 @@ void DrawProjGroup::onChanged(const App::Property* prop) TechDraw::DrawPage *page = getPage(); if (!isRestoring() && page) { if (prop == &Source) { -// std::vector sourceObjs = Source.getValues(); -// if (!sourceObjs.empty()) { -// if (!hasAnchor()) { -// // if we have a Source, but no Anchor, make an anchor -// Anchor.setValue(addProjection("Front")); //<<<<< semi-loop here! -// //add projection marks object as changed -> onChanged, but anchor value isn't set -// Anchor.purgeTouched(); //don't need to mark this -// } -// } else { -// //Source has been changed to null! Why? What to do? -// } + //nothing in particular } if (prop == &Scale) { - updateChildrenScale(); + if (!m_lockScale) { + updateChildrenScale(); + } } if (prop == &ProjectionType) { @@ -128,11 +121,7 @@ void DrawProjGroup::onChanged(const App::Property* prop) if (prop == &ScaleType) { double newScale = getScale(); if (ScaleType.isValue("Automatic")) { - //Recalculate scale if Group is too big or too small! - newScale = calculateAutomaticScale(); - if(std::abs(getScale() - newScale) > FLT_EPSILON) { - Scale.setValue(newScale); - } + //Nothing in particular } else if (ScaleType.isValue("Page")) { newScale = page->Scale.getValue(); if(std::abs(getScale() - newScale) > FLT_EPSILON) { @@ -176,8 +165,18 @@ App::DocumentObjectExecReturn *DrawProjGroup::execute(void) return DrawViewCollection::execute(); } - autoPositionChildren(); + if (ScaleType.isValue("Automatic")) { + if (!checkFit()) { + double newScale = autoScale(); + m_lockScale = true; + Scale.setValue(newScale); + Scale.purgeTouched(); + updateChildrenScale(); + m_lockScale = false; + } + } + autoPositionChildren(); return DrawViewCollection::execute(); } @@ -219,6 +218,7 @@ Base::BoundBox3d DrawProjGroup::getBoundingBox() const bb.ScaleX(1. / part->getScale()); bb.ScaleY(1. / part->getScale()); + bb.ScaleZ(1. / part->getScale()); // X and Y of dependent views are relative to the anchorView if (part != anchorView) { @@ -237,6 +237,7 @@ TechDraw::DrawPage * DrawProjGroup::getPage(void) const return findParentPage(); } +// obs? replaced by autoscale? // Function provided by Joe Dowsett, 2014 double DrawProjGroup::calculateAutomaticScale() const { @@ -248,15 +249,14 @@ double DrawProjGroup::calculateAutomaticScale() const arrangeViewPointers(viewPtrs); double width, height; - minimumBbViews(viewPtrs, width, height); //get 1:1 bbxs - // if Page.keepUpdated is false, and DrawViews have never been executed, - // bb's will be 0x0 and this routine will return 0!!! - // if we return 1.0, AutoScale will sort itself out once bb's are non-zero. + minimumBbViews(viewPtrs, width, height); //get SCALED boxes! + // if Page.keepUpdated is false, and DrawViews have never been executed, + // bb's will be 0x0 and this routine will return 0!!! + // if we return 1.0, AutoScale will sort itself out once bb's are non-zero. double bbFudge = 1.2; width *= bbFudge; height *= bbFudge; - // C++ Standard says casting bool to int gives 0 or 1 int numVertSpaces = (viewPtrs[0] || viewPtrs[3] || viewPtrs[7]) + (viewPtrs[2] || viewPtrs[5] || viewPtrs[9]) + @@ -284,26 +284,36 @@ double DrawProjGroup::calculateAutomaticScale() const return result; } +//returns the (scaled) bounding rectangle of all the views. QRectF DrawProjGroup::getRect() const //this is current rect, not potential rect { +// Base::Console().Message("DPG::getRect - views: %d\n", Views.getValues().size()); DrawProjGroupItem *viewPtrs[10]; arrangeViewPointers(viewPtrs); double width, height; - minimumBbViews(viewPtrs, width, height); // w,h of just the views at 1:1 scale + minimumBbViews(viewPtrs, width, height); //this is scaled! double xSpace = spacingX.getValue() * 3.0 * std::max(1.0,getScale()); double ySpace = spacingY.getValue() * 2.0 * std::max(1.0,getScale()); - double rectW = getScale() * width + xSpace; //scale the 1:1 w,h and add whitespace - double rectH = getScale() * height + ySpace; + double rectW = 0.0; + double rectH = 0.0; + if ( !(DrawUtil::fpCompare(width, 0.0) && + DrawUtil::fpCompare(height, 0.0)) ) { + rectW = width + xSpace; + rectH = height + ySpace; + } + double fudge = 1.3; //make rect a little big to make sure it fits + rectW *= fudge; + rectH *= fudge; return QRectF(0,0,rectW,rectH); } -//find area consumed by Views only in 1:1 Scale +//find area consumed by Views only in current scale void DrawProjGroup::minimumBbViews(DrawProjGroupItem *viewPtrs[10], double &width, double &height) const { // Get bounding boxes in object scale Base::BoundBox3d bboxes[10]; - makeViewBbs(viewPtrs, bboxes, true); + makeViewBbs(viewPtrs, bboxes, true); //true => scaled //TODO: note that TLF/TRF/BLF,BRF extend a bit farther than a strict row/col arrangement would suggest. //get widest view in each row/column @@ -607,6 +617,7 @@ gp_Dir DrawProjGroup::vec2dir(Base::Vector3d v) return result; } +//this can be improved. this implementation positions views too far apart. Base::Vector3d DrawProjGroup::getXYPosition(const char *viewTypeCStr) { Base::Vector3d result(0.0,0.0,0.0); @@ -635,14 +646,14 @@ Base::Vector3d DrawProjGroup::getXYPosition(const char *viewTypeCStr) // Calculate bounding boxes for each displayed view Base::BoundBox3d bboxes[10]; - makeViewBbs(viewPtrs, bboxes); + makeViewBbs(viewPtrs, bboxes); //scaled - double xSpacing = spacingX.getValue(); //in mm/scale - double ySpacing = spacingY.getValue(); //in mm/scale + double xSpacing = spacingX.getValue(); //in mm, no scale + double ySpacing = spacingY.getValue(); //in mm, no scale double bigRow = 0.0; double bigCol = 0.0; - for (auto& b: bboxes) { + for (auto& b: bboxes) { //space based on width/height of biggest view if (!b.IsValid()) { continue; } @@ -659,6 +670,7 @@ Base::Vector3d DrawProjGroup::getXYPosition(const char *viewTypeCStr) bigCol = std::max(bigCol,bigRow); bigRow = bigCol; } + //TODO: find biggest for each row/column and adjust calculation to use bigCol[i], bigRow[j] ????? if (viewPtrs[0] && //iso bboxes[0].IsValid()) { @@ -791,7 +803,7 @@ int DrawProjGroup::getViewIndex(const char *viewTypeCStr) const void DrawProjGroup::arrangeViewPointers(DrawProjGroupItem *viewPtrs[10]) const { for (int i=0; i<10; ++i) { - viewPtrs[i] = NULL; + viewPtrs[i] = nullptr; } // Determine layout - should be either "First Angle" or "Third Angle" @@ -871,7 +883,9 @@ void DrawProjGroup::makeViewBbs(DrawProjGroupItem *viewPtrs[10], Base::BoundBox3d bboxes[10], bool documentScale) const { - for (int i = 0; i < 10; ++i) + Base::BoundBox3d empty(Base::Vector3d(0.0, 0.0, 0.0), 0.0); + for (int i = 0; i < 10; ++i) { + bboxes[i] = empty; if (viewPtrs[i]) { bboxes[i] = viewPtrs[i]->getBoundingBox(); if (!documentScale) { @@ -880,12 +894,8 @@ void DrawProjGroup::makeViewBbs(DrawProjGroupItem *viewPtrs[10], bboxes[i].ScaleY(scale); bboxes[i].ScaleZ(scale); } - } else { - // BoundBox3d defaults to length=(FLOAT_MAX + -FLOAT_MAX) - bboxes[i].ScaleX(0); - bboxes[i].ScaleY(0); - bboxes[i].ScaleZ(0); } + } } void DrawProjGroup::recomputeChildren(void) @@ -928,6 +938,7 @@ void DrawProjGroup::updateChildrenScale(void) throw Base::TypeError("Error: projection in DPG list is not a DPGI!"); } else if(view->Scale.getValue()!=Scale.getValue()) { view->Scale.setValue(Scale.getValue()); + view->recomputeFeature(); } } } @@ -982,34 +993,6 @@ void DrawProjGroup::updateChildrenEnforce(void) } } -/*! - * check if ProjectionGroup fits on Page - */ -bool DrawProjGroup::checkFit(TechDraw::DrawPage* p) const -{ - bool result = true; - - QRectF viewBox = getRect(); - double fudge = 1.1; - double maxWidth = viewBox.width() * fudge; - double maxHeight = viewBox.height() * fudge; - - if ( (maxWidth > p->getPageWidth()) || - (maxHeight > p->getPageHeight()) ) { - result = false; - } - - if (ScaleType.isValue("Automatic")) { //expand if too small - double magnifyLimit = 0.60; - if ( (maxWidth < p->getPageWidth() * magnifyLimit) && - (maxHeight < p->getPageHeight() * magnifyLimit) ) { - result = false; - } - } - return result; -} - - App::Enumeration DrawProjGroup::usedProjectionType(void) { //TODO: Would've been nice to have an Enumeration(const PropertyEnumeration &) constructor diff --git a/src/Mod/TechDraw/App/DrawProjGroup.h b/src/Mod/TechDraw/App/DrawProjGroup.h index 011c8731aa..23d5367104 100644 --- a/src/Mod/TechDraw/App/DrawProjGroup.h +++ b/src/Mod/TechDraw/App/DrawProjGroup.h @@ -69,7 +69,6 @@ public: Base::BoundBox3d getBoundingBox() const; double calculateAutomaticScale() const; virtual QRectF getRect(void) const override; - virtual bool checkFit(TechDraw::DrawPage* p) const override; /// Check if container has a view of a specific type bool hasProjection(const char *viewProjType) const; @@ -175,7 +174,8 @@ protected: gp_Dir vec2dir(Base::Vector3d v); virtual void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property * prop) override; - + + bool m_lockScale; }; } //namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.h b/src/Mod/TechDraw/App/DrawProjGroupItem.h index d8a7cc0447..7ecbe1aec9 100644 --- a/src/Mod/TechDraw/App/DrawProjGroupItem.h +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.h @@ -85,6 +85,9 @@ public: void autoPosition(void); bool isAnchor(void) const; + //DPGI always fits on page since DPG handles scaling + virtual bool checkFit(void) const override { return true; } + virtual bool checkFit(DrawPage*) const override { return true; } protected: void onChanged(const App::Property* prop) override; diff --git a/src/Mod/TechDraw/App/DrawView.cpp b/src/Mod/TechDraw/App/DrawView.cpp index f23caf1293..39f8407ff0 100644 --- a/src/Mod/TechDraw/App/DrawView.cpp +++ b/src/Mod/TechDraw/App/DrawView.cpp @@ -262,30 +262,60 @@ DrawViewClip* DrawView::getClipGroup(void) return result; } - -double DrawView::autoScale(double w, double h) const +double DrawView::autoScale(void) const { - double fudgeFactor = 0.90; - QRectF viewBox = getRect(); + auto page = findParentPage(); + double w = page->getPageWidth(); + double h = page->getPageHeight(); + return autoScale(w,h); +} + +//compare 1:1 rect of view to pagesize(pw,h) +double DrawView::autoScale(double pw, double ph) const +{ +// Base::Console().Message("DV::autoScale(Page: %.3f, %.3f) - %s\n", pw, ph, getNameInDocument()); + double fudgeFactor = 1.0; //make it a bit smaller just in case. + QRectF viewBox = getRect(); //getRect is scaled (ie current actual size) + if (!viewBox.isValid()) { + return 1.0; + } //have to unscale rect to determine new scale double vbw = viewBox.width()/getScale(); double vbh = viewBox.height()/getScale(); - double xScale = w/vbw; - double yScale = h/vbh; - //TODO: find a standard scale that's close? 1:2, 1:10, 1:100...? Logic in TaskProjGroup - double newScale = fudgeFactor * std::min(xScale,yScale); - newScale = DrawUtil::sensibleScale(newScale); - return newScale; + double xScale = pw/vbw; // > 1 page bigger than figure + double yScale = ph/vbh; // < 1 page is smaller than figure + double newScale = std::min(xScale,yScale) * fudgeFactor; + double sensibleScale = DrawUtil::sensibleScale(newScale); + return sensibleScale; } -//!check if View fits on Page +bool DrawView::checkFit(void) const +{ + auto page = findParentPage(); + return checkFit(page); +} + +//!check if View is too big for page +//should check if unscaled rect is too big for page bool DrawView::checkFit(TechDraw::DrawPage* p) const { bool result = true; - QRectF viewBox = getRect(); - if ( (viewBox.width() > p->getPageWidth()) || - (viewBox.height() > p->getPageHeight()) ) { - result = false; + double fudge = 1.1; + + double width = 0.0; + double height = 0.0; + QRectF viewBox = getRect(); //rect is scaled + if (!viewBox.isValid()) { + result = true; + } else { + width = viewBox.width() / getScale(); //unscaled rect w x h + height = viewBox.height() / getScale(); + width *= fudge; + height *= fudge; + if ( (width > p->getPageWidth()) || + (height > p->getPageHeight()) ) { + result = false; + } } return result; } diff --git a/src/Mod/TechDraw/App/DrawView.h b/src/Mod/TechDraw/App/DrawView.h index 31d0cfd22b..d7f3c0838e 100644 --- a/src/Mod/TechDraw/App/DrawView.h +++ b/src/Mod/TechDraw/App/DrawView.h @@ -83,7 +83,9 @@ public: virtual DrawPage* findParentPage() const; virtual QRectF getRect() const; //must be overridden by derived class + virtual double autoScale(void) const; virtual double autoScale(double w, double h) const; + virtual bool checkFit(void) const; virtual bool checkFit(DrawPage*) const; virtual void setPosition(double x, double y, bool force = false); bool keepUpdated(void); @@ -106,8 +108,6 @@ protected: int prefScaleType(void); double prefScale(void); - - private: static const char* ScaleTypeEnums[]; static App::PropertyFloatConstraint::Constraints scaleRange; diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 209d8cba5a..edbfd43825 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -167,6 +167,8 @@ DrawViewPart::DrawViewPart(void) : geometryObject = nullptr; getRunControl(); + //initialize bbox to non-garbage + bbox = Base::BoundBox3d(Base::Vector3d(0.0, 0.0, 0.0), 0.0); } DrawViewPart::~DrawViewPart() @@ -254,33 +256,32 @@ App::DocumentObjectExecReturn *DrawViewPart::execute(void) XDirection.purgeTouched(); //don't trigger updates! //unblock } - -// m_saveShape = shape; - geometryObject = makeGeometryForShape(shape); - -#if MOD_TECHDRAW_HANDLE_FACES auto start = std::chrono::high_resolution_clock::now(); - if (handleFaces() && !geometryObject->usePolygonHLR()) { - try { - extractFaces(); - } - catch (Standard_Failure& e4) { - Base::Console().Log("LOG - DVP::execute - extractFaces failed for %s - %s **\n",getNameInDocument(),e4.GetMessageString()); - return new App::DocumentObjectExecReturn(e4.GetMessageString()); + + m_saveShape = shape; + buildGeometry(shape); + + //second pass if required + if (ScaleType.isValue("Automatic")) { + if (!checkFit()) { + double newScale = autoScale(); + Scale.setValue(newScale); + Scale.purgeTouched(); + if (geometryObject != nullptr) { + delete geometryObject; + geometryObject = nullptr; + buildGeometry(shape); + } } } - addCosmeticVertexesToGeom(); - addCosmeticEdgesToGeom(); - addCenterLinesToGeom(); - auto end = std::chrono::high_resolution_clock::now(); auto diff = end - start; double diffOut = std::chrono::duration (diff).count(); Base::Console().Log("TIMING - %s DVP spent: %.3f millisecs handling Faces\n", getNameInDocument(),diffOut); -#endif //#if MOD_TECHDRAW_HANDLE_FACES +//#endif //#if MOD_TECHDRAW_HANDLE_FACES // Base::Console().Message("DVP::execute - exits\n"); return DrawView::execute(); } @@ -318,6 +319,28 @@ void DrawViewPart::onChanged(const App::Property* prop) //TODO: when scale changes, any Dimensions for this View sb recalculated. DVD should pick this up subject to topological naming issues. } +void DrawViewPart::buildGeometry(TopoDS_Shape shape) +{ +// Base::Console().Message("DVP::buildGeometry()\n"); + geometryObject = makeGeometryForShape(shape); + +#if MOD_TECHDRAW_HANDLE_FACES +// auto start = std::chrono::high_resolution_clock::now(); + if (handleFaces() && !geometryObject->usePolygonHLR()) { + try { + extractFaces(); + } + catch (Standard_Failure& e4) { + Base::Console().Log("LOG - DVP::execute - extractFaces failed for %s - %s **\n",getNameInDocument(),e4.GetMessageString()); + } + } +#endif //#if MOD_TECHDRAW_HANDLE_FACES + + addCosmeticVertexesToGeom(); + addCosmeticEdgesToGeom(); + addCenterLinesToGeom(); +} + GeometryObject* DrawViewPart::makeGeometryForShape(TopoDS_Shape shape) { // Base::Console().Message("DVP::makeGeometryforShape() - %s\n", Label.getValue()); @@ -725,15 +748,10 @@ double DrawViewPart::getBoxY(void) const QRectF DrawViewPart::getRect() const { +// Base::Console().Message("DVP::getRect() - %s\n", getNameInDocument()); double x = getBoxX(); double y = getBoxY(); - QRectF result; - if (std::isinf(x) || std::isinf(y)) { - //geometry isn't created yet. return an arbitrary rect. - result = QRectF(0.0,0.0,100.0,100.0); - } else { - result = QRectF(0.0,0.0,getBoxX(),getBoxY()); //this is from GO and is already scaled - } + QRectF result(0.0, 0.0, x, y); return result; } diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index 995f49f904..5311ae1b42 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -201,6 +201,7 @@ protected: virtual TechDraw::GeometryObject* buildGeometryObject(TopoDS_Shape shape, gp_Ax2 viewAxis); //const?? virtual TechDraw::GeometryObject* makeGeometryForShape(TopoDS_Shape shape); //const?? + void buildGeometry(TopoDS_Shape shape); void extractFaces();