-1

Any ideas how to draw custom geofence area in QML (Qt Location module) similar to this:

enter image description here

Something similar to MapCircle or MapPolygon but filled outside of the region? And have custom filling pattern?

Aleksey Kontsevich
  • 4,671
  • 4
  • 46
  • 101

1 Answers1

1

You probably can play with one of MapItems, for example MapQuickItem allows you put any QML item inside, for example I use Canvas for that:

Plugin {
    id: mapPlugin
    name: "osm"
}

Map {
    id: map
    anchors.fill: parent
    plugin: mapPlugin
    center: QtPositioning.coordinate(59.91, 10.75)
    zoomLevel: 14

    MapQuickItem {
        id: marker
        anchorPoint.x: image.width / 2
        anchorPoint.y: image.height / 2
        coordinate: map.center
        sourceItem: Canvas {
            id: image
            width: map.width
            height:  map.height
            onPaint: {
                var ctx = getContext("2d");
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(image.width, 0);
                ctx.lineTo(image.width, image.height);
                ctx.lineTo(0, image.height);
                ctx.lineTo(0, 0);
                ctx.moveTo(image.width/2 + 50, image.height/2);
                ctx.arc(image.width/2, image.height/2, 50, 0, 2 * Math.PI,0, true);
                ctx.closePath();
                ctx.fillStyle = Qt.rgba(1.0, 0, 0, 0.5);
                ctx.strokeStyle = "red"
                ctx.lineWidth = 10;
                ctx.fill();
                ctx.stroke();
            }
        }
    }
}

Pay attention, the arc's counterclockwise is true to make a hole. In the same way you can add images etc. But in a real project I would use some custom QQuickItem based item, just for better performance.

Aleksey Kontsevich
  • 4,671
  • 4
  • 46
  • 101
folibis
  • 12,048
  • 6
  • 54
  • 97
  • Wow! it works! Thanks! In real project I'll need to do 3 things: convert map coordinates to screen coordinates with `map.fromCoordinate()` method, so hole will move on pan or zoom (hole is in map coordinates). And replace circle with a polygon, and fill the area by tilted red dash lines pattern. So `Canvas` works perfect here. – Aleksey Kontsevich Jul 31 '22 at 08:18
  • Question about arc's counterclockwise: what if I want to draw arbitrary polygon? Will it work? – Aleksey Kontsevich Jul 31 '22 at 08:19
  • if you draw a shape (arc or polygon) in opposite direction then outer one it will make a hole. – folibis Jul 31 '22 at 08:21
  • 1
    I don't know how does this trick really works, [This question](https://stackoverflow.com/questions/13618844/polygon-with-a-hole-in-the-middle-with-html5s-canvas) for example does the same I think. – folibis Jul 31 '22 at 09:50
  • As I have predefined polygon, then I need to define its direction somehow and draw outer line in the opposite direction. Also need to see what will happen if polygon crosses map viewport. – Aleksey Kontsevich Jul 31 '22 at 11:07
  • Thanks a lot!!! Link You'd mentioned also contains function to detect shape is clockwise or not. Also it shows how to fill area around the polygon, so it is possible to fill whole map or just some threshold around the polygon. – Aleksey Kontsevich Aug 01 '22 at 19:10
  • I've converted polygon map coordinates into screen coordinates and got multiple problems with above solution: polygon does not move/scale with map pan/zoom, this was easily solved however by setting correct `MapQuickItem`'s `coordinate` and `anchorPoint` properties. – Aleksey Kontsevich Aug 02 '22 at 21:09
  • 2nd problem: it works correctly only if geofence polygon fully inside the screen, if geofence polygon crosses map viewport so screen coordinates appear outside of the screen, then canvas draws incorrect polygon - is there a way to draw canvas outside of the screen? 3rd: Not redrawn on map pan/zoom, so seems need to redraw canvas not only `onPaint` but also on map pan/zoom - will try this. – Aleksey Kontsevich Aug 02 '22 at 21:09
  • 3rd is solved by calling `canvas.requestPaint()` on map pan/zoom, however need to clear context on every repaint: `ctx.clearRect(0, 0, width, height)`. The only problem to solve is the 2nd one: if geofence polygon crosses lays out of map viewport (visible area). – Aleksey Kontsevich Aug 02 '22 at 22:13
  • 2nd is solved with QML `Map` component method call [`point fromCoordinate(coordinate coordinate, bool clipToViewPort)`](https://doc.qt.io/qt-5/qml-qtlocation-map.html#fromCoordinate-method) with `clipToViewPort` parameter set to `false`. – Aleksey Kontsevich Oct 06 '22 at 18:13