From cf90d6931914bb1f7a0cdb1eefd27b14e23bf458 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Fri, 5 Aug 2016 14:12:47 -0400 Subject: [PATCH] Implement automatic scaling --- src/Mod/TechDraw/App/DrawPage.cpp | 8 +- src/Mod/TechDraw/App/DrawProjGroup.cpp | 63 ++++++++++++---- src/Mod/TechDraw/App/DrawProjGroup.h | 2 + src/Mod/TechDraw/App/DrawProjGroupItem.cpp | 20 +---- src/Mod/TechDraw/App/DrawView.cpp | 83 +++++++++++++-------- src/Mod/TechDraw/App/DrawView.h | 6 +- src/Mod/TechDraw/App/DrawViewAnnotation.cpp | 19 ++++- src/Mod/TechDraw/App/DrawViewAnnotation.h | 5 +- src/Mod/TechDraw/App/DrawViewClip.h | 2 +- src/Mod/TechDraw/App/DrawViewCollection.cpp | 11 +++ src/Mod/TechDraw/App/DrawViewCollection.h | 1 + src/Mod/TechDraw/App/DrawViewDimension.h | 1 + src/Mod/TechDraw/App/DrawViewPart.cpp | 20 +++++ src/Mod/TechDraw/App/DrawViewPart.h | 3 + src/Mod/TechDraw/App/DrawViewSymbol.cpp | 31 +++++++- src/Mod/TechDraw/App/DrawViewSymbol.h | 1 + 16 files changed, 198 insertions(+), 78 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawPage.cpp b/src/Mod/TechDraw/App/DrawPage.cpp index 694033a28..e43d4580b 100644 --- a/src/Mod/TechDraw/App/DrawPage.cpp +++ b/src/Mod/TechDraw/App/DrawPage.cpp @@ -244,11 +244,17 @@ int DrawPage::addView(App::DocumentObject *docObj) view->Y.setValue(getPageHeight()/2.0); } + //add view to list const std::vector currViews = Views.getValues(); std::vector newViews(currViews); newViews.push_back(docObj); Views.setValues(newViews); - Views.touch(); + + //check if View fits on Page + if ( !view->checkFit(this) ) { + Base::Console().Warning("%s is larger than page. Will be scaled.\n",view->getNameInDocument()); + view->ScaleType.setValue("Automatic"); + } return Views.getSize(); } diff --git a/src/Mod/TechDraw/App/DrawProjGroup.cpp b/src/Mod/TechDraw/App/DrawProjGroup.cpp index ad70202c0..cb4831436 100644 --- a/src/Mod/TechDraw/App/DrawProjGroup.cpp +++ b/src/Mod/TechDraw/App/DrawProjGroup.cpp @@ -149,7 +149,8 @@ double DrawProjGroup::calculateAutomaticScale() const double scale_x = availableX / width; double scale_y = availableY / height; - float working_scale = std::min(scale_x, scale_y); + double fudgeFactor = 0.90; + float working_scale = fudgeFactor * std::min(scale_x, scale_y); //which gives the largest scale for which the min_space requirements can be met, but we want a 'sensible' scale, rather than 0.28457239... //eg if working_scale = 0.115, then we want to use 0.1, similarly 7.65 -> 5, and 76.5 -> 50 @@ -168,6 +169,15 @@ double DrawProjGroup::calculateAutomaticScale() const return valid_scales[(exponent >= 0)][i] * pow(10, exponent); } +QRectF DrawProjGroup::getRect() const +{ + DrawProjGroupItem *viewPtrs[10]; + arrangeViewPointers(viewPtrs); + double width, height; + minimumBbViews(viewPtrs, width, height); //min space for 1:1 drawing + return QRectF(0,0,Scale.getValue() * width,Scale.getValue() * height); +} + void DrawProjGroup::minimumBbViews(DrawProjGroupItem *viewPtrs[10], double &width, double &height) const { @@ -543,29 +553,52 @@ void DrawProjGroup::setFrontViewOrientation(const Base::Matrix4D &newMat) App::DocumentObjectExecReturn *DrawProjGroup::execute(void) { + //if group hasn't been added to page yet, can't scale or distribute projItems + TechDraw::DrawPage *page = getPage(); + if (!page) { + return DrawViewCollection::execute(); + } + if (ScaleType.isValue("Automatic")) { - - //Recalculate scale - double autoScale = calculateAutomaticScale(); - - if(std::abs(Scale.getValue() - autoScale) > FLT_EPSILON) { - // Set this Scale - Scale.setValue(autoScale); - + //Recalculate scale if Group is too big + if (!checkFit(page)) { + double newScale = calculateAutomaticScale(); + if(std::abs(Scale.getValue() - newScale) > FLT_EPSILON) { + Scale.setValue(newScale); + //Rebuild the DPGI's + for( const auto it : Views.getValues() ) { + auto view( dynamic_cast(it) ); + if( view ) { + view->ScaleType.setValue("Custom"); + view->Scale.setValue(newScale); //not sure we have to set scale here. DVP will do it based on ScaleType + view->Scale.setStatus(App::Property::ReadOnly,true); + //view->touch(); + } + } + resetPositions(); + } + } + } else if (ScaleType.isValue("Document")) { + double docScale = page->Scale.getValue(); + if(std::abs(Scale.getValue() - docScale) > FLT_EPSILON) { + Scale.setValue(docScale); //Rebuild the DPGI's - for( const auto it : Views.getValues() ) { - auto view( dynamic_cast(it) ); - if( view ) { - view->ScaleType.setValue("Custom"); - view->Scale.setValue(autoScale); + const std::vector &views = Views.getValues(); + for(std::vector::const_iterator it = views.begin(); it != views.end(); ++it) { + App::DocumentObject *docObj = *it; + if(docObj->getTypeId().isDerivedFrom(DrawProjGroupItem::getClassTypeId())) { + DrawProjGroupItem *view = dynamic_cast(*it); + view->ScaleType.setValue("Document"); + view->Scale.setValue(docScale); view->Scale.setStatus(App::Property::ReadOnly,true); - view->touch(); + //view->touch(); } } resetPositions(); } } + // recalculate positions for children if (Views.getSize()) { distributeProjections(); diff --git a/src/Mod/TechDraw/App/DrawProjGroup.h b/src/Mod/TechDraw/App/DrawProjGroup.h index 620a851c7..a6b53e2d2 100644 --- a/src/Mod/TechDraw/App/DrawProjGroup.h +++ b/src/Mod/TechDraw/App/DrawProjGroup.h @@ -23,6 +23,7 @@ #ifndef _TECHDRAW_FEATUREVIEWGROUP_H_ #define _TECHDRAW_FEATUREVIEWGROUP_H_ +# include #include #include @@ -63,6 +64,7 @@ public: Base::BoundBox3d getBoundingBox() const; double calculateAutomaticScale() const; + virtual QRectF getRect(void) const; /// Check if container has a view of a specific type bool hasProjection(const char *viewProjType) const; diff --git a/src/Mod/TechDraw/App/DrawProjGroupItem.cpp b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp index dc7fc223e..08a562d73 100644 --- a/src/Mod/TechDraw/App/DrawProjGroupItem.cpp +++ b/src/Mod/TechDraw/App/DrawProjGroupItem.cpp @@ -56,17 +56,9 @@ DrawProjGroupItem::DrawProjGroupItem(void) Type.setEnums(TypeEnums); ADD_PROPERTY(Type, ((long)0)); - // Set Hidden - //Direction.StatusBits.set(3); + //projection group controls these Direction.setStatus(App::Property::Hidden,true); - - // Set Hidden - //XAxisDirection.StatusBits.set(3); XAxisDirection.setStatus(App::Property::Hidden,true); - - // Scale and ScaleType are Readonly - //Scale.StatusBits.set(2); - //ScaleType.StatusBits.set(2); Scale.setStatus(App::Property::ReadOnly,true); ScaleType.setStatus(App::Property::ReadOnly,true); } @@ -101,16 +93,6 @@ void DrawProjGroupItem::onDocumentRestored() execute(); } -/* -//TODO: Perhaps we don't need this anymore? -App::DocumentObjectExecReturn *DrawProjGroupItem::execute(void) -{ - if(Type.isTouched()) { - Type.purgeTouched(); - } - - return TechDraw::DrawViewPart::execute(); -}*/ PyObject *DrawProjGroupItem::getPyObject(void) { diff --git a/src/Mod/TechDraw/App/DrawView.cpp b/src/Mod/TechDraw/App/DrawView.cpp index caad7ad96..17e8761dc 100644 --- a/src/Mod/TechDraw/App/DrawView.cpp +++ b/src/Mod/TechDraw/App/DrawView.cpp @@ -79,69 +79,63 @@ DrawView::~DrawView() { } -App::DocumentObjectExecReturn *DrawView::recompute(void) -{ - try { - return App::DocumentObject::recompute(); - } - catch (Standard_Failure) { - Handle_Standard_Failure e = Standard_Failure::Caught(); - App::DocumentObjectExecReturn* ret = new App::DocumentObjectExecReturn(e->GetMessageString()); - if (ret->Why.empty()) ret->Why = "Unknown OCC exception"; - return ret; - } -} - App::DocumentObjectExecReturn *DrawView::execute(void) { - //right way to handle this? can't do it at creation since don't have a parent. - if (ScaleType.isValue("Document")) { - TechDraw::DrawPage *page = findParentPage(); - if(page) { + TechDraw::DrawPage *page = findParentPage(); + if(page) { + if (ScaleType.isValue("Document")) { if(std::abs(page->Scale.getValue() - Scale.getValue()) > FLT_EPSILON) { Scale.setValue(page->Scale.getValue()); - Scale.touch(); + } + } else if (ScaleType.isValue("Automatic")) { + //check fit. if too big, rescale + if (!checkFit(page)) { + double newScale = autoScale(page->getPageWidth(),page->getPageHeight()); + if(std::abs(newScale - Scale.getValue()) > FLT_EPSILON) { //stops onChanged/execute loop + Scale.setValue(newScale); + } } } } - return App::DocumentObject::execute(); } -/// get called by the container when a Property was changed void DrawView::onChanged(const App::Property* prop) { if (!isRestoring()) { - if (prop == &ScaleType || - prop == &Scale) { + if (prop == &Scale) { + execute(); + } else if (prop == &ScaleType) { if (ScaleType.isValue("Document")) { - TechDraw::DrawPage *page = findParentPage(); - if(page) { - if(std::abs(page->Scale.getValue() - Scale.getValue()) > FLT_EPSILON) { - Scale.setValue(page->Scale.getValue()); // Reset scale from page - Scale.touch(); - } - } Scale.setStatus(App::Property::ReadOnly,true); App::GetApplication().signalChangePropertyEditor(Scale); } else if ( ScaleType.isValue("Custom") ) { Scale.setStatus(App::Property::ReadOnly,false); App::GetApplication().signalChangePropertyEditor(Scale); + } else if ( ScaleType.isValue("Automatic") ) { + Scale.setStatus(App::Property::ReadOnly,true); + App::GetApplication().signalChangePropertyEditor(Scale); } - //TODO else if (ScaleType.isValue("Automatic"))... - DrawView::execute(); + execute(); } else if (prop == &X || prop == &Y) { setAutoPos(false); - DrawView::execute(); + execute(); } else if (prop == &Rotation) { - DrawView::execute(); + execute(); } } App::DocumentObject::onChanged(prop); } +////you must override this in derived class +QRectF DrawView::getRect() const +{ + QRectF result(0,0,1,1); + return result; +} + void DrawView::onDocumentRestored() { // Rebuild the view @@ -182,6 +176,29 @@ bool DrawView::isInClip() return false; } +double DrawView::autoScale(double w, double h) const +{ + double fudgeFactor = 0.90; + QRectF viewBox = getRect(); + double xScale = w/viewBox.width(); + double yScale = h/viewBox.height(); + //find a standard scale that's close? 1:2, 1:10, 1:100...? + double newScale = fudgeFactor * std::min(xScale,yScale); + return newScale; +} + +//!check if View fits on 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; + } + return result; +} + PyObject *DrawView::getPyObject(void) { if (PythonObject.is(Py::_None())) { diff --git a/src/Mod/TechDraw/App/DrawView.h b/src/Mod/TechDraw/App/DrawView.h index 8a9e03096..4f4090c5f 100644 --- a/src/Mod/TechDraw/App/DrawView.h +++ b/src/Mod/TechDraw/App/DrawView.h @@ -23,6 +23,8 @@ #ifndef _DrawView_h_ #define _DrawView_h_ +#include + #include #include #include @@ -54,7 +56,6 @@ public: /** @name methods overide Feature */ //@{ /// recalculate the Feature - virtual App::DocumentObjectExecReturn *recompute(void); virtual App::DocumentObjectExecReturn *execute(void); virtual void onDocumentRestored(); //@} @@ -71,6 +72,9 @@ public: DrawPage* findParentPage() const; bool allowAutoPos() {return autoPos;}; //sb in DPGI?? void setAutoPos(bool state) {autoPos = state;}; + virtual QRectF getRect() const; //must be overridden by derived class + virtual double autoScale(double w, double h) const; + virtual bool checkFit(DrawPage*) const; protected: void onChanged(const App::Property* prop); diff --git a/src/Mod/TechDraw/App/DrawViewAnnotation.cpp b/src/Mod/TechDraw/App/DrawViewAnnotation.cpp index ae23aae6d..9726ec6d4 100644 --- a/src/Mod/TechDraw/App/DrawViewAnnotation.cpp +++ b/src/Mod/TechDraw/App/DrawViewAnnotation.cpp @@ -73,8 +73,6 @@ DrawViewAnnotation::DrawViewAnnotation(void) TextStyle.setEnums(TextStyleEnums); ADD_PROPERTY(TextStyle, ((long)0)); - //Scale.StatusBits.set(3); //hide scale. n/a for Annotation - //ScaleType.StatusBits.set(3); Scale.setStatus(App::Property::Hidden,true); ScaleType.setStatus(App::Property::Hidden,true); } @@ -104,6 +102,23 @@ void DrawViewAnnotation::onChanged(const App::Property* prop) TechDraw::DrawView::onChanged(prop); } +QRectF DrawViewAnnotation::getRect() const +{ + QRectF result; + double tSize = TextSize.getValue(); + int lines = Text.getValues().size(); + int chars = 1; + for (auto& l:Text.getValues()) { + if ((int)l.size() > chars) { + chars = (int)l.size(); + } + } + int w = chars * std::max(1,(int)tSize); + int h = lines * std::max(1,(int)tSize); + result = QRectF(0,0,Scale.getValue() * w,Scale.getValue() * h); + return result; +} + App::DocumentObjectExecReturn *DrawViewAnnotation::execute(void) { return TechDraw::DrawView::execute(); diff --git a/src/Mod/TechDraw/App/DrawViewAnnotation.h b/src/Mod/TechDraw/App/DrawViewAnnotation.h index 86dfb72a1..6a385a2cf 100644 --- a/src/Mod/TechDraw/App/DrawViewAnnotation.h +++ b/src/Mod/TechDraw/App/DrawViewAnnotation.h @@ -27,7 +27,6 @@ #ifndef _DrawViewAnnotation_h_ #define _DrawViewAnnotation_h_ - #include #include #include @@ -39,8 +38,6 @@ namespace TechDraw { -/** Base class of all View Features in the drawing module - */ class TechDrawExport DrawViewAnnotation : public TechDraw::DrawView { PROPERTY_HEADER(TechDraw::DrawViewAnnotation); @@ -58,6 +55,8 @@ public: App::PropertyEnumeration TextStyle; // Plain,Bold,Italic,Bold-Italic App::PropertyFloat MaxWidth; + virtual QRectF getRect() const; + /** @name methods overide Feature */ //@{ /// recalculate the Feature diff --git a/src/Mod/TechDraw/App/DrawViewClip.h b/src/Mod/TechDraw/App/DrawViewClip.h index d1d91211c..5ead6b682 100644 --- a/src/Mod/TechDraw/App/DrawViewClip.h +++ b/src/Mod/TechDraw/App/DrawViewClip.h @@ -25,7 +25,6 @@ #ifndef _DrawViewClip_h_ #define _DrawViewClip_h_ - #include #include #include @@ -71,6 +70,7 @@ public: std::vector getChildViewNames(); bool isViewInClip(App::DocumentObject* view); + virtual QRectF getRect(void) const { return QRectF(0,0,Width.getValue(),Height.getValue()); } protected: diff --git a/src/Mod/TechDraw/App/DrawViewCollection.cpp b/src/Mod/TechDraw/App/DrawViewCollection.cpp index d97491877..50c57ae00 100644 --- a/src/Mod/TechDraw/App/DrawViewCollection.cpp +++ b/src/Mod/TechDraw/App/DrawViewCollection.cpp @@ -155,3 +155,14 @@ App::DocumentObjectExecReturn *DrawViewCollection::execute(void) return DrawView::execute(); } + + +QRectF DrawViewCollection::getRect() const +{ + QRectF result; + for (auto& v:Views.getValues()) { + TechDraw::DrawView *view = dynamic_cast(v); + result = result.united(view->getRect().translated(view->X.getValue(),view->Y.getValue())); + } + return QRectF(0,0,Scale.getValue() * result.width(),Scale.getValue() * result.height()); +} diff --git a/src/Mod/TechDraw/App/DrawViewCollection.h b/src/Mod/TechDraw/App/DrawViewCollection.h index 00e4a0e33..d54a139ce 100644 --- a/src/Mod/TechDraw/App/DrawViewCollection.h +++ b/src/Mod/TechDraw/App/DrawViewCollection.h @@ -61,6 +61,7 @@ public: virtual const char* getViewProviderName(void) const { return "TechDrawGui::ViewProviderViewCollection"; } + virtual QRectF getRect(void) const; protected: void onChanged(const App::Property* prop); diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index 0304a67e0..41e27b961 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -81,6 +81,7 @@ public: virtual std::string getFormatedValue() const; virtual double getDimValue() const; DrawViewPart* getViewPart() const; + virtual QRectF getRect() const { return QRectF(0,0,1,1);} //pretend dimensions always fit! protected: void onChanged(const App::Property* prop); diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 0d73dfc12..e40ecd980 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -581,6 +581,26 @@ Base::BoundBox3d DrawViewPart::getBoundingBox() const return bbox; } +double DrawViewPart::getBoxX(void) const +{ + Base::BoundBox3d bbx = getBoundingBox(); //bbox is already scaled + return (bbx.MaxX - bbx.MinX); +} + +double DrawViewPart::getBoxY(void) const +{ + Base::BoundBox3d bbx = getBoundingBox(); + return (bbx.MaxY - bbx.MinY); +} + +QRectF DrawViewPart::getRect() const +{ + QRectF result(0.0,0.0,getBoxX(),getBoxY()); //this is from GO and is already scaled + return result; +} + + + //! make a clean wire with sorted, oriented, connected, etc edges TopoDS_Wire DrawViewPart::makeCleanWire(std::vector edges, double tol) { diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index b50e0e015..809e7f057 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -87,6 +87,9 @@ public: TechDrawGeometry::Vertex* getProjVertexByIndex(int idx) const; //get existing geom for vertex idx in projection std::vector getProjFaceByIndex(int idx) const; //get edges for face idx in projection virtual Base::BoundBox3d getBoundingBox() const; + double getBoxX(void) const; + double getBoxY(void) const; + virtual QRectF getRect() const; short mustExecute() const; diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.cpp b/src/Mod/TechDraw/App/DrawViewSymbol.cpp index 898c255d8..ad87ecc2d 100644 --- a/src/Mod/TechDraw/App/DrawViewSymbol.cpp +++ b/src/Mod/TechDraw/App/DrawViewSymbol.cpp @@ -61,7 +61,6 @@ DrawViewSymbol::~DrawViewSymbol() { } -/// get called by the container when a Property was changed void DrawViewSymbol::onChanged(const App::Property* prop) { if (prop == &Symbol) { @@ -90,8 +89,8 @@ App::DocumentObjectExecReturn *DrawViewSymbol::execute(void) std::string svg = Symbol.getValue(); const std::vector& editText = EditableTexts.getValues(); - if (!editText.empty()) { - //TODO: has this ever been run? + if (!editText.empty()) { + //TODO: has this ever been run? boost::regex e1 ("(.*?)"); string::const_iterator begin, end; begin = svg.begin(); @@ -121,6 +120,32 @@ App::DocumentObjectExecReturn *DrawViewSymbol::execute(void) return DrawView::execute(); } +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; + + 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)); +} + + // Python Drawing feature --------------------------------------------------------- namespace App { diff --git a/src/Mod/TechDraw/App/DrawViewSymbol.h b/src/Mod/TechDraw/App/DrawViewSymbol.h index fd7bc7163..665b42fcb 100644 --- a/src/Mod/TechDraw/App/DrawViewSymbol.h +++ b/src/Mod/TechDraw/App/DrawViewSymbol.h @@ -56,6 +56,7 @@ public: virtual const char* getViewProviderName(void) const { return "TechDrawGui::ViewProviderSymbol"; } + virtual QRectF getRect() const; protected: virtual void onChanged(const App::Property* prop);