void Arrow2D(const Point<float>& tail, const Point<float>& head) { // u-v-w - Arrow coordinate system: Vector<float> u, v, w; Vector<float> arrowLine(tail, head); GetOrthonormalBasisFromNormal(arrowLine, u, v, w); // set size of wings and turn w into a Unit vector: float d = WINGS * arrowLine.norm(); // draw the shaft of the arrow: glBegin(GL_LINE_STRIP); glVertex3f(tail.x(), tail.y(), tail.z()); glVertex3f(head.x(), head.y(), head.z()); glEnd(); Vector<float> point1(head.x() + d * (u.x() - w.x()), head.y() + d * (u.y() - w.y()), head.z() + d * (u.z() - w.z())); glBegin(GL_LINE_STRIP); glVertex3f(head.x(), head.y(), head.z()); glVertex3f(point1.x(), point1.y(), point1.z()); glEnd(); Vector<float> point2(head.x() + d * (-u.x() - w.x()), head.y() + d * (-u.y() - w.y()), head.z() + d * (-u.z() - w.z())); glBegin(GL_LINE_STRIP); glVertex3f(head.x(), head.y(), head.z()); glVertex3f(point2.x(), point2.y(), point2.z()); glEnd(); }
void Arrow::readGraphicAttributes(const QXmlStreamAttributes &attributes) { // Check for legacy arrow type auto legacyArrowType = attributes.value("type").toString(); // if not legacy type, read arrow tip type and return if ("ReactionArrow" != legacyArrowType // TODO make these names constants (see MolScene::produceChild()) && "MechanismArrow" != legacyArrowType) { d->arrowType = (ArrowType) (attributes.value("arrowType").toString().toInt()) ; d->spline = ! (attributes.value("splineDisabled").toString().toInt()); return; } // Code for legacy version if ("ReactionArrow" == legacyArrowType) { enum LegacyReactionArrowType { SingleArrow = 0, DoubleArrow, Equilibrium, EqRightShifted, EqLeftShifted }; // Arrow tip auto legacyReactionArrowType = (LegacyReactionArrowType) (attributes.value("arrowType").toString().toInt()); switch(legacyReactionArrowType) { case SingleArrow: setArrowType(UpperBackward | LowerBackward); break; case DoubleArrow: setArrowType(LowerForward | UpperForward | LowerBackward | UpperBackward); break; case Equilibrium: case EqRightShifted: case EqLeftShifted: setArrowType(UpperBackward); break; default: setArrowType(NoArrow); } // Coordinates QPointF origin(attributes.value("posx").toString().toDouble(), attributes.value("posy").toString().toDouble()); QLineF arrowLine(origin, origin + QPointF(attributes.value("endx").toString().toDouble(), attributes.value("endy").toString().toDouble())); setCoordinates(QPolygonF() << arrowLine.p1() << arrowLine.p2()); if (!scene()) return; // Fix equilibrium arrows: if (Equilibrium == legacyReactionArrowType || EqLeftShifted == legacyReactionArrowType || EqRightShifted == legacyReactionArrowType) { // shift both arrows in equilibrium QLineF normalVector = arrowLine.normalVector().unitVector(); QLineF unitVector = arrowLine.unitVector(); QPointF normalTranslation = 2*(normalVector.p2() - normalVector.p1()); QPointF unitTranslation = 15*(unitVector.p2() - unitVector.p1()); QLineF reverseArrowLine = arrowLine; arrowLine.translate(normalTranslation); reverseArrowLine.translate(-normalTranslation); if (EqRightShifted == legacyReactionArrowType) { reverseArrowLine.setP1(reverseArrowLine.p1() + unitTranslation); reverseArrowLine.setP2(reverseArrowLine.p2() - unitTranslation); } if (EqLeftShifted == legacyReactionArrowType) { arrowLine.setP1(arrowLine.p1() + unitTranslation); arrowLine.setP2(arrowLine.p2() - unitTranslation); } auto reverseArrow = new Arrow; reverseArrow->setParentItem(parentItem()); scene()->addItem(reverseArrow); reverseArrow->setCoordinates(QPolygonF() << reverseArrowLine.p1() << reverseArrowLine.p2()); reverseArrow->setArrowType(LowerForward); setCoordinates(QPolygonF() << arrowLine.p1() << arrowLine.p2()); } } if ("MechanismArrow" == legacyArrowType) { enum LegacyMechanismArrowType { SingleArrowRight = 0, SingleArrowLeft, DoubleMechanismArrow, SingleHookRight, SingleHookLeft, DoubleHook }; // Arrow tip auto legacyMechanismArrowType = (LegacyMechanismArrowType) (attributes.value("arrowType").toString().toInt()); switch(legacyMechanismArrowType) { case SingleArrowRight: setArrowType(UpperBackward | LowerBackward); break; case SingleArrowLeft: setArrowType(UpperForward | LowerForward); break; case DoubleMechanismArrow: setArrowType(LowerForward | UpperForward | LowerBackward | UpperBackward); break; case SingleHookRight: setArrowType(UpperBackward); break; case SingleHookLeft: setArrowType(UpperForward); break; case DoubleHook: setArrowType(UpperForward | UpperBackward); break; default: setArrowType(NoArrow); } // Setting coordinates QPolygonF points; for (int i = 0 ; i < 4 ; ++i) points << QPointF(attributes.value("p" + QString::number(i+1) + "x").toString().toDouble(), attributes.value("p" + QString::number(i+1) + "y").toString().toDouble()); points.translate(attributes.value("posx").toString().toDouble(), attributes.value("posy").toString().toDouble()); setCoordinates(points); } }