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();
}
Esempio n. 2
0
  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);
    }
  }