Open GoogleCodeExporter opened 9 years ago
Original comment by neilboyd
on 13 Apr 2010 at 9:16
This issue was closed by revision r128.
Original comment by neilboyd
on 13 Apr 2010 at 9:18
Hi,
I'm just trying to implement the onSingleTap method to recognize if a line has
been
touched using your posted code.
I've slightly rewritten your concept, so it is structured more like
OpenStreetMapItemizedOverlay. This means I'm having one Object
OpenStreetMapViewOverlayPath which contains all information for one path. Then
I add
a list of OpenStreetMapViewOverlayPath objects to OpenStreetMapViewPathOverlay
which
is then added to OpenStreetMapView.mOverlays. This is working for me.
But I'm struggling with the projections to recognize if a line has been touched
by
the user.
Here's my current onSingleTab:
[code]
@Override
public boolean onSingleTapUp(MotionEvent event,
OpenStreetMapView mapView)
{
final OpenStreetMapViewProjection pj = mapView.getProjection();
final int eventX = (int)event.getX();
final int eventY = (int)event.getY();
Point mCurScreenCoordsLinePoint1 = new Point();
Point mCurScreenCoordsLinePoint2 = new Point();
Point mTabCoords = new Point();
for(int i = 0; i < this.mItemList.size(); i++)
{
final OpenStreetMapViewOverlayPath mItem =
this.mItemList.get(i);
for(int n = 0; n < mItem.mPoints.size(); n++)
{
if(n+1 < mItem.mPoints.size())
{
// line point 1
pj.toMapPixels(new
GeoPoint(mItemList.get(i).mPoints.get(n).y,
mItemList.get(i).mPoints.get(n).x)
,
mCurScreenCoordsLinePoint1);
// line point 2
pj.toMapPixels(new
GeoPoint(mItemList.get(i).mPoints.get(n+1).y,
mItemList.get(i).mPoints.get(n+1).x)
,
mCurScreenCoordsLinePoint2);
// my tap position
mTabCoords = pj.fromPixels(eventX, eventY,
OpenStreetMap.isSlided);
if(isPointOnLine(mCurScreenCoordsLinePoint1.x, mCurScreenCoordsLinePoint1.y,
mCurScreenCoordsLinePoint2.x, mCurScreenCoordsLinePoint2.y,
mTabCoords.x,
mTabCoords.y))
{
if(onTap(i))
return true;
}
}
}
}
return super.onSingleTapUp(event, mapView);
}
public static boolean isPointOnLine(float lox, float loy, float ltx, float
lty, float x, float y)
{
//determine if point is on line
Float dx = x - lox;
Float dy = y - loy;
Float tx = ltx - lox;
Float ty = lty - loy;
//normalise the line vector
Float t1 = new Float(1/Math.sqrt(tx*tx+ty*ty));
tx *= t1;
ty *= t1;
//calculate inverse length of secondary vector
Float dl = new Float(1/Math.sqrt(dx*dx+dy*dy));
//take dot product of normalised line vector, and rotated normalised
secondary vector
Float dot = (dy*tx-dx*ty)*dl;
//Increase these values for less or more picky
if (dot < -0.2 || dot > 0.2)
return false;
//calculate distance along line segment by taking dot product of normalised
line vector and un-normalised secondary vector
Float dis = tx*dx+ty*dy;
if (dis < 0 || dis > 1 / t1)
return false;
return true;
}
[/code]
Currently I'm using the same type of projection as used in
OpenStreetMapViewItemizedOverlay - I don't think that's correct, is it?
When I have the starting and endpoint of a subline in an overall line, I check
if it
has been touched using the PointOnLine algorithm.
When it's possible to recognize a correct touch event I would love to add some
kind
of bubble as in OpenStreetMapViewItemizedOverlayWithFocus. But right now I'm
really
struggling with the projection stuff.
I attached my two classes.
Thank you in advance and thanks for the great path overlay!
Original comment by d.sc...@gmail.com
on 29 Apr 2010 at 3:10
I'm sorry, I forgot to attach the code. Here it is now.
Original comment by d.sc...@gmail.com
on 29 Apr 2010 at 3:12
Attachments:
Hi!
I will implement a hit testing method, that takes care of the projections.
Original comment by viesturz
on 30 Apr 2010 at 7:19
Made a simple patch that demoes hit testing in path overlay.
Note that the code tests only for distance to points, not distance to lines.
Original comment by viesturz
on 30 Apr 2010 at 10:08
Attachments:
wow, thanks viesturz! I'm going to test it as soon as possible. But problems
could
occur when the starting and end point of a line are farther from eachother
away, am I
right?
cheers,
d.schre
Original comment by d.sc...@gmail.com
on 30 Apr 2010 at 11:07
Here is a patch that tests line segments.
Original comment by viesturz
on 30 Apr 2010 at 12:29
Attachments:
thank you very much viesturz!
I'm trying to understand the algorithm you implemented.
This part in findPointInPath confuses me a little bit:
// call in onSingleTap
findPointInPath(canvasPxels.x, canvasPxels.y, Math.max(event.getSize(),
this.mPaint.getStrokeWidth()) + 5, mapView.getProjection());
// code in findPointInPath
float approxDist = Math.max(Math.abs(pt.x - testX), Math.abs(pt.y - testY)) -
Math.abs(pt.x - prevX) - Math.abs(pt.y - prevY);
if (approxDist <= maxDistance) // <-- Couldn't be there a problem if the line
segment's points are too far away from eachother?
As I am understanding it right now, the start and end point of a line segment
can not
be farther away from eachother than the size of the touch event (finger) or the
StrokeWidth + 5 (pixels) to be recognized as touched? Is my assumption correct?
Because it's working really good if you touch the line near it's points but it
gets
tricky when you try to touch a (very) long line in the middle.
Thanks!
Original comment by d.sc...@gmail.com
on 5 May 2010 at 12:34
Hi!
Yes your assumption is correct. I tried to make some approximation of the touch
size
as max from touch size and line width, added the 5 units, just in case. Feel
free to
use some other values.
// code in findPointInPath
float approxDist = Math.max(Math.abs(pt.x - testX), Math.abs(pt.y - testY)) -
Math.abs(pt.x - prevX) - Math.abs(pt.y - prevY);
A very rough approximation to test if the line is far away from the point. Try
to
follow me here carefully:
The current point is at least Math.max(Math.abs(pt.x - testX), Math.abs(pt.y -
testY)) from test point. And the previous point is no more than Math.abs(pt.x -
prevX) + Math.abs(pt.y - prevY) closer to test point than the current point
(imagine
it being in middle between test point and current point). Thus the test point
is at
least (the whole expr.) away from any point on the line segment.
You can try to replace the *if (approxDist <= maxDistance)* with *if (true)*
and test
if it makes the code work better in your case.
Viesturs
Original comment by viesturz
on 5 May 2010 at 12:49
Ok, thanks for the explanation! I just increased maxDist to make it work for
longer
lines.
Original comment by d.sc...@gmail.com
on 7 May 2010 at 7:40
Just a note:
maxDist is maximum distance from the line, regardless of the length of the line.
Original comment by viesturz
on 7 May 2010 at 8:02
Is this finished now? What patch should I apply to the source?
Original comment by neilboyd
on 11 May 2010 at 7:20
It's not quite ready for the source, just a implementation of a hit testing
function.
There is still a problem of defining a nice API.
d.schre has his own path overlay implementation that supports multiple paths.
I suggest we make a generic item view overlay that can house both POIs and
paths.
Original comment by viesturz
on 11 May 2010 at 11:28
Perhaps I should remove the patch I applied for revision r128 then? And wait
until it's
finished.
Original comment by neilboyd
on 11 May 2010 at 11:36
Nope, that patch is fine. But it contains only the basic functionality for
displaying
tracks. The later patches are for interacting with the tracks.
Perhaps we should move it to another issue.
Original comment by viesturz
on 11 May 2010 at 12:15
It's a bit late now ;-)
Original comment by neilboyd
on 11 May 2010 at 2:54
Not really, just 6 pm at UTC+02 ;)
Original comment by viesturz
on 11 May 2010 at 2:56
Original comment by neilboyd
on 14 Oct 2010 at 6:58
Original issue reported on code.google.com by
viesturz
on 7 Apr 2010 at 11:50Attachments: