Generated on Tue Apr 18 10:21:46 2017 for Gecode by doxygen 1.6.3

visualnode.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Guido Tack, 2006
00008  *
00009  *  Last modified:
00010  *     $Date: 2016-04-19 17:19:45 +0200 (Tue, 19 Apr 2016) $ by $Author: schulte $
00011  *     $Revision: 14967 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  * Permission is hereby granted, free of charge, to any person obtaining
00018  * a copy of this software and associated documentation files (the
00019  * "Software"), to deal in the Software without restriction, including
00020  * without limitation the rights to use, copy, modify, merge, publish,
00021  * distribute, sublicense, and/or sell copies of the Software, and to
00022  * permit persons to whom the Software is furnished to do so, subject to
00023  * the following conditions:
00024  *
00025  * The above copyright notice and this permission notice shall be
00026  * included in all copies or substantial portions of the Software.
00027  *
00028  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/gist/visualnode.hh>
00039 
00040 #include <gecode/gist/layoutcursor.hh>
00041 #include <gecode/gist/nodevisitor.hh>
00042 
00043 #include <utility>
00044 
00045 namespace Gecode { namespace Gist {
00046 
00047   Shape* Shape::leaf;
00048   Shape* Shape::hidden;
00049 
00051   class ShapeAllocator {
00052   public:
00054     ShapeAllocator(void) {
00055       Shape::leaf = Shape::allocate(1);
00056       (*Shape::leaf)[0] = Extent(Layout::extent);
00057       Shape::leaf->computeBoundingBox();
00058 
00059       Shape::hidden = Shape::allocate(2);
00060       (*Shape::hidden)[0] = Extent(Layout::extent);
00061       (*Shape::hidden)[1] = Extent(Layout::extent);
00062       Shape::hidden->computeBoundingBox();
00063     }
00064     ~ShapeAllocator(void) {
00065       Shape::deallocate(Shape::leaf);
00066       Shape::deallocate(Shape::hidden);
00067     }
00068   };
00069 
00071   ShapeAllocator shapeAllocator;
00072 
00073   VisualNode::VisualNode(int p)
00074   : SpaceNode(p)
00075   , offset(0)
00076   {
00077     shape = NULL;
00078     setDirty(true);
00079     setChildrenLayoutDone(false);
00080     setHidden(false);
00081     setMarked(false);
00082     setOnPath(false);
00083     setBookmarked(false);
00084   }
00085 
00086   VisualNode::VisualNode(Space* root)
00087   : SpaceNode(root)
00088   , offset(0)
00089   {
00090     shape = NULL;
00091     setDirty(true);
00092     setChildrenLayoutDone(false);
00093     setHidden(false);
00094     setMarked(false);
00095     setOnPath(false);
00096     setBookmarked(false);
00097   }
00098 
00099   void
00100   VisualNode::dispose(void) {
00101     Shape::deallocate(shape);
00102     SpaceNode::dispose();
00103   }
00104 
00105   void
00106   VisualNode::dirtyUp(const NodeAllocator& na) {
00107     VisualNode* cur = this;
00108     while (!cur->isDirty()) {
00109       cur->setDirty(true);
00110       if (! cur->isRoot()) {
00111         cur = cur->getParent(na);
00112       }
00113     }
00114   }
00115 
00116   void
00117   VisualNode::layout(const NodeAllocator& na) {
00118     LayoutCursor l(this,na);
00119     PostorderNodeVisitor<LayoutCursor>(l).run();
00120     // int nodesLayouted = 1;
00121     // clock_t t0 = clock();
00122     // while (p.next()) {}
00123     // while (p.next()) { nodesLayouted++; }
00124     // double t = (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC) * 1000.0;
00125     // double nps = static_cast<double>(nodesLayouted) /
00126     //   (static_cast<double>(clock()-t0) / CLOCKS_PER_SEC);
00127     // std::cout << "Layout done. " << nodesLayouted << " nodes in "
00128     //   << t << " ms. " << nps << " nodes/s." << std::endl;
00129   }
00130 
00131   void VisualNode::pathUp(const NodeAllocator& na) {
00132     VisualNode* cur = this;
00133     while (cur) {
00134       cur->setOnPath(true);
00135       cur = cur->getParent(na);
00136     }
00137   }
00138 
00139   void VisualNode::unPathUp(const NodeAllocator& na) {
00140     VisualNode* cur = this;
00141     while (!cur->isRoot()) {
00142       cur->setOnPath(false);
00143       cur = cur->getParent(na);
00144     }
00145   }
00146 
00147   int
00148   VisualNode::getPathAlternative(const NodeAllocator& na) {
00149     for (int i=getNumberOfChildren(); i--;) {
00150       if (getChild(na,i)->isOnPath())
00151         return i;
00152     }
00153     return -1;
00154   }
00155 
00156   void
00157   VisualNode::toggleHidden(const NodeAllocator& na) {
00158     setHidden(!isHidden());
00159     dirtyUp(na);
00160   }
00161 
00162   void
00163   VisualNode::hideFailed(const NodeAllocator& na, bool onlyDirty) {
00164     HideFailedCursor c(this,na,onlyDirty);
00165     PreorderNodeVisitor<HideFailedCursor>(c).run();
00166     dirtyUp(na);
00167   }
00168 
00169   void
00170   VisualNode::labelBranches(NodeAllocator& na,
00171                             BestNode* curBest, int c_d, int a_d) {
00172     bool clear = na.hasLabel(this);
00173     BranchLabelCursor c(this,curBest,c_d,a_d,clear,na);
00174     PreorderNodeVisitor<BranchLabelCursor>(c).run();
00175     dirtyUp(na);
00176   }
00177 
00178   void
00179   VisualNode::labelPath(NodeAllocator& na,
00180                         BestNode* curBest, int c_d, int a_d) {
00181     if (na.hasLabel(this)) {
00182       // clear labels on path to root
00183       VisualNode* p = this;
00184       while (p) {
00185         na.clearLabel(p);
00186         p = p->getParent(na);
00187       }
00188     } else {
00189       // set labels on path to root
00190       std::vector<std::pair<VisualNode*,int> > path;
00191       VisualNode* p = this;
00192       while (p) {
00193         path.push_back(std::pair<VisualNode*,int>(p,p->getAlternative(na)));
00194         p = p->getParent(na);
00195       }
00196       while (!path.empty()) {
00197         std::pair<VisualNode*,int> cur = path.back(); path.pop_back();
00198         if (p) {
00199           std::string l =
00200             cur.first->getBranchLabel(na,p,p->getChoice(),
00201                                       curBest,c_d,a_d,cur.second);
00202           na.setLabel(cur.first,QString(l.c_str()));
00203         }
00204         p = cur.first;
00205       }
00206     }
00207     dirtyUp(na);
00208   }
00209 
00210   void
00211   VisualNode::unhideAll(const NodeAllocator& na) {
00212     UnhideAllCursor c(this,na);
00213     PreorderNodeVisitor<UnhideAllCursor>(c).run();
00214     dirtyUp(na);
00215   }
00216 
00217   void
00218   VisualNode::toggleStop(const NodeAllocator& na) {
00219     if (getStatus() == STOP)
00220       setStatus(UNSTOP);
00221     else if (getStatus() == UNSTOP)
00222       setStatus(STOP);
00223     dirtyUp(na);
00224   }
00225 
00226   void
00227   VisualNode::unstopAll(const NodeAllocator& na) {
00228     UnstopAllCursor c(this,na);
00229     PreorderNodeVisitor<UnstopAllCursor>(c).run();
00230     dirtyUp(na);
00231   }
00232 
00233   void
00234   VisualNode::changedStatus(const NodeAllocator& na) { dirtyUp(na); }
00235 
00236   bool
00237   VisualNode::containsCoordinateAtDepth(int x, int depth) {
00238     BoundingBox box = getShape()->getBoundingBox();
00239     if (x < box.left ||
00240         x > box.right ||
00241         depth >= getShape()->depth()) {
00242       return false;
00243     }
00244     Extent theExtent;
00245     if (getShape()->getExtentAtDepth(depth, theExtent)) {
00246       return (theExtent.l <= x && x <= theExtent.r);
00247     } else {
00248       return false;
00249     }
00250   }
00251 
00252   VisualNode*
00253   VisualNode::findNode(const NodeAllocator& na, int x, int y) {
00254     VisualNode* cur = this;
00255     int depth = y / Layout::dist_y;
00256 
00257     while (depth > 0 && cur != NULL) {
00258       if (cur->isHidden()) {
00259         break;
00260       }
00261       VisualNode* oldCur = cur;
00262       cur = NULL;
00263       for (unsigned int i=0; i<oldCur->getNumberOfChildren(); i++) {
00264         VisualNode* nextChild = oldCur->getChild(na,i);
00265         int newX = x - nextChild->getOffset();
00266         if (nextChild->containsCoordinateAtDepth(newX, depth - 1)) {
00267           cur = nextChild;
00268           x = newX;
00269           break;
00270         }
00271       }
00272       depth--;
00273       y -= Layout::dist_y;
00274     }
00275 
00276     if(cur == this && !cur->containsCoordinateAtDepth(x, 0)) {
00277       return NULL;
00278     }
00279     return cur;
00280   }
00281 
00282   std::string
00283   VisualNode::toolTip(NodeAllocator&, BestNode*, int, int) {
00284     return "";
00285   }
00286 
00287   std::string
00288   VisualNode::getBranchLabel(NodeAllocator& na,
00289                              VisualNode* p, const Choice* c,
00290                              BestNode* curBest, int c_d, int a_d, int alt) {
00291     std::ostringstream oss;
00292     p->acquireSpace(na,curBest,c_d,a_d);
00293     p->getWorkingSpace()->print(*c,alt,oss);
00294     return oss.str();
00295   }
00296 
00297 
00299   class Layouter {
00300   public:
00302     template<class S1, class S2>
00303     static int getAlpha(const S1& shape1, int depth1,
00304                         const S2& shape2, int depth2);
00306     template<class S1, class S2>
00307     static void merge(Extent* result,
00308                       const S1& shape1, int depth1,
00309                       const S2& shape2, int depth2, int alpha);
00310   };
00311 
00312   template<class S1, class S2>
00313   int
00314   Layouter::getAlpha(const S1& shape1, int depth1,
00315                      const S2& shape2, int depth2) {
00316     int alpha = Layout::minimalSeparation;
00317     int extentR = 0;
00318     int extentL = 0;
00319     for (int i=0; i<depth1 && i<depth2; i++) {
00320       extentR += shape1[i].r;
00321       extentL += shape2[i].l;
00322       alpha = std::max(alpha, extentR - extentL + Layout::minimalSeparation);
00323     }
00324     return alpha;
00325   }
00326 
00327   template<class S1, class S2>
00328   void
00329   Layouter::merge(Extent* result,
00330                   const S1& shape1, int depth1,
00331                   const S2& shape2, int depth2, int alpha) {
00332     if (depth1 == 0) {
00333       for (int i=depth2; i--;)
00334         result[i] = shape2[i];
00335     } else if (depth2 == 0) {
00336       for (int i=depth1; i--;)
00337         result[i] = shape1[i];
00338     } else {
00339       // Extend the topmost right extent by alpha.  This, in effect,
00340       // moves the second shape to the right by alpha units.
00341       int topmostL = shape1[0].l;
00342       int topmostR = shape2[0].r;
00343       int backoffTo1 =
00344         shape1[0].r - alpha - shape2[0].r;
00345       int backoffTo2 =
00346         shape2[0].l + alpha - shape1[0].l;
00347 
00348       result[0] = Extent(topmostL, topmostR+alpha);
00349 
00350       // Now, since extents are given in relative units, in order to
00351       // compute the extents of the merged shape, we can just collect the
00352       // extents of shape1 and shape2, until one of the shapes ends.  If
00353       // this happens, we need to "back-off" to the axis of the deeper
00354       // shape in order to properly determine the remaining extents.
00355       int i=1;
00356       for (; i<depth1 && i<depth2; i++) {
00357         Extent currentExtent1 = shape1[i];
00358         Extent currentExtent2 = shape2[i];
00359         int newExtentL = currentExtent1.l;
00360         int newExtentR = currentExtent2.r;
00361         result[i] = Extent(newExtentL, newExtentR);
00362         backoffTo1 += currentExtent1.r - currentExtent2.r;
00363         backoffTo2 += currentExtent2.l - currentExtent1.l;
00364       }
00365 
00366       // If shape1 is deeper than shape2, back off to the axis of shape1,
00367       // and process the remaining extents of shape1.
00368       if (i<depth1) {
00369         Extent currentExtent1 = shape1[i];
00370         int newExtentL = currentExtent1.l;
00371         int newExtentR = currentExtent1.r;
00372         result[i] = Extent(newExtentL, newExtentR+backoffTo1);
00373         ++i;
00374         for (; i<depth1; i++) {
00375           result[i] = shape1[i];
00376         }
00377       }
00378 
00379       // Vice versa, if shape2 is deeper than shape1, back off to the
00380       // axis of shape2, and process the remaining extents of shape2.
00381       if (i<depth2) {
00382         Extent currentExtent2 = shape2[i];
00383         int newExtentL = currentExtent2.l;
00384         int newExtentR = currentExtent2.r;
00385         result[i] = Extent(newExtentL+backoffTo2, newExtentR);
00386         ++i;
00387         for (; i<depth2; i++) {
00388           result[i] = shape2[i];
00389         }
00390       }
00391     }
00392   }
00393 
00394   void
00395   VisualNode::setShape(Shape* s) {
00396     if (shape != s)
00397       Shape::deallocate(shape);
00398     shape = s;
00399     shape->computeBoundingBox();
00400   }
00401 
00402   void
00403   VisualNode::computeShape(const NodeAllocator& na, VisualNode* root) {
00404     int numberOfShapes = getNumberOfChildren();
00405     Extent extent;
00406     if (na.hasLabel(this)) {
00407       int ll = na.getLabel(this).length();
00408       ll *= 7;
00409       VisualNode* p = getParent(na);
00410       int alt = 0;
00411       int n_alt = 1;
00412       if (p) {
00413         alt = getAlternative(na);
00414         n_alt = p->getNumberOfChildren();
00415       }
00416       extent = Extent(Layout::extent);
00417       if (alt==0 && n_alt > 1) {
00418         extent.l = std::min(extent.l, -ll);
00419       } else if (alt==n_alt-1 && n_alt > 1) {
00420         extent.r = std::max(extent.r, ll);
00421       } else {
00422         extent.l = std::min(extent.l, -ll);
00423         extent.r = std::max(extent.r, ll);
00424       }
00425     } else {
00426       if (numberOfShapes==0) {
00427         setShape(Shape::leaf);
00428         return;
00429       } else {
00430         extent = Extent(Layout::extent);
00431       }
00432     }
00433 
00434     int maxDepth = 0;
00435     for (int i = numberOfShapes; i--;)
00436       maxDepth = std::max(maxDepth, getChild(na,i)->getShape()->depth());
00437     Shape* mergedShape;
00438     if (getShape() && getShape() != Shape::leaf &&
00439         getShape()->depth() >= maxDepth+1) {
00440       mergedShape = getShape();
00441       mergedShape->setDepth(maxDepth+1);
00442     } else {
00443       mergedShape = Shape::allocate(maxDepth+1);
00444     }
00445     (*mergedShape)[0] = extent;
00446     if (numberOfShapes < 1) {
00447       setShape(mergedShape);
00448     } else if (numberOfShapes == 1) {
00449       getChild(na,0)->setOffset(0);
00450       const Shape* childShape = getChild(na,0)->getShape();
00451       for (int i=childShape->depth(); i--;)
00452         (*mergedShape)[i+1] = (*childShape)[i];
00453       (*mergedShape)[1].extend(- extent.l, - extent.r);
00454       setShape(mergedShape);
00455     } else {
00456       // alpha stores the necessary distances between the
00457       // axes of the shapes in the list: alpha[i].first gives the distance
00458       // between shape[i] and shape[i-1], when shape[i-1] and shape[i]
00459       // are merged left-to-right; alpha[i].second gives the distance between
00460       // shape[i] and shape[i+1], when shape[i] and shape[i+1] are merged
00461       // right-to-left.
00462       assert(root->copy != NULL);
00463       Region r(*root->copy);
00464       std::pair<int,int>* alpha =
00465         r.alloc<std::pair<int,int> >(numberOfShapes);
00466 
00467       // distance between the leftmost and the rightmost axis in the list
00468       int width = 0;
00469 
00470       Extent* currentShapeL = r.alloc<Extent>(maxDepth);
00471       int ldepth = getChild(na,0)->getShape()->depth();
00472       for (int i=ldepth; i--;)
00473         currentShapeL[i] = (*getChild(na,0)->getShape())[i];
00474 
00475       // After merging, we can pick the result of either merging left or right
00476       // Here we chose the result of merging right
00477       Shape* rShape = getChild(na,numberOfShapes-1)->getShape();
00478       int rdepth = rShape->depth();
00479       for (int i=rdepth; i--;)
00480         (*mergedShape)[i+1] = (*rShape)[i];
00481       Extent* currentShapeR = &(*mergedShape)[1];
00482 
00483       for (int i = 1; i < numberOfShapes; i++) {
00484         // Merge left-to-right.  Note that due to the asymmetry of the
00485         // merge operation, nextAlphaL is the distance between the
00486         // *leftmost* axis in the shape list, and the axis of
00487         // nextShapeL; what we are really interested in is the distance
00488         // between the *previous* axis and the axis of nextShapeL.
00489         // This explains the correction.
00490 
00491         Shape* nextShapeL = getChild(na,i)->getShape();
00492         int nextAlphaL =
00493           Layouter::getAlpha<Extent*,Shape>(&currentShapeL[0], ldepth,
00494                              *nextShapeL, nextShapeL->depth());
00495         Layouter::merge<Extent*,Shape>(&currentShapeL[0],
00496                                        &currentShapeL[0], ldepth,
00497                                        *nextShapeL, nextShapeL->depth(),
00498                                        nextAlphaL);
00499         ldepth = std::max(ldepth,nextShapeL->depth());
00500         alpha[i].first = nextAlphaL - width;
00501         width = nextAlphaL;
00502 
00503         // Merge right-to-left.  Here, a correction of nextAlphaR is
00504         // not required.
00505         Shape* nextShapeR = getChild(na,numberOfShapes-1-i)->getShape();
00506         int nextAlphaR =
00507           Layouter::getAlpha<Shape,Extent*>(*nextShapeR, nextShapeR->depth(),
00508                                &currentShapeR[0], rdepth);
00509         Layouter::merge<Shape,Extent*>(&currentShapeR[0],
00510                                        *nextShapeR, nextShapeR->depth(),
00511                                        &currentShapeR[0], rdepth,
00512                                        nextAlphaR);
00513         rdepth = std::max(rdepth,nextShapeR->depth());
00514         alpha[numberOfShapes - i].second = nextAlphaR;
00515       }
00516 
00517       // The merged shape has to be adjusted to its topmost extent
00518       (*mergedShape)[1].extend(- extent.l, - extent.r);
00519 
00520       // After the loop, the merged shape has the same axis as the
00521       // leftmost shape in the list.  What we want is to move the axis
00522       // such that it is the center of the axis of the leftmost shape in
00523       // the list and the axis of the rightmost shape.
00524       int halfWidth = false ? 0 : width / 2;
00525       (*mergedShape)[1].move(- halfWidth);
00526 
00527       // Finally, for the offset lists.  Now that the axis of the merged
00528       // shape is at the center of the two extreme axes, the first shape
00529       // needs to be offset by -halfWidth units with respect to the new
00530       // axis.  As for the offsets for the other shapes, we take the
00531       // median of the alphaL and alphaR values, as suggested in
00532       // Kennedy's paper.
00533       int offset = - halfWidth;
00534       getChild(na,0)->setOffset(offset);
00535       for (int i = 1; i < numberOfShapes; i++) {
00536         offset += (alpha[i].first + alpha[i].second) / 2;
00537         getChild(na,i)->setOffset(offset);
00538       }
00539       setShape(mergedShape);
00540     }
00541   }
00542 
00543 }}
00544 
00545 // STATISTICS: gist-any