tanweijiu / osmbonuspack

Automatically exported from code.google.com/p/osmbonuspack
0 stars 0 forks source link

onLongPress in a Polyline #79

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi
I have to add some Polylines to a MapView and each line should open a popup 
relative to that item on a long press event.
The problem is that if I override the method onLongPress it does not affect 
only the line drawed, but all the Overlay which covers all the map.
How can I set it so that i must click on the drawed line only to open the popup?

Thanks 
Michele

Original issue reported on code.google.com by armellin...@gmail.com on 7 Aug 2014 at 3:07

GoogleCodeExporter commented 9 years ago
You must check first if the event is related to your overlay. And this is not 
done yet for polylines.
The key point is to detect if the hit point is close to the polyline. The 
method used for polygon can not be used here. So you have to check segment 
after segment if the point is close enough.
If you implement that, I would be interested to add it in the lib.

Original comment by mathieu....@gmail.com on 7 Aug 2014 at 7:24

GoogleCodeExporter commented 9 years ago
I came up with a solution which could be optimized a lot but works.
Probably it won't work very smoothly where there are a lot of Polylines.
I have overrode the Polyline adding the following methods:

//Method to be called to check if a point is on the line
public boolean isOnLine(IGeoPoint point) {
        boolean toRtn = false;
        ArrayList<GeoPoint> mPoints = (ArrayList<GeoPoint>) getPoints();
        for (int i = 0; i < getNumberOfPoints() - 1; i++) {
            GeoPoint a = mPoints.get(i);
            GeoPoint b = mPoints.get(i + 1);
                        //the simpliest way i found is to hardcode a tolerance but it could be made so it varies with the zoom level
            toRtn = toRtn || (linePointDist(a, b, point, true) <= 0.0005);
        }
        return toRtn;
    }

    // Compute the dot product AB x AC
    private double dot(IGeoPoint A, IGeoPoint B, IGeoPoint C) {
        double[] AB = new double[2];
        double[] BC = new double[2];
        AB[0] = B.getLongitude() - A.getLongitude();
        AB[1] = B.getLatitude() - A.getLatitude();
        BC[0] = C.getLongitude() - B.getLongitude();
        BC[1] = C.getLatitude() - B.getLatitude();
        double dot = AB[0] * BC[0] + AB[1] * BC[1];
        return dot;
    }

    // Compute the cross product AB x AC
    private double cross(IGeoPoint A, IGeoPoint B, IGeoPoint C) {
        double[] AB = new double[2];
        double[] AC = new double[2];
        AB[0] = B.getLongitude() - A.getLongitude();
        AB[1] = B.getLatitude() - A.getLatitude();
        AC[0] = C.getLongitude() - A.getLongitude();
        AC[1] = C.getLatitude() - A.getLatitude();
        double cross = AB[0] * AC[1] - AB[1] * AC[0];
        return cross;
    }

    // Compute the distance from A to B
    private double distance(IGeoPoint A, IGeoPoint B) {
        double d1 = A.getLongitude() - B.getLongitude();
        double d2 = A.getLatitude() - B.getLatitude();
        return Math.sqrt(d1 * d1 + d2 * d2);
    }

    // Compute the distance from AB to C
    // if isSegment is true, AB is a segment, not a line.
    private double linePointDist(IGeoPoint A, IGeoPoint B, IGeoPoint C,
            boolean isSegment) {
        double dist = cross(A, B, C) / distance(A, B);
        if (isSegment) {
            double dot1 = dot(A, B, C);
            if (dot1 > 0)
                return distance(B, C);
            double dot2 = dot(B, A, C);
            if (dot2 > 0)
                return distance(A, C);
        }
        return Math.abs(dist);
    }

Original comment by armellin...@gmail.com on 8 Aug 2014 at 3:21

GoogleCodeExporter commented 9 years ago
Thanks a lot, that's a good starting point. 
I integrated directly in the Polyline class, with some perfs improvements. 
The source is now commited. 

Simple usage:
polyline.setInfoWindow(new DefaultInfoWindow(R.layout.bonuspack_bubble, map));
polyline.setTitle("My Route");

However, this solution has 2 issues: 
1) As you mentionned, no handling of zoom level
2) In geodesic mode, additional points not taken into account

It would be probably better to work in the projected (screen) coord system, but 
this is not straightforward. I let the issue opened for now. 

Original comment by mathieu....@gmail.com on 11 Aug 2014 at 4:02

GoogleCodeExporter commented 9 years ago
Solution solving issues 1 and 2 just commited. Touch detection done in screen 
coords, taking into account polyline stroke width. 

Original comment by mathieu....@gmail.com on 22 Aug 2014 at 12:55

GoogleCodeExporter commented 9 years ago
Feature now fully integrated in v4.9. 
Michelle, thanks for the contribution! 

Original comment by mathieu....@gmail.com on 15 Sep 2014 at 3:52