[TD]fix autoscale for DPG

This commit is contained in:
wandererfan
2020-02-11 06:50:42 -05:00
committed by WandererFan
parent b4943c1f08
commit 3a42205cb4
7 changed files with 146 additions and 111 deletions

View File

@@ -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<App::DocumentObject*> 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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 <double, std::milli> (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;
}

View File

@@ -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();