Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-124745

Let QPainter draw custom shape along line/arc/polygon/etc., or let QGraphicsScene lay out items likewise

    XMLWordPrintable

Details

    Description

      The use case is that someone wants to draw polygon (or some other shapes, but polygon as an example) with complex strokes. Or equivalently, lay out QGraphicsItems along contour defined by polygon. Anyway, imagine a highly artistic polygon whose contour is consist of the "stroke" shown in the attached image "stroke".

      I don't see any existing APIs that can do what is described. I think there can be 2 options:
      1. Add a "stroke" argument to QPainter::drawPolygon. Customer can designate a custom stroke other than just a plain line.
      2. Add an API related to "pattern" in QGraphicsScene. The purpose is to lay out QGraphicsItem instances against a "pattern" defined by some other APIs.

      The current workaround foes with 2, using QGraphicsScene. Something like:

      class CustomGraphicsItem : public QGraphicsItem
      {
      public:
          QRectF boundingRect() const override
          {
              qreal penWidth = 1;
              return QRectF(-10 - penWidth / 2, -10 - penWidth / 2, 20 + penWidth, 20 + penWidth);
          }
      
          void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
          {
              painter->drawImage(this->boundingRect(), QImage("stroke.png"));
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
      
          //The polygon contour
          QPolygonF polygon;
          polygon << QPoint(0, 0) << QPoint(100, 100) << QPoint(200, 100) << QPoint(300, 0);
      
          QGraphicsScene scene;
      
          //Loop through polygon vertices
          for (int i = 0; i < polygon.size(); ++i) {
              QPointF p1 = polygon[i];
              QPointF p2 = polygon[(i + 1) % polygon.size()]; // next point, with wraparound
      
              //Reference item just for better clearity
              CustomGraphicsItem *ref = new CustomGraphicsItem();
              ref->setPos(p1);
              scene.addItem(ref);
      
              // CInterpolated item
              CustomGraphicsItem *item = new CustomGraphicsItem();
      
              // Position item at midpoint of polygon side
              item->setPos((p1 + p2) / 2.0);
      
              // Calculate angle between horizontal and the side of the polygon
              qreal angle = std::atan2(p2.y() - p1.y(), p2.x() - p1.x());
      
              // Rotate item to align with polygon side
              QTransform t;
              t.rotateRadians(angle);
              item->setTransform(t);
      
              scene.addItem(item);
          }
      
          QGraphicsView view(&scene);
          view.show();
      
          return app.exec();
      }
      

      A custom QGraphicsItem is used to draw the stroke item. A polygon is defined and interpolated (only midpoint is calculated in example for simplicity). Custom items are positioned at vertices and interpolated positions. And the orientation of items is calculated using "std::atan2(p2.y() - p1.y(), p2.x() - p1.x());" and explicitly set.

      The attached screenshot "result" shows the result. With finer interpolation and manipulation in paint(), it should look better. So it works, but very complicated.

      More or less like a "pattern" that SolidWorks provides:
      https://help.solidworks.com/2021/English/SolidWorks/sldworks/t_Curve_Driven_Pattern_Overview.htm#bka1450446754521
      But in 2D space, and orientation also needs to be taken care of.

      Attachments

        1. result.png
          result.png
          4 kB
        2. stroke.png
          stroke.png
          0.3 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            vgt Eirik Aavitsland
            luqiaochen Luqiao Chen
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes