draw vertical line to camera center in arcore - android

i have some horizontal plane, where i set the start point of line i want to draw.
Now i want to make a vertical line from start point to the center of camera, aka ArFragment.
Current i make it as follow
// create an anchor 1 meter away of current camera position and rotation
Anchor anchor = arFragment.getArSceneView().getSession().createAnchor(
arFragment.getArSceneView().getArFrame().getCamera().getPose()
.compose(Pose.makeTranslation(0, 0, -1f))
.extractTranslation());
// create AnchorNode with position data of Anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// remove anchor to be free change position of AnchorNode
anchorNode.setAnchor(null);
// get local position of new anchor node
Vector3 newLocPos = anchorNode.getLocalPosition();
// get the local position of start node
Vector3 fromVector = fromNode.getLocalPosition();
// since we want to make vertical line, set x and z of new AnchorNode to same as start
newLocPos.x = fromVector.x;
newLocPos.z = fromVector.z;
// set updated position data to new AnchorNode
anchorNode.setLocalPosition(newLocPos);
// set scene as parent to have node in UI
anchorNode.setParent(arFragment.getArSceneView().getScene());
// draw line between Nodes
....
and this works as expected as long as i can hold smartphone vertical.
When i rotate the camera, the line is no more drawed to middle because the created anchor is no more in the middle of screen.
Is there a official or better way to make a vertical line as expected no matter how i hold a smartphone?
UPDATE
now i have reached to create a line by calculate a point of intersection.
private static MyPoint calculateIntersectionPoint(MyPoint A, MyPoint B, MyPoint C, MyPoint D) {
// Line AB represented as a1x + b1y = c1
double a1 = B.y - A.y;
double b1 = A.x - B.x;
double c1 = a1 * (A.x) + b1 * (A.y);
// Line CD represented as a2x + b2y = c2
double a2 = D.y - C.y;
double b2 = C.x - D.x;
double c2 = a2 * (C.x) + b2 * (C.y);
double determinant = a1 * b2 - a2 * b1;
if (determinant == 0) {
// The lines are parallel. This is simplified
// by returning a pair of FLT_MAX
return new MyPoint(Double.MAX_VALUE, Double.MAX_VALUE);
} else {
double x = (b2 * c1 - b1 * c2) / determinant;
double y = (a1 * c2 - a2 * c1) / determinant;
return new MyPoint(x, y);
}
}
MyPoint interceptionPoint = calculateIntersectionPoint(
new MyPoint(line1From.getWorldPosition().x, line1From.getWorldPosition().y),
new MyPoint(line1To.getWorldPosition().x, line1To.getWorldPosition().y),
new MyPoint(line2From.getWorldPosition().x, line2From.getWorldPosition().y),
new MyPoint(line2To.getWorldPosition().x, line2To.getWorldPosition().y));
// get local position of new anchor node
Vector3 newLocPos = anchorNode.getWorldPosition();
// since we want to make vertical line, set x and z of new AnchorNode to same as start
newLocPos.y = (float) interceptionPoint.y;
newLocPos.x = fromVector.x;
newLocPos.z = fromVector.z;
// set updated position data to new AnchorNode
anchorNode.setWorldPosition(newLocPos);
The only problem is that the line must be exactly in the middle (right, left) of smartphone
in other case the line is too big or too small
sphere shows the middle of camera
UPDATE 2
Some more explanation
we set somewhere in xz-room a startpoint of vertical line.
Then we are some away from the line and look at the point where we want the end of line.
Now i look at the problem in 2D and imagine, that my camera start and end point are in same xy-room as line and calculate the endpoint of line.
The Problem
my start and end points of camera view has different z as the line i draw.
To find is the point (and his y-value) on camera view vector that is in same xy-room as line (z of line = z of point)
Has anyone idea?

It looks like you are removing the anchor from the anchorNode as one of your steps - I think this is because you want to move the anchorNode, but I suspect this is the root of your problem.
The code below will draw a line between any two anchorNodes and remain in place when you rotate the camera (allowing for any small error or movement with your device). This is taken from this answer (https://stackoverflow.com/a/52816504/334402) and built into the project linked below so you can check it:
private void drawLine(AnchorNode node1, AnchorNode node2) {
//Draw a line between two AnchorNodes (adapted from https://stackoverflow.com/a/52816504/334402)
Log.d(TAG,"drawLine");
Vector3 point1, point2;
point1 = node1.getWorldPosition();
point2 = node2.getWorldPosition();
//First, find the vector extending between the two points and define a look rotation
//in terms of this Vector.
final Vector3 difference = Vector3.subtract(point1, point2);
final Vector3 directionFromTopToBottom = difference.normalized();
final Quaternion rotationFromAToB =
Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
MaterialFactory.makeOpaqueWithColor(getApplicationContext(), new Color(0, 255, 244))
.thenAccept(
material -> {
/* Then, create a rectangular prism, using ShapeFactory.makeCube() and use the difference vector
to extend to the necessary length. */
Log.d(TAG,"drawLine insie .thenAccept");
ModelRenderable model = ShapeFactory.makeCube(
new Vector3(.01f, .01f, difference.length()),
Vector3.zero(), material);
/* Last, set the world rotation of the node to the rotation calculated earlier and set the world position to
the midpoint between the given points . */
Anchor lineAnchor = node2.getAnchor();
nodeForLine = new Node();
nodeForLine.setParent(node1);
nodeForLine.setRenderable(model);
nodeForLine.setWorldPosition(Vector3.add(point1, point2).scaled(.5f));
nodeForLine.setWorldRotation(rotationFromAToB);
}
);
}
You can see the full code here: https://github.com/mickod/LineView

Related

Create Anchor in AR at center of screen and move it near or far with respect to camera same like magicplan

I want to create an app same like magicplan and want to draw continuous green vertical pipe same like magicplan which goes near and far as camera moves.
I have tried below code but it keeps node at center of screen.
Please help me how I can achieve this.
Ray ray = arFragment.getArSceneView().getScene().getCamera().screenPointToRay(arFragment.getArSceneView().getWidth() / 2, arFragment.getArSceneView().getHeight() / 2);
Vector3 localpos = ray.getPoint(1f);
Quaternion localRotation = arFragment.getArSceneView().getScene().getCamera().getLocalRotation();
Vector3 localScale = new Vector3(0.3f,0.3f,0.3f);
Frame frame = arFragment.getArSceneView().getArFrame();
Vector3 pos;
pos = Vector3.add(ray.getOrigin(), ray.getDirection());
Pose pose = Pose.makeTranslation(pos.x, pos.y, pos.z);
anchor = arFragment.getArSceneView().getSession().createAnchor(pose);
anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
TransformationSystem transformationSystem = arFragment.getTransformationSystem();
node = new TransformableNode(transformationSystem);
node.setRenderable(cylinderRenderable2);
node.setParent(anchorNode);
node.setLocalPosition(localpos);
node.setLocalRotation(localRotation);
node.setLocalScale(localScale);
node.select();

Can I draw a curved dashed line in Google Maps Android?

In Google Maps from browser which has the curved dashed line look like this:
But when I implement Google Maps in my own Android project, it didn't show this line
How can I draw this line?
You can implement the curved dashed polyline between two points. For this purpose you can use Google Maps Android API Utility Library that has SphericalUtil class and apply some math in your code to create a polyline.
You have to include the utility library in your gradle as
compile 'com.google.maps.android:android-maps-utils:0.5'.
Please have a look at my sample Activity and function showCurvedPolyline (LatLng p1, LatLng p2, double k) that constructs dashed curved polyline between two points. The last parameter k defines curvature of the polyline, it can be >0 and <=1. In my example I used k=0.5
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private LatLng sydney1;
private LatLng sydney2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
// Add a marker in Sydney and move the camera
sydney1 = new LatLng(-33.904438,151.249852);
sydney2 = new LatLng(-33.905823,151.252422);
mMap.addMarker(new MarkerOptions().position(sydney1)
.draggable(false).visible(true).title("Marker in Sydney 1"));
mMap.addMarker(new MarkerOptions().position(sydney2)
.draggable(false).visible(true).title("Marker in Sydney 2"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney1, 16F));
this.showCurvedPolyline(sydney1,sydney2, 0.5);
}
private void showCurvedPolyline (LatLng p1, LatLng p2, double k) {
//Calculate distance and heading between two points
double d = SphericalUtil.computeDistanceBetween(p1,p2);
double h = SphericalUtil.computeHeading(p1, p2);
//Midpoint position
LatLng p = SphericalUtil.computeOffset(p1, d*0.5, h);
//Apply some mathematics to calculate position of the circle center
double x = (1-k*k)*d*0.5/(2*k);
double r = (1+k*k)*d*0.5/(2*k);
LatLng c = SphericalUtil.computeOffset(p, x, h + 90.0);
//Polyline options
PolylineOptions options = new PolylineOptions();
List<PatternItem> pattern = Arrays.<PatternItem>asList(new Dash(30), new Gap(20));
//Calculate heading between circle center and two points
double h1 = SphericalUtil.computeHeading(c, p1);
double h2 = SphericalUtil.computeHeading(c, p2);
//Calculate positions of points on circle border and add them to polyline options
int numpoints = 100;
double step = (h2 -h1) / numpoints;
for (int i=0; i < numpoints; i++) {
LatLng pi = SphericalUtil.computeOffset(c, r, h1 + i * step);
options.add(pi);
}
//Draw polyline
mMap.addPolyline(options.width(10).color(Color.MAGENTA).geodesic(false).pattern(pattern));
}
}
You can download a sample project with complete code from GitHub
https://github.com/xomena-so/so43305664
Just replace my API key with yours in the app/src/debug/res/values/google_maps_api.xml
Thanks to #xomena for the great answer. But it has just one little bug. Sometimes, it's arc becoming like a circle. I made a few debugging and see that, we are always using h + 90.0 for heading value at the 12. line of the method. We can solve this by changing that line like this:
LatLng c = SphericalUtil.computeOffset(p, x, h > 40 ? h + 90.0 : h - 90.0);
From now, you probably not encounter this problem again.
I had the same problem of crooked curved line when I am drawing curve in solid line. After few hours of searching on the internet and trying the different solution. Finally, I came up with the solution (NOT a proper solution but target can be achieved) by using Polygon instead of Polyline. I have modified the above method showCurvedPolyline() to draw a smooth curve and the curve direction will always be in upward direction. Below screenshots are the final result of my modified version.
fun drawCurveOnMap(googleMap: GoogleMap, latLng1: LatLng, latLng2: LatLng) {
//Adding marker is optional here, you can move out from here.
googleMap.addMarker(
MarkerOptions().position(latLng1).icon(BitmapDescriptorFactory.defaultMarker()))
googleMap.addMarker(
MarkerOptions().position(latLng2).icon(BitmapDescriptorFactory.defaultMarker()))
val k = 0.5 //curve radius
var h = SphericalUtil.computeHeading(latLng1, latLng2)
var d = 0.0
val p: LatLng?
//The if..else block is for swapping the heading, offset and distance
//to draw curve always in the upward direction
if (h < 0) {
d = SphericalUtil.computeDistanceBetween(latLng2, latLng1)
h = SphericalUtil.computeHeading(latLng2, latLng1)
//Midpoint position
p = SphericalUtil.computeOffset(latLng2, d * 0.5, h)
} else {
d = SphericalUtil.computeDistanceBetween(latLng1, latLng2)
//Midpoint position
p = SphericalUtil.computeOffset(latLng1, d * 0.5, h)
}
//Apply some mathematics to calculate position of the circle center
val x = (1 - k * k) * d * 0.5 / (2 * k)
val r = (1 + k * k) * d * 0.5 / (2 * k)
val c = SphericalUtil.computeOffset(p, x, h + 90.0)
//Calculate heading between circle center and two points
val h1 = SphericalUtil.computeHeading(c, latLng1)
val h2 = SphericalUtil.computeHeading(c, latLng2)
//Calculate positions of points on circle border and add them to polyline options
val numberOfPoints = 1000 //more numberOfPoints more smooth curve you will get
val step = (h2 - h1) / numberOfPoints
//Create PolygonOptions object to draw on map
val polygon = PolygonOptions()
//Create a temporary list of LatLng to store the points that's being drawn on map for curve
val temp = arrayListOf<LatLng>()
//iterate the numberOfPoints and add the LatLng to PolygonOptions to draw curve
//and save in temp list to add again reversely in PolygonOptions
for (i in 0 until numberOfPoints) {
val latlng = SphericalUtil.computeOffset(c, r, h1 + i * step)
polygon.add(latlng) //Adding in PolygonOptions
temp.add(latlng) //Storing in temp list to add again in reverse order
}
//iterate the temp list in reverse order and add in PolygonOptions
for (i in (temp.size - 1) downTo 1) {
polygon.add(temp[i])
}
polygon.strokeColor(Color.BLUE)
polygon.strokeWidth(12f)
polygon.strokePattern(listOf(Dash(30f), Gap(50f))) //Skip if you want solid line
googleMap.addPolygon(polygon)
temp.clear() //clear the temp list
}
Why are we adding temp list again in reverse order in PolygonOptions?
If we do not add LatLng again in PolygonOptions in reverse order, the googleMap.addPolygon() will close the path and the final result will be look like below.
TIPS:
If you want the curve is more in circular shape, increase the value of k. like k = 0.75
Thanks #xomena for the solution above. It works beautifully in most cases. But there needs some improvement:
When k == 1, x will be 0 and midpoint (p) will be the same as mid curve point (c). That means it should be a straight line, but then when you calculate the step, it's not Zero so the final result is a half-circle curve, which is ambiguous with the above condition.
When the curve is long enough, let say LIMIT = 1000km, each calculation in h1 + i * step inside the loop make a tiny error to the correct value (due to java double calculation error I guess). Then the start and end points of the polyline not exactly match with start and end coordinations. Moreover, the curvature of the polyline is unpredictable, base on my research, the reason can be the curvature of the Earth's surface that can make your calculation base on heading not correct.
My quick fix is to reset the step to 0 if k == 1 to make it a straight line. For the second problem, if the distance between 2 points is greater than a LIMIT of 1000km, drawing a straight line with k = 1 will be a safer choice to me.

Android, How to check collision between two rotated views

I am trying to randomize the position of a few textviews inside a frameview. The textviews will also have a randomized rotation between 0 and 360 degrees. The textViews is not allowed to be on top of eachother which means I need to check for collisions (or at least know which points that are valid/not valid). I do not know how to check for collision between two textviews when they are rotated. I have tried to use Rect intersects but this does not really work because this function only works if there is no rotation to the view.
Here is an example on what i want:
TEXT1 is placed first. When TEXT2 is placed the green border around the TEXT1 and TEXT2 is colliding which means that TEXT2 should not be allowed to be placed there. TEXT3 does however not collide with anything and should be allowed to be placed. So I want to check the collision for the green border and not the blue rectangle. How do I do this?
Edit
To rotate the view I am using View.setRotation(float)
To position the textview I am using setX(float) and setY(float).
I ended up with the following solution where I create 4 points, one for each corner of the textView, which I then rotate at the same angle as the textView. With these points I then create a Path which I am using to create a region.
private Region createRotatedRegion(TextView textView){
Matrix matrix = new Matrix();
matrix.setRotate(textView.getRotation(), textView.getX() + textView.getMeasuredWidth() / 2, textView.getY() + textView.getMeasuredHeight() / 2);
Path path = new Path();
Point LT = rotatePoint(matrix, textView.getX(), textView.getY());
Point RT = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY());
Point RB = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY() + textView.getMeasuredHeight());
Point LB = rotatePoint(matrix, textView.getX(), textView.getY() + textView.getMeasuredHeight());
path.moveTo(LT.x, LT.y);
path.lineTo(RT.x, RT.y);
path.lineTo(RB.x, RB.y);
path.lineTo(LB.x, LB.y);
Region region = new Region();
region.setPath(path, new Region(0, 0, textViewParent.getWidth(), textViewParent.getHeight()));
return region;
}
private Point rotatePoint(Matrix matrix, float x, float y){
float[] pts = new float[2];
pts[0] = x;
pts[1] = y;
matrix.mapPoints(pts);
return new Point((int)pts[0], (int)pts[1]);
}
When I have two regions which now have the same position and rotation as two textViews I can then use the following code to check for collision:
if (!region1.quickReject(region2) && region1.op(region2, Region.Op.INTERSECT)) {
return true; //There is a collision
}
Probably not the best solution but it gets the job done.

GLSL: How to calculate fragments output RGB value based on Photoshops curve value?

I am working on image editing using OPENGL in Android and I have applied filter to an image using photoshop curve now I want to reproduce the same in Android using glsl. Is there any formula to calculate single fragment color using photoshops curve output value?
EDIT
The math behind the photoshop curve has already been answered in this question
How to recreate the math behind photoshop curves but I am not very clear about how to reproduce the same in glsl fragment shader.
Screen Shot of my photoshop curve
You're after a function fragColour = curves(inColour, constants...). If you have just the one curve for red, green and blue you apply the same curve to each individually. This answer has a link (below) to code which plots points along the function. The key line is:
double y = ...
Which you'd return from curves. The variable x in the loop is your inColour. All you need now is the constants which come from the points and the second derivative sd arrays. These you'll have to pass in as uniforms. The function first has to figure out which point each colour x is between (finding cur, next, sd[i] and sd[i+1]), then evaluate and return y.
EDIT:
If you just want to apply some curve you've created in photoshop then the problem is much simpler. The easiest way is to create a simple function that gives a similar shape. I use these as a starting point. A gamma correction curve is also quite common.
This is overkill, but if you do need a more exact result, you could create an image with a linear ramp (e.g. 255 pixels from black to white), apply your filter to it in photoshop and the result becomes a lookup table. Passing in all 255 values to a shader is expensive so if it's a smooth curve you could try some curve fitting tools (for example).
Once you have a function, simply apply it to your colour in GLSL. Applying a gamma curve for example is done like this:
fragColour = vec4(pow(inColour.rgb, 1.0 / gamma.rgb), inColour.a);
EDIT2:
The curve you have looks very similar to this:
fragColour = vec4(pow(inColour.rgb, 1.0 / vec3(0.6)), inColour.a);
Or even simpler:
fragColour = vec4(inColour.rgb * inColour.rgb, inColour.a);
Just in case the link dies, I'll copy the code here (not that I've tested it):
Point[] points = /* liste de points, triés par "x" croissants */
double[] sd = secondDerivative(points);
for(int i=0;i<points.length-1;i++) {
Point cur = points[i];
Point next = points[i+1];
for(int x=cur.x;x<next.x;x++) {
double t = (double)(x-cur.x)/(next.x-cur.x);
double a = 1-t;
double b = t;
double h = next.x-cur.x;
double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
draw(x,y); /* ou tout autre utilisation */
}
}
And the second derivative:
public static double[] secondDerivative(Point... P) {
int n = P.length;
double yp1=0.0;
double ypn=0.0;
// build the tridiagonal system
// (assume 0 boundary conditions: y2[0]=y2[-1]=0)
double[][] matrix = new double[n][3];
double[] result = new double[n];
matrix[0][1]=1;
for(int i=1;i<n-1;i++) {
matrix[i][0]=(double)(P[i].x-P[i-1].x)/6;
matrix[i][1]=(double)(P[i+1].x-P[i-1].x)/3;
matrix[i][2]=(double)(P[i+1].x-P[i].x)/6;
result[i]=(double)(P[i+1].y-P[i].y)/(P[i+1].x-P[i].x) - (double)(P[i].y-P[i-1].y)/(P[i].x-P[i-1].x);
}
matrix[n-1][1]=1;
// solving pass1 (up->down)
for(int i=1;i<n;i++) {
double k = matrix[i][0]/matrix[i-1][1];
matrix[i][1] -= k*matrix[i-1][2];
matrix[i][0] = 0;
result[i] -= k*result[i-1];
}
// solving pass2 (down->up)
for(int i=n-2;i>=0;i--) {
double k = matrix[i][2]/matrix[i+1][1];
matrix[i][1] -= k*matrix[i+1][0];
matrix[i][2] = 0;
result[i] -= k*result[i+1];
}
// return second derivative value for each point P
double[] y2 = new double[n];
for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
return y2;
}

Move an object on on a Bézier curve path

I want to move my image on a Bézier curve path from top to bottom but I can't get how can I calculate x/y points and slope from this path. The path looks like the following image:
I have start points, end points and two control points.
Path path = new Path();
Point s = new Point(150, 5);
Point cp1 = new Point(140, 125);
Point cp2 = new Point(145, 150);
Point e = new Point(200, 250);
path.moveTo(s.x, s.y);
path.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
Android gives you an API to accomplish what you want. Use the class called android.graphics.PathMeasure. There are two methods you will find useful: getLength(), to retrieve the total length in pixels of the path, and getPosTan(), to retrieve the X,Y position of a point on the curve at a specified distance (as well as the tangent at this location.)
For instance, if getLength() returns 200 and you want to know the X,Y position of the point in the middle of the curve, call getPosTan() with distance=100.
More info: http://developer.android.com/reference/android/graphics/PathMeasure.html
This is a cubic Bézier curve for which the formula is simply [x,y]=(1–t)^3*P0+3(1–t)^2*t*P1+3(1–t)t^2*P2+t^3*P3. With this you can solve for each point by evaluating the equation. In Java this you could do it like this:
/* t is time(value of 0.0f-1.0f; 0 is the start 1 is the end) */
Point CalculateBezierPoint(float t, Point s, Point c1, Point c2, Point e)
{
float u = 1 – t;
float tt = t*t;
float uu = u*u;
float uuu = uu * u;
float ttt = tt * t;
Point p = new Point(s.x * uuu, s.y * uuu);
p.x += 3 * uu * t * c1.x;
p.y += 3 * uu * t * c1.y;
p.x += 3 * u * tt * c2.x;
p.y += 3 * u * tt * c2.y;
p.x += ttt * e.x;
p.y += ttt * e.y;
return p;
}
So if you wanted to move a sprite along the path, then you would simply set the t value from a value of 0 - 1 depending on how far down the path you want to be. Example:
int percentMovedPerFrame = 1;// Will complete path in 100 frames
int currentPercent = 0;
update() {
if (currentPercent < 100) {
this.pos = CalculateBezierPoint(currentPercent / 100.0f, this.path.s, this.path.c1, this.path.c2, this.path.e);
currentPercent += percentMovedPerFrame
}
}
To find a point on a Bezier curve, you can use the De Casteljau algorithm.
See for example http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html or use Google to find some implementations.
If you only have 2 control points, a bezier curve is a linear line.
If you have 3, you have a quadratic curve. 4 control points define a cubic curve.
Bezier curves are functions which depend on "time". It goes from 0.0 - 1.0. If you enter 0 into the equation, you get the value at the beginning of the curve. If you enter 1.0, the value at the end.
Bezier curves interpolate the first and last control points, so those would be your starting and ending points. Look carefully at what package or library you are using to generate the curve.
To orient your image with the tangent vector of the curve, you have to differentiate the curve equation (you can look up the cubic bezier curve equation on wiki). That will give you the tangent vector to orient your image.
Note that changing the parameter in the parametric form of a cubic bezier does not produce linear results. In other words, setting t=0.5 does not give you a point that is halfway along the curve. Depending on the curvature (which is defined by control points) there will be non-linearities along the path.
For anyone who needs to calculate static value points of Bezier curve Bezier curve calculator is a good source. Especially if you use the fourth quadrant (i.e. between X line and -Y line). Then you can completely map it to the Android coordinate system doing mod on negative value.

Categories

Resources