//---------------------------------------------------------------------------- // $Id: TransferItem.cpp,v 1.8 2010/05/03 22:03:42 lynn Exp $ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // class // // A TransferItem is a derived QCanvasItem that represents a supply between two // simulation objects as a line on the Workspace canvas. // //---------------------------------------------------------------------------- #ifndef TransferItemINCLUDED #include "TransferItem.hpp" #endif #include #include #include #include #include #include #include #include //Added by qt3to4: #include #include #include #ifndef LinkDisplayInfoINCLUDED #include "LinkDisplayInfo.hpp" #endif #ifndef RwQtSettingsINCLUDED #include "RwQtSettings.hpp" #endif #ifndef RwQtUtilsIncluded #include "RwQtUtils.hpp" #endif // End of Qt includes #undef slots #ifndef rwErrorINCLUDED #include "rwError.hpp" #endif #ifndef SimWorkspaceINCLUDED #include "SimWS.hpp" #endif #ifndef SimObjINCLUDED #include "SimObj.hpp" #endif #ifndef SystemINCLUDED #include "System.hpp" #endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifdef CW_MSVC #define rint(f) ((int)(f+0.5)) #endif //---------------------------------------------------------------------------- // public // // Constructor // //---------------------------------------------------------------------------- TransferItem::TransferItem(Supply *supply, AccountItem *suppAcct, AccountItem *destAcct, Q3Canvas *canvas) : Q3CanvasRectangle ( canvas ), _supply(supply), _supplyAccount(suppAcct), _destAccount(destAcct), _lineWidth(1), _ARC_HEIGHT(125), _ARC_WIDTH(25), _points(4), _arrowhead(new Q3CanvasPolygon(canvas)), _ARROW_WIDTH(4), _ARROW_LENGTH(12) { _destAccount->addSupply(this); _supplyAccount->addSupply(this); QPen pen(Qt::black); pen.setWidth(_lineWidth); setPen(pen); setZ(1.25); _arrowhead->show(); _arrowhead->setPen(pen); _arrowhead->setBrush(QBrush(Qt::black)); update(); } //---------------------------------------------------------------------------- // public // // DestrucdestAcctr // //---------------------------------------------------------------------------- TransferItem::~TransferItem() { _destAccount->removeSupply(this); _supplyAccount->removeSupply(this); delete _arrowhead; _arrowhead = NULL; } //---------------------------------------------------------------------------- // protected // // Draw the line representing the supply. // //---------------------------------------------------------------------------- void TransferItem::drawShape(QPainter &painter) { // TBD -- in Qt 4.0 we'll be able to provide anti-aliasing here QMatrix wm = painter.worldMatrix(); scale(wm.m11(), wm.m12()); painter.drawCubicBezier(_points); } //---------------------------------------------------------------------------- // public // // Update the position of the supply. This member is used to respond to // changes in the position of the simulation objects that this item supplys. // //---------------------------------------------------------------------------- void TransferItem::update() { int sx = _supplyAccount->boundingRect().center().x(); int dx = _destAccount->boundingRect().center().x(); int y = _destAccount->boundingRect().top(); if (sx < dx) { _points.setPoint(0, dx, y); _points.setPoint(1, dx - _ARC_WIDTH, y - _ARC_HEIGHT); _points.setPoint(2, sx + _ARC_WIDTH, y - _ARC_HEIGHT); _points.setPoint(3, sx, y); } else { _points.setPoint(0, dx, y); _points.setPoint(1, dx + _ARC_WIDTH, y - _ARC_HEIGHT); _points.setPoint(2, sx - _ARC_WIDTH, y - _ARC_HEIGHT); _points.setPoint(3, sx, y); } move(MIN(dx,sx), _supplyAccount->boundingRect().top() - _ARC_HEIGHT); setSize(MAX(fabs(_destAccount->x() - _supplyAccount->x()), 2 * _ARC_WIDTH), _ARC_HEIGHT); canvas()->setChanged(boundingRect()); // // Update arrowhead // Q3PointArray points(3); const QPoint direction = _points[0] - _points[1]; const int directX (direction.x()); const int directY (direction.y()); double mag = sqrt (double ((directX * directX) + (directY * directY))); if (mag == 0.0) { mag = 1.0; } double nx = directX / mag; double ny = directY / mag; double px = -ny; double py = nx; QPoint edgePt(rint(_points[0].x() - nx * _ARROW_LENGTH), rint(_points[0].y() - ny * _ARROW_LENGTH)); points[0] = _points[0]; points[1] = QPoint(rint(edgePt.x() + px * _ARROW_WIDTH), rint(edgePt.y() + py * _ARROW_WIDTH)); points[2] = QPoint(rint(edgePt.x() - px * _ARROW_WIDTH), rint(edgePt.y() - py * _ARROW_WIDTH)); _arrowhead->setPoints(points); _arrowhead->setZ(z()); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- void TransferItem::show() { Q3CanvasRectangle::show(); _arrowhead->show(); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- void TransferItem::hide() { Q3CanvasRectangle::hide(); _arrowhead->hide(); } //---------------------------------------------------------------------------- // public // // Set the display properties of the supply //---------------------------------------------------------------------------- void TransferItem::setStyle(const LinkDisplayInfo &info) { QColor color; color.setRgb(info.colorRGB()); QPen pen(color); _lineWidth = info.width(); pen.setWidth(_lineWidth); pen.setStyle(RwQtUtils::stringToLineStyle(info.style())); setPen(pen); _arrowhead->setBrush(QBrush(color)); if (info.visible()) { show(); } else { hide(); } } //---------------------------------------------------------------------------- // pubilc // // Scale the supply (i.e., the width of the line). Used to reflect changes in // zoom. //---------------------------------------------------------------------------- void TransferItem::scale(double sx, double) { QPen qpen = pen(); qpen.setWidth((int)_lineWidth*sx); setPen(qpen); } //---------------------------------------------------------------------------- // pubilc // // Returns true if the point is "close" to the Bezier curve. //---------------------------------------------------------------------------- bool TransferItem::hit(const QPoint &point) const { Q3PointArray bezier = _points.cubicBezier(); // double closeDistSq = 4 + pow(_lineWidth / 2, 2); double closeDistSq = 4 + (_lineWidth * _lineWidth / 4); for (int i=0; i < bezier.size()-1; i++) { const QPoint vect = point - closestPoint(bezier[i], bezier[i+1], point); const int vectX (vect.x()); const int vectY (vect.y()); const double distSq = (vectX * vectX) + (vectY * vectY); if (distSq <= closeDistSq) { return true; } } return false; } //---------------------------------------------------------------------------- // protected // // Finds and returns the closest point to 'p' on the line segment defined // by e1 and e2. // //---------------------------------------------------------------------------- QPoint TransferItem::closestPoint(const QPoint &e1, const QPoint &e2, const QPoint &p) const { double u = ( (p.x()-e1.x()) * (e2.x()-e1.x()) ) + ( (p.y()-e1.y()) * (e2.y()-e1.y()) ); const int diffX (e1.x() - e2.x()); const int diffY (e1.y() - e2.y()); u /= ((diffX * diffX) + (diffY * diffY)); if (u < 0) { return e1; } if (u > 1) { return e2; } return QPoint(rint(e1.x() + u * (e2.x() - e1.x())), rint(e1.y() + u * (e2.y() - e1.y()))); } //--- (end TransferItem.cpp) ---