drawingcursor.cpp
Go to the documentation of this file.
/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <tack@gecode.org>
*
* Copyright:
* Guido Tack, 2006
*
* This file is part of Gecode, the generic constraint
* development environment:
* http://www.gecode.org
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <gecode/gist/drawingcursor.hh>
namespace Gecode { namespace Gist {
const QColor DrawingCursor::red(218, 37, 29);
const QColor DrawingCursor::green(11, 118, 70);
const QColor DrawingCursor::blue(0, 92, 161);
const QColor DrawingCursor::orange(235, 137, 27);
const QColor DrawingCursor::white(255,255,255);
const QColor DrawingCursor::lightRed(218, 37, 29, 120);
const QColor DrawingCursor::lightGreen(11, 118, 70, 120);
const QColor DrawingCursor::lightBlue(0, 92, 161, 120);
const double nodeWidth = 20.0;
const double halfNodeWidth = nodeWidth / 2.0;
const double failedWidth = 14.0;
const double halfFailedWidth = failedWidth / 2.0;
const double quarterFailedWidthF = failedWidth / 4.0;
const double shadowOffset = 3.0;
const double hiddenDepth =
static_cast<double>(Layout::dist_y) + failedWidth;
DrawingCursor::DrawingCursor(VisualNode* root,
const VisualNode::NodeAllocator& na,
BestNode* curBest0,
QPainter& painter0,
const QRect& clippingRect0, bool showCopies)
: NodeCursor<VisualNode>(root,na), painter(painter0),
clippingRect(clippingRect0), curBest(curBest0),
x(0.0), y(0.0), copies(showCopies) {
QPen pen = painter.pen();
pen.setWidth(1);
painter.setPen(pen);
}
void
DrawingCursor::processCurrentNode(void) {
Gist::VisualNode* n = node();
double parentX = x - static_cast<double>(n->getOffset());
double parentY = y - static_cast<double>(Layout::dist_y) + nodeWidth;
if (!n->isRoot() &&
(n->getParent(na)->getStatus() == STOP ||
n->getParent(na)->getStatus() == UNSTOP) )
parentY -= (nodeWidth-failedWidth)/2;
double myx = x;
double myy = y;
if (n->getStatus() == STOP || n->getStatus() == UNSTOP)
myy += (nodeWidth-failedWidth)/2;
if (n != startNode()) {
if (n->isOnPath())
painter.setPen(Qt::red);
else
painter.setPen(Qt::black);
// Here we use drawPath instead of drawLine in order to
// workaround a strange redraw artefact on Windows
QPainterPath path;
path.moveTo(myx,myy);
path.lineTo(parentX,parentY);
painter.drawPath(path);
QFontMetrics fm = painter.fontMetrics();
QString label = na.getLabel(n);
int alt = n->getAlternative(na);
int n_alt = n->getParent(na)->getNumberOfChildren();
int tw = fm.width(label);
int lx;
if (alt==0 && n_alt > 1) {
lx = myx-tw-4;
} else if (alt==n_alt-1 && n_alt > 1) {
lx = myx+4;
} else {
lx = myx-tw/2;
}
painter.drawText(QPointF(lx,myy-2),label);
}
// draw shadow
if (n->isMarked()) {
painter.setBrush(Qt::gray);
painter.setPen(Qt::NoPen);
if (n->isHidden()) {
QPointF points[3] = {QPointF(myx+shadowOffset,myy+shadowOffset),
QPointF(myx+nodeWidth+shadowOffset,
myy+hiddenDepth+shadowOffset),
QPointF(myx-nodeWidth+shadowOffset,
myy+hiddenDepth+shadowOffset),
};
painter.drawConvexPolygon(points, 3);
} else {
switch (n->getStatus()) {
case Gist::SOLVED:
{
QPointF points[4] = {QPointF(myx+shadowOffset,myy+shadowOffset),
QPointF(myx+halfNodeWidth+shadowOffset,
myy+halfNodeWidth+shadowOffset),
QPointF(myx+shadowOffset,
myy+nodeWidth+shadowOffset),
QPointF(myx-halfNodeWidth+shadowOffset,
myy+halfNodeWidth+shadowOffset)
};
painter.drawConvexPolygon(points, 4);
}
break;
case Gist::FAILED:
painter.drawRect(myx-halfFailedWidth+shadowOffset,
myy+shadowOffset, failedWidth, failedWidth);
break;
case Gist::UNSTOP:
case Gist::STOP:
{
QPointF points[8] = {QPointF(myx+shadowOffset-quarterFailedWidthF,
myy+shadowOffset),
QPointF(myx+shadowOffset+quarterFailedWidthF,
myy+shadowOffset),
QPointF(myx+shadowOffset+halfFailedWidth,
myy+shadowOffset
+quarterFailedWidthF),
QPointF(myx+shadowOffset+halfFailedWidth,
myy+shadowOffset+halfFailedWidth+
quarterFailedWidthF),
QPointF(myx+shadowOffset+quarterFailedWidthF,
myy+shadowOffset+failedWidth),
QPointF(myx+shadowOffset-quarterFailedWidthF,
myy+shadowOffset+failedWidth),
QPointF(myx+shadowOffset-halfFailedWidth,
myy+shadowOffset+halfFailedWidth+
quarterFailedWidthF),
QPointF(myx+shadowOffset-halfFailedWidth,
myy+shadowOffset
+quarterFailedWidthF),
};
painter.drawConvexPolygon(points, 8);
}
break;
case Gist::BRANCH:
painter.drawEllipse(myx-halfNodeWidth+shadowOffset,
myy+shadowOffset, nodeWidth, nodeWidth);
break;
case Gist::UNDETERMINED:
painter.drawEllipse(myx-halfNodeWidth+shadowOffset,
myy+shadowOffset, nodeWidth, nodeWidth);
break;
}
}
}
painter.setPen(Qt::SolidLine);
if (n->isHidden()) {
if (n->hasOpenChildren()) {
QLinearGradient gradient(myx-nodeWidth,myy,
myx+nodeWidth*1.3,myy+hiddenDepth*1.3);
if (n->hasSolvedChildren()) {
gradient.setColorAt(0, white);
gradient.setColorAt(1, green);
} else if (n->hasFailedChildren()) {
gradient.setColorAt(0, white);
gradient.setColorAt(1, red);
} else {
gradient.setColorAt(0, white);
gradient.setColorAt(1, QColor(0,0,0));
}
painter.setBrush(gradient);
} else {
if (n->hasSolvedChildren())
painter.setBrush(QBrush(green));
else
painter.setBrush(QBrush(red));
}
QPointF points[3] = {QPointF(myx,myy),
QPointF(myx+nodeWidth,myy+hiddenDepth),
QPointF(myx-nodeWidth,myy+hiddenDepth),
};
painter.drawConvexPolygon(points, 3);
} else {
switch (n->getStatus()) {
case Gist::SOLVED:
{
if (n->isCurrentBest(curBest)) {
painter.setBrush(QBrush(orange));
} else {
painter.setBrush(QBrush(green));
}
QPointF points[4] = {QPointF(myx,myy),
QPointF(myx+halfNodeWidth,myy+halfNodeWidth),
QPointF(myx,myy+nodeWidth),
QPointF(myx-halfNodeWidth,myy+halfNodeWidth)
};
painter.drawConvexPolygon(points, 4);
}
break;
case Gist::FAILED:
painter.setBrush(QBrush(red));
painter.drawRect(myx-halfFailedWidth, myy, failedWidth, failedWidth);
break;
case Gist::UNSTOP:
case Gist::STOP:
{
painter.setBrush(n->getStatus() == STOP ?
QBrush(red) : QBrush(green));
QPointF points[8] = {QPointF(myx-quarterFailedWidthF,myy),
QPointF(myx+quarterFailedWidthF,myy),
QPointF(myx+halfFailedWidth,
myy+quarterFailedWidthF),
QPointF(myx+halfFailedWidth,
myy+halfFailedWidth+
quarterFailedWidthF),
QPointF(myx+quarterFailedWidthF,
myy+failedWidth),
QPointF(myx-quarterFailedWidthF,
myy+failedWidth),
QPointF(myx-halfFailedWidth,
myy+halfFailedWidth+
quarterFailedWidthF),
QPointF(myx-halfFailedWidth,
myy+quarterFailedWidthF),
};
painter.drawConvexPolygon(points, 8);
}
break;
case Gist::BRANCH:
painter.setBrush(n->childrenLayoutIsDone() ? QBrush(blue) :
QBrush(white));
painter.drawEllipse(myx-halfNodeWidth, myy, nodeWidth, nodeWidth);
break;
case Gist::UNDETERMINED:
painter.setBrush(Qt::white);
painter.drawEllipse(myx-halfNodeWidth, myy, nodeWidth, nodeWidth);
break;
}
}
if (copies && (n->hasCopy() && !n->hasWorkingSpace())) {
painter.setBrush(Qt::darkRed);
painter.drawEllipse(myx, myy, 10.0, 10.0);
}
if (copies && n->hasWorkingSpace()) {
painter.setBrush(Qt::darkYellow);
painter.drawEllipse(myx, myy + 10.0, 10.0, 10.0);
}
if (n->isBookmarked()) {
painter.setBrush(Qt::black);
painter.drawEllipse(myx-10-0, myy, 10.0, 10.0);
}
}
}}
// STATISTICS: gist-any
Gecode::Gist::BestNode
Static reference to the currently best space.
Definition spacenode.hh:80
Gecode::Gist::DrawingCursor::red
static const QColor red
The color for failed nodes.
Definition drawingcursor.hh:61
Gecode::Gist::DrawingCursor::processCurrentNode
void processCurrentNode(void)
Draw the node.
Definition drawingcursor.cpp:79
Gecode::Gist::DrawingCursor::blue
static const QColor blue
The color for choice nodes.
Definition drawingcursor.hh:65
Gecode::Gist::DrawingCursor::green
static const QColor green
The color for solved nodes.
Definition drawingcursor.hh:63
Gecode::Gist::DrawingCursor::white
static const QColor white
White color.
Definition drawingcursor.hh:69
Gecode::Gist::DrawingCursor::lightBlue
static const QColor lightBlue
The color for expanded choice nodes.
Definition drawingcursor.hh:76
Gecode::Gist::DrawingCursor::DrawingCursor
DrawingCursor(VisualNode *root, const VisualNode::NodeAllocator &na, BestNode *curBest0, QPainter &painter0, const QRect &clippingRect0, bool showCopies)
Constructor.
Definition drawingcursor.cpp:65
Gecode::Gist::DrawingCursor::lightRed
static const QColor lightRed
The color for expanded failed nodes.
Definition drawingcursor.hh:72
Gecode::Gist::DrawingCursor::lightGreen
static const QColor lightGreen
The color for expanded solved nodes.
Definition drawingcursor.hh:74
Gecode::Gist::DrawingCursor::orange
static const QColor orange
The color for the best solution.
Definition drawingcursor.hh:67
Gecode::Gist::Layout::dist_y
static const int dist_y
Definition visualnode.hh:46
Gecode::Gist::NodeCursor< VisualNode >::na
const VisualNode::NodeAllocator & na
Definition nodecursor.hh:53
Gecode::Gist::NodeCursor< VisualNode >::NodeCursor
NodeCursor(VisualNode *theNode, const typename VisualNode::NodeAllocator &na)
Definition nodecursor.hpp:38
Gecode::Gist::NodeCursor< VisualNode >::node
void node(VisualNode *n)
Definition nodecursor.hpp:62
Gecode::Gist::NodeCursor< VisualNode >::startNode
VisualNode * startNode(void)
Definition nodecursor.hpp:58
Gecode::Gist::Node::NodeAllocator
NodeAllocatorBase< VisualNode > NodeAllocator
Definition node.hh:143
Gecode::Gist::Node::getParent
int getParent(void) const
Return the parent.
Definition node.hpp:182
Gecode::Gist::Node::isRoot
bool isRoot(void) const
Check if this node is the root of a tree.
Definition node.hpp:211
Gecode::Gist::SpaceNode::hasCopy
bool hasCopy(void)
Return whether the node has a copy.
Definition spacenode.hpp:159
Gecode::Gist::SpaceNode::hasWorkingSpace
bool hasWorkingSpace(void)
Return whether the node has a working space.
Definition spacenode.hpp:164
Gecode::Gist::SpaceNode::isCurrentBest
bool isCurrentBest(BestNode *curBest)
Return whether this node is the currently best solution.
Definition spacenode.hpp:133
Gecode::Gist::SpaceNode::hasFailedChildren
bool hasFailedChildren(void)
Return whether the subtree of this node has any failed children.
Definition spacenode.hpp:144
Gecode::Gist::SpaceNode::hasSolvedChildren
bool hasSolvedChildren(void)
Return whether the subtree of this node has any solved children.
Definition spacenode.hpp:149
Gecode::Gist::SpaceNode::getAlternative
int getAlternative(const NodeAllocator &na) const
Return alternative number of this node.
Definition spacenode.hpp:169
Gecode::Gist::SpaceNode::getStatus
NodeStatus getStatus(void) const
Return current status of the node.
Definition spacenode.hpp:71
Gecode::Gist::SpaceNode::hasOpenChildren
bool hasOpenChildren(void)
Return whether the subtree of this node has any open children.
Definition spacenode.hpp:154
Gecode::Gist::VisualNode
Node class that supports visual layout
Definition visualnode.hh:125
Gecode::Gist::VisualNode::getOffset
int getOffset(void)
Return offset off this node from its parent.
Definition visualnode.hpp:147
Gecode::Gist::VisualNode::isBookmarked
bool isBookmarked(void)
Return whether node is bookmarked.
Definition visualnode.hpp:183
Gecode::Gist::VisualNode::isHidden
bool isHidden(void)
Return if node is hidden.
Definition visualnode.hpp:129
Gecode::Gist::VisualNode::isMarked
bool isMarked(void)
Return whether node is marked.
Definition visualnode.hpp:173
Gecode::Gist::VisualNode::childrenLayoutIsDone
bool childrenLayoutIsDone(void)
Return whether the layout of the node's children has been completed.
Definition visualnode.hpp:163
Gecode::Gist::VisualNode::isOnPath
bool isOnPath(void)
Return whether node is on the path.
Definition visualnode.hpp:193
drawingcursor.hh
Gecode::Gist
The Gecode Interactive Search Tool.
Gecode::Gist::shadowOffset
const double shadowOffset
Definition drawingcursor.cpp:61
Gecode::Gist::failedWidth
const double failedWidth
Definition drawingcursor.cpp:58
Gecode::Gist::halfNodeWidth
const double halfNodeWidth
Definition drawingcursor.cpp:57
Gecode::Gist::UNDETERMINED
@ UNDETERMINED
Node that has not been explored yet.
Definition spacenode.hh:48
Gecode::Gist::UNSTOP
@ UNSTOP
Node representing ignored stop point.
Definition spacenode.hh:50
Gecode::Gist::FAILED
@ FAILED
Node representing failure.
Definition spacenode.hh:46
Gecode::Gist::STOP
@ STOP
Node representing stop point.
Definition spacenode.hh:49
Gecode::Gist::SOLVED
@ SOLVED
Node representing a solution.
Definition spacenode.hh:45
Gecode::Gist::BRANCH
@ BRANCH
Node representing a branch.
Definition spacenode.hh:47
Gecode::Gist::hiddenDepth
const double hiddenDepth
Definition drawingcursor.cpp:62
Gecode::Gist::nodeWidth
const double nodeWidth
Definition drawingcursor.cpp:56
Gecode::Gist::halfFailedWidth
const double halfFailedWidth
Definition drawingcursor.cpp:59
Gecode::Gist::quarterFailedWidthF
const double quarterFailedWidthF
Definition drawingcursor.cpp:60
Gecode
Gecode toplevel namespace
Gecode::path
void path(Home home, const IntVarArgs &x, IntVar s, IntVar e, IntPropLevel ipl=IPL_DEF)
Post propagator such that x forms a Hamiltonian path.
Definition circuit.cpp:169