Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How can I draw a shape area around a polyline? So I can move polyline with mouse.

How can I draw a shape area around a polyline? So I can move polyline with mouse.

Scheduled Pinned Locked Moved Unsolved General and Desktop
qt4boundingrectshapepolygonpolyline
11 Posts 3 Posters 5.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    helloworld12345
    wrote on 3 Aug 2017, 02:01 last edited by
    #1

    The shape function is used to replace boundingRect. Polyline is not an enclosed area, so there is no concept inside or outside as polygon.

    The shape should be an area around the polyline, so the shape should be able to detect the mouse cursor when it's around the polyline(for example when distance is 10).

    Does anyone have experience on this? I really appreciate any suggestions.

    R 1 Reply Last reply 3 Aug 2017, 06:59
    0
    • H helloworld12345
      3 Aug 2017, 02:01

      The shape function is used to replace boundingRect. Polyline is not an enclosed area, so there is no concept inside or outside as polygon.

      The shape should be an area around the polyline, so the shape should be able to detect the mouse cursor when it's around the polyline(for example when distance is 10).

      Does anyone have experience on this? I really appreciate any suggestions.

      R Offline
      R Offline
      raven-worx
      Moderators
      wrote on 3 Aug 2017, 06:59 last edited by
      #2

      @helloworld12345
      by polyline you mean a list of points right?
      I think the easiest would be to draw rectangles for each line segment and merge them each into a QPainterPath. When you are done call QPainterPath::toFillPolygon().
      Now the problem is just to calculate the coordinates of the rectangles based on the line-segments and your desired spacing.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      H 2 Replies Last reply 4 Aug 2017, 00:34
      0
      • H Offline
        H Offline
        helloworld12345
        wrote on 3 Aug 2017, 22:53 last edited by helloworld12345 8 Mar 2017, 22:54
        #3

        @raven-worx said in How can I draw a shape area around a polyline? So I can move polyline with mouse.:

        toFillPolygon()

        Thanks raven.

        1. I didn't use toFillPolygon, but use addPolygon, it works partially, most but not all area can be dragged by mouse.
        2. I added eclipses around the points of polyline since rect can't cover the turning area of polyline, but it seems the eclipses didn't response when I use mouse to drag it, you have any idea? Below is the simplified code.
        def shape(self):  
            final_shape = QPainterPath()
            
            ##
            ##here calcuclate the each polygon for each line session, store the points in polygons
            ##
            
            for k in range(0, len(polygons)):
                polygon = QPolygonF([polygons[k][0], polygons[k][1],  polygons[k][2], polygons[k][3]])
                final_shape.addPolygon(polygon)
        
        
            for p in self._polyline:
                newpath = QPainterPath()
                newpath.addEllipse(p, 15, 15)
                final_shape = final_shape.united(newpath)
                
            return final_shape
        
        1 Reply Last reply
        0
        • R raven-worx
          3 Aug 2017, 06:59

          @helloworld12345
          by polyline you mean a list of points right?
          I think the easiest would be to draw rectangles for each line segment and merge them each into a QPainterPath. When you are done call QPainterPath::toFillPolygon().
          Now the problem is just to calculate the coordinates of the rectangles based on the line-segments and your desired spacing.

          H Offline
          H Offline
          helloworld12345
          wrote on 4 Aug 2017, 00:34 last edited by
          #4

          @raven-worx if you happen to know some example code in which several graphics(rect + ellipse) are combined in shape, that would definitely help a lot.

          1 Reply Last reply
          0
          • R raven-worx
            3 Aug 2017, 06:59

            @helloworld12345
            by polyline you mean a list of points right?
            I think the easiest would be to draw rectangles for each line segment and merge them each into a QPainterPath. When you are done call QPainterPath::toFillPolygon().
            Now the problem is just to calculate the coordinates of the rectangles based on the line-segments and your desired spacing.

            H Offline
            H Offline
            helloworld12345
            wrote on 4 Aug 2017, 05:36 last edited by
            #5

            @raven-worx
            you can see I drew a rect for each line session, an ellipse for each point(rect doesn't cover the point). With all these rects and ellipses, the polyline is covered totally.

            But at the left-most, right-most, up-most, bottom-most area of the shape, my mouse can't drag the polyline. And at the intersection area of rect and ellipse, I can't drag either, does any one have idea?

            In paint function, I draw my shape area, please see below picture. My polyline is yellow, shape area is red, the area can't be dragged by mouse is pointed out by black lines.
            alt text

            I also attached my code here.

            def shape(self):
            
                selectionOffset = 15
            
                path = QPainterPath()
            
                pn = [p for p in self._polyline]
            
            
                for k in range(0, len(pn) -1):
                    line = QLineF(pn[k], pn[k+1])
                    radAngle = line.angle()* math.pi / 180
            
                    dx = selectionOffset * math.sin(radAngle)
                    dy = selectionOffset * math.cos(radAngle)
            
                    offset1 = QPointF(dx, dy)
                    offset2 = QPointF(-dx, -dy)
            
                    rect_p1 = line.p1() + offset1
                    rect_p2 = line.p1() + offset2
                    rect_p3 = line.p2() + offset2
                    rect_p4 = line.p2() + offset1
            
                    polygon_new = QPolygonF([rect_p1, rect_p2, rect_p3, rect_p4])
            
                    path.addPolygon(polygon_new)
            
                for m in range(0, len(pn)):
                    path.addEllipse(pn[m], 15, 15)
            
                return path
            
            R 1 Reply Last reply 4 Aug 2017, 07:39
            0
            • H helloworld12345
              4 Aug 2017, 05:36

              @raven-worx
              you can see I drew a rect for each line session, an ellipse for each point(rect doesn't cover the point). With all these rects and ellipses, the polyline is covered totally.

              But at the left-most, right-most, up-most, bottom-most area of the shape, my mouse can't drag the polyline. And at the intersection area of rect and ellipse, I can't drag either, does any one have idea?

              In paint function, I draw my shape area, please see below picture. My polyline is yellow, shape area is red, the area can't be dragged by mouse is pointed out by black lines.
              alt text

              I also attached my code here.

              def shape(self):
              
                  selectionOffset = 15
              
                  path = QPainterPath()
              
                  pn = [p for p in self._polyline]
              
              
                  for k in range(0, len(pn) -1):
                      line = QLineF(pn[k], pn[k+1])
                      radAngle = line.angle()* math.pi / 180
              
                      dx = selectionOffset * math.sin(radAngle)
                      dy = selectionOffset * math.cos(radAngle)
              
                      offset1 = QPointF(dx, dy)
                      offset2 = QPointF(-dx, -dy)
              
                      rect_p1 = line.p1() + offset1
                      rect_p2 = line.p1() + offset2
                      rect_p3 = line.p2() + offset2
                      rect_p4 = line.p2() + offset1
              
                      polygon_new = QPolygonF([rect_p1, rect_p2, rect_p3, rect_p4])
              
                      path.addPolygon(polygon_new)
              
                  for m in range(0, len(pn)):
                      path.addEllipse(pn[m], 15, 15)
              
                  return path
              
              R Offline
              R Offline
              raven-worx
              Moderators
              wrote on 4 Aug 2017, 07:39 last edited by
              #6

              @helloworld12345
              try setting the fillRule of the path to Qt::WindingFill

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              H 1 Reply Last reply 4 Aug 2017, 18:04
              1
              • A Offline
                A Offline
                Asperamanca
                wrote on 4 Aug 2017, 09:34 last edited by
                #7

                I would try this:

                • Find out the coordinates of a point which should work for dragging, but doesn't
                • Make a debug function that calls yourPolyline->contains(thatPoint)
                • Step into the contains method and see where the code decides that the point is not part of your polyline's shape
                H 1 Reply Last reply 4 Aug 2017, 18:09
                1
                • R raven-worx
                  4 Aug 2017, 07:39

                  @helloworld12345
                  try setting the fillRule of the path to Qt::WindingFill

                  H Offline
                  H Offline
                  helloworld12345
                  wrote on 4 Aug 2017, 18:04 last edited by
                  #8

                  @raven-worx

                  I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.

                  Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.

                  Does it make sense to you?

                  1 Reply Last reply
                  0
                  • A Asperamanca
                    4 Aug 2017, 09:34

                    I would try this:

                    • Find out the coordinates of a point which should work for dragging, but doesn't
                    • Make a debug function that calls yourPolyline->contains(thatPoint)
                    • Step into the contains method and see where the code decides that the point is not part of your polyline's shape
                    H Offline
                    H Offline
                    helloworld12345
                    wrote on 4 Aug 2017, 18:09 last edited by
                    #9

                    @Asperamanca

                    Hi, this is what I replied to raven-worx, does it make sense to you?

                    I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.

                    Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      Asperamanca
                      wrote on 7 Aug 2017, 08:46 last edited by
                      #10

                      The docs nowhere specify that the shape has to be fully contained within the boundingRect. However, it seems like a logical optimization to first make a hit test using the boundingRect, before even checking the much more complex shape.

                      Do you have any clipping flags set (e.g. ItemClipsToShape, or ItemClipsChildrenToShape for a parent)? This might actually change the behavior, because this code of QGraphicsItem seems relevant:

                      bool QGraphicsItem::contains(const QPointF &point) const
                      {
                          return isClipped() ? clipPath().contains(point) : shape().contains(point);
                      }
                      

                      ...and the clipPath() starts with the boundingRect()

                      H 1 Reply Last reply 16 Aug 2017, 17:09
                      0
                      • A Asperamanca
                        7 Aug 2017, 08:46

                        The docs nowhere specify that the shape has to be fully contained within the boundingRect. However, it seems like a logical optimization to first make a hit test using the boundingRect, before even checking the much more complex shape.

                        Do you have any clipping flags set (e.g. ItemClipsToShape, or ItemClipsChildrenToShape for a parent)? This might actually change the behavior, because this code of QGraphicsItem seems relevant:

                        bool QGraphicsItem::contains(const QPointF &point) const
                        {
                            return isClipped() ? clipPath().contains(point) : shape().contains(point);
                        }
                        

                        ...and the clipPath() starts with the boundingRect()

                        H Offline
                        H Offline
                        helloworld12345
                        wrote on 16 Aug 2017, 17:09 last edited by
                        #11

                        @Asperamanca

                        No, I didn't set these two flags ItemClipsToShape, ItemClipsChildrenToShape.

                        Then I tried setting only one flag ItemClipsToShape, and both of ItemClipsToShape, ItemClipsChildrenToShape. For each, it still check if the point is in the boundingrect() firstly, and then check the shape() which means if point is not in boundingrect(), it wouldn't bother to check shape().

                        So now my solution is still enlarging the boundingrect() area.

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved