How to drag a view, along the circumference of an oval? - iphone

I have an Oval and a view on the circumference of the Oval. When you try to drag the view, the view should be moved only on the circumference of the Oval. How can I achieve this?
Any sample equation would be helpful. Thanks.

CGPoint ovalCenter;
CGSize ovalSize;
- (CGPoint)constrainPointToOval:(CGPoint)point
{
float angle = atan2(point.y - ovalCenter.y, point.x - ovalCenter.x);
return CGPointMake(ovalSize.width * cosf(angle), ovalSize.height * sinf(angle));
}
You'll need to set ovalCenter and ovalSize elsewhere. Then run the touch position through this before setting the location of the view.

I have figured out a solution for getting a constrained drag along the sides of a square.
If anyone can improve the code, or have a better solution, you most welcome.
- (CGPoint) constrainPointToSquare:(CGPoint) point
{
float pi = 3.14159265;
float s1,s2;
CGPoint squareDragPoint;
float squareSize = 200.0;
float angle;
angle = atan2 (point.y - mCenter.y, point.x - mCenter.x);
float x1 = point.x;
float x2 = mCenter.x;
float y1 = point.y;
float y2 = mCenter.y;
if (((3*(pi/4) <= angle && pi >= angle) || (-pi <= angle && -3*(pi/4) >= angle)))//left
{
s1 = y2 - squareSize;
s2 = x2 - squareSize * ((y1-y2)/(x1-x2));
squareDragPoint = CGPointMake(s1, s2);
}
else if (((-(pi/4) <= angle && 0.0 >= angle) || (0.0 <= angle && (pi/4) >= angle))) //right
{
s1 = y2 + squareSize;
s2 = x2 + squareSize * ((y1-y2)/(x1-x2));
squareDragPoint = CGPointMake(s1, s2);
}
else if (((-3*(pi/4) <= angle && -(pi/2) >= angle) || (-(pi/4) >= angle && -(pi/2) <= angle))) //top
{
s1 = x2 - squareSize;
s2 = y2 - squareSize * ((x1-x2)/(y1-y2));
squareDragPoint = CGPointMake(s2, s1);
}
else if (((3*(pi/4) >= angle && (pi/2) <= angle) || (pi/4 <= angle && (pi/2) >= angle))) //bottom
{
s1 = x2 + squareSize;
s2 = y2 + squareSize * ((x1-x2)/(y1-y2));
squareDragPoint = CGPointMake (s2, s1);
}
return squareDragPoint;
}

Related

Finding Line segment-Rectangle intersection point

Simply put, I have:
A viewport rectangle where (0,0) is the bottom-left corner, (1,1) is the top-right and (0.5,0.5) is the centre of the screen.
A point (a,b) which is outside of the rectangle.
This is in viewport coordinates so +X is right, +Y is up on the screen.
And I need a function which takes these parameters and returns the point on the edge of the rectangle where the line (between the centre of the rectangle (0.5,0.5) and the point (a,b)) intersects it.
I know how to do this on paper with given coordinates but I just can't figure it out when it comes down to code. Also, I realise questions like this have been addressed in different threads - but I can't find a simple input to output function anywhere.
I'm doing this in the Unity3D engine so preferably in Javascript but any language or pseudocode would be a great help as I can probably hand convert it.
EDIT
To clarify, I'm looking for something like:
function IntersectFromViewportCenter(x : float, y : float) {
...
return Point(x1, y1);
}
Where (x,y) is the point outside of the circle and (x1,y1) is the intersection point.
Thanks
Shift all system to be centered at point (0,0). Calc intersection of ray from origin to (shifted) point (x',y') with box (-1,-1)-(1,1). Scale and shift back. I did not consider trivial case with point inside the box ( is it needed?)
x = x - 0.5
y = y - 0.5
if Abs(x) >= Abs(y) then //vertical box edge
y1 = y/x //care with case both y and x = 0
x1 = Sign(x) //+-1
else // horizontal edge
x1 = x/y
y1 = Sign(y)
x1 = 0.5*x1 + 0.5
y1 = 0.5*y1 + 0.5
Since some general Line/Rect approaches have been provided, here is an approach that is optimized to avoid Raycasts in trivial cases (completely inside or completely outside the Rect): https://gist.github.com/JohannesMP/50dad3175bf2925df508b642091e41c4
It also efficiently provides both the entry and exit point (necessary in my use case):
Here is a basic overview of this approach:
Divide the area around the rect into Sectors as follows (Where S4 is the rect itself):
S0| S1 |S2
--+----+-- ^
S3| S4 |S5 |
--+----+-- y
S6| S7 |S8 x-->
Given the sectors where the line segment begins and ends, we know what raycasts need to be performed (Ex: S0-S2 never needs to raycast, while S4-S1 only needs to raycast the top edge, etc)
Pre-compute this data and store it in a small 9x9 static array. We are basically using a bit of static memory to avoid conditional checks.
At runtime find the Sector that the start and end points of the line occupy, and use the result to Raycast only the necessary edges of the Rect.
Additionally you can simplify the raycast into one dimension if you handle vertical and horizontal lines separately.
In my personal use case (lots of line segments, where the vast majority are either completely inside or completely outside the Rect) this approach is faster than the general case, since Raycasts are only performed when necessary.
MBo has the right idea. Here's a way to implement in in Unity. I don't think UnityScript is worth using – in particular, it doesn't support extension methods – so you really should switch languages. (Also, Unity is actually not named Unity3D.)
This script can go anywhere in the Project:
using UnityEngine;
public static class UnityEngineExtensions {
public static Vector2 Abs(this Vector2 vector) {
for (int i = 0; i < 2; ++i) vector[i] = Mathf.Abs(vector[i]);
return vector;
}
public static Vector2 DividedBy(this Vector2 vector, Vector2 divisor) {
for (int i = 0; i < 2; ++i) vector[i] /= divisor[i];
return vector;
}
public static Vector2 Max(this Rect rect) {
return new Vector2(rect.xMax, rect.yMax);
}
public static Vector2 IntersectionWithRayFromCenter(this Rect rect, Vector2 pointOnRay) {
Vector2 pointOnRay_local = pointOnRay - rect.center;
Vector2 edgeToRayRatios = (rect.Max() - rect.center).DividedBy(pointOnRay_local.Abs());
return (edgeToRayRatios.x < edgeToRayRatios.y) ?
new Vector2(pointOnRay_local.x > 0 ? rect.xMax : rect.xMin,
pointOnRay_local.y * edgeToRayRatios.x + rect.center.y) :
new Vector2(pointOnRay_local.x * edgeToRayRatios.y + rect.center.x,
pointOnRay_local.y > 0 ? rect.yMax : rect.yMin);
}
}
Attach this other script to a Game Object, and set its variables in the Inspector.
#pragma warning disable 0649
using System;
using UnityEngine;
public class VisualizeRectIntersectionWithRayFromCenter : MonoBehaviour {
[SerializeField] Rect rect;
[SerializeField] Vector2 point;
[Serializable] class Colors {
public Color rect, point, intersection;
} [SerializeField] Colors colors;
void OnDrawGizmos() {
Gizmos.color = colors.rect;
Vector2[] corners = {new Vector2(rect.xMin, rect.yMin), new Vector2(rect.xMin, rect.yMax),
rect.Max(), new Vector2(rect.xMax, rect.yMin)};
int i = 0;
while (i < 3) Gizmos.DrawLine(corners[i], corners[++i]);
Gizmos.DrawLine(corners[3], corners[0]);
Gizmos.color = colors.point;
Gizmos.DrawLine(rect.center, point);
Gizmos.color = colors.intersection;
Gizmos.DrawLine(rect.center, rect.IntersectionWithRayFromCenter(pointOnRay: point));
}
}
bool LineRectIntersection(Vector2 lineStartPoint, Vector2 lineEndPoint, Rect rectangle, ref double resultX, ref double resultY)
{
Vector2 minXLinePoint = (lineStartPoint.x <= lineEndPoint.x) ? (lineStartPoint) : (lineEndPoint);
Vector2 maxXLinePoint = (lineStartPoint.x <= lineEndPoint.x) ? (lineEndPoint) : (lineStartPoint);
Vector2 minYLinePoint = (lineStartPoint.y <= lineEndPoint.y) ? (lineStartPoint) : (lineEndPoint);
Vector2 maxYLinePoint = (lineStartPoint.y <= lineEndPoint.y) ? (lineEndPoint) : (lineStartPoint);
double rectMaxX = rectangle.xMax;
double rectMinX = rectangle.xMin;
double rectMaxY = rectangle.yMax;
double rectMinY = rectangle.yMin;
if (minXLinePoint.x <= rectMaxX && rectMaxX <= maxXLinePoint.x)
{
double m = (maxXLinePoint.y - minXLinePoint.y) / (maxXLinePoint.x - minXLinePoint.x);
double intersectionY = ((rectMaxX - ((double)minXLinePoint.x)) * m) + ((double)minXLinePoint.y);
if(minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y)
{
resultX = rectMaxX;
resultY = intersectionY;
return true;
}
}
if (minXLinePoint.x <= rectMinX && rectMinX <= maxXLinePoint.x)
{
double m = (maxXLinePoint.y - minXLinePoint.y) / (maxXLinePoint.x - minXLinePoint.x);
double intersectionY = ((rectMinX - ((double)minXLinePoint.x)) * m) + ((double)minXLinePoint.y);
if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y)
{
resultX = rectMinX;
resultY = intersectionY;
return true;
}
}
if (minYLinePoint.y <= rectMaxY && rectMaxY <= maxYLinePoint.y)
{
double rm = (maxYLinePoint.x - minYLinePoint.x) / (maxYLinePoint.y - minYLinePoint.y);
double intersectionX = ((rectMaxY - ((double)minYLinePoint.y)) * rm) + ((double)minYLinePoint.x);
if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x)
{
resultX = intersectionX;
resultY = rectMaxY;
return true;
}
}
if (minYLinePoint.y <= rectMinY && rectMinY <= maxYLinePoint.y)
{
double rm = (maxYLinePoint.x - minYLinePoint.x) / (maxYLinePoint.y - minYLinePoint.y);
double intersectionX = ((rectMinY - ((double)minYLinePoint.y)) * rm) + ((double)minYLinePoint.x);
if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x)
{
resultX = intersectionX;
resultY = rectMinY;
return true;
}
}
return false;
}
#chakmeshma, your solution is almost correct, but you must also check whether the intersection point is within the rect to avoid border cases:
private static bool LineRectIntersection(Vector2 lineStartPoint, Vector2 lineEndPoint, Rect rectangle, ref Vector2 result)
{
Vector2 minXLinePoint = lineStartPoint.x <= lineEndPoint.x ? lineStartPoint : lineEndPoint;
Vector2 maxXLinePoint = lineStartPoint.x <= lineEndPoint.x ? lineEndPoint : lineStartPoint;
Vector2 minYLinePoint = lineStartPoint.y <= lineEndPoint.y ? lineStartPoint : lineEndPoint;
Vector2 maxYLinePoint = lineStartPoint.y <= lineEndPoint.y ? lineEndPoint : lineStartPoint;
double rectMaxX = rectangle.xMax;
double rectMinX = rectangle.xMin;
double rectMaxY = rectangle.yMax;
double rectMinY = rectangle.yMin;
if (minXLinePoint.x <= rectMaxX && rectMaxX <= maxXLinePoint.x)
{
double m = (maxXLinePoint.y - minXLinePoint.y) / (maxXLinePoint.x - minXLinePoint.x);
double intersectionY = ((rectMaxX - minXLinePoint.x) * m) + minXLinePoint.y;
if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y
&& rectMinY <= intersectionY && intersectionY <= rectMaxY)
{
result = new Vector2((float)rectMaxX, (float)intersectionY);
return true;
}
}
if (minXLinePoint.x <= rectMinX && rectMinX <= maxXLinePoint.x)
{
double m = (maxXLinePoint.y - minXLinePoint.y) / (maxXLinePoint.x - minXLinePoint.x);
double intersectionY = ((rectMinX - minXLinePoint.x) * m) + minXLinePoint.y;
if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y
&& rectMinY <= intersectionY && intersectionY <= rectMaxY)
{
result = new Vector2((float)rectMinX, (float)intersectionY);
return true;
}
}
if (minYLinePoint.y <= rectMaxY && rectMaxY <= maxYLinePoint.y)
{
double rm = (maxYLinePoint.x - minYLinePoint.x) / (maxYLinePoint.y - minYLinePoint.y);
double intersectionX = ((rectMaxY - minYLinePoint.y) * rm) + minYLinePoint.x;
if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x
&& rectMinX <= intersectionX && intersectionX <= rectMaxX)
{
result = new Vector2((float)intersectionX, (float)rectMaxY);
return true;
}
}
if (minYLinePoint.y <= rectMinY && rectMinY <= maxYLinePoint.y)
{
double rm = (maxYLinePoint.x - minYLinePoint.x) / (maxYLinePoint.y - minYLinePoint.y);
double intersectionX = ((rectMinY - minYLinePoint.y) * rm) + minYLinePoint.x;
if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x
&& rectMinX <= intersectionX && intersectionX <= rectMaxX)
{
result = new Vector2((float)intersectionX, (float)rectMinY);
return true;
}
}
return false;
}
}

Rotate an image to direct to a well know point using compass heading

As a proof of concept, I want to create an application that retrieve the current coordinates, calculate the direction towards an another point and, using compass, rotate an arrow image to direct to that point in space.
I know how to retrieve current coordinate and to rotate the image through CGAffineTransformMakeRotation, but I haven't find a formula to calculate the correct angle.
Any hints?
First you need to calculate a bearing. This page gives a neat formula for doing that:
http://www.movable-type.co.uk/scripts/latlong.html
Then, you can do some simple arithmetic to find the difference between that bearing and the heading the iPhone is pointed towards. Rotate your image by that difference.
Bearing is:
double bearingUsingStartCoordinate(CLLocation *start, CLLocation *end)
{
double tc1;
tc1 = 0.0;
//dlat = lat2 - lat1
//CLLocationDegrees dlat = end.coordinate.latitude - start.coordinate.latitude;
//dlon = lon2 - lon1
CLLocationDegrees dlon = end.coordinate.longitude - start.coordinate.longitude;
//y = sin(lon2-lon1)*cos(lat2)
double y = sin(d2r(dlon)) * cos(d2r(end.coordinate.latitude));
//x = cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1)
double x = cos(d2r(start.coordinate.latitude))*sin(d2r(end.coordinate.latitude)) - sin(d2r(start.coordinate.latitude))*cos(d2r(end.coordinate.latitude))*cos(d2r(dlon));
if (y > 0)
{
if (x > 0)
tc1 = r2d(atan(y/x));
if (x < 0)
tc1 = 180 - r2d(atan(-y/x));
if (x == 0)
tc1 = 90;
} else if (y < 0)
{
if (x > 0)
tc1 = r2d(-atan(-y/x));
if (x < 0)
tc1 = r2d(atan(y/x)) - 180;
if (x == 0)
tc1 = 270;
} else if (y == 0)
{
if (x > 0)
tc1 = 0;
if (x < 0)
tc1 = 180;
if (x == 0)
tc1 = nan(0);
}
if (tc1 < 0)
tc1 +=360.0;
return tc1;
}
And for those looking for the distance between two points:
double haversine_km(double lat1, double long1, double lat2, double long2)
{
double dlong = d2r(long2 - long1);
double dlat = d2r(lat2 - lat1);
double a = pow(sin(dlat/2.0), 2) + cos(d2r(lat1)) * cos(d2r(lat2)) * pow(sin(dlong/2.0), 2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));
double d = 6367 * c;
return d;
}
double haversine_mi(double lat1, double long1, double lat2, double long2)
{
double dlong = d2r(long2 - long1);
double dlat = d2r(lat2 - lat1);
double a = pow(sin(dlat/2.0), 2) + cos(d2r(lat1)) * cos(d2r(lat2)) * pow(sin(dlong/2.0), 2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));
double d = 3956 * c;
return d;
}

Box2d Calculating Trajectory

I'm trying to make physics bodies generated at a random position with a random velocity hit a target. I gleaned and slightly modified this code from the web that was using chipmunk to run in Box2d
+ (CGPoint) calculateShotForTarget:(CGPoint)target from:(CGPoint) launchPos with:(float) velocity
{
float xp = target.x - launchPos.x;
float y = target.y - launchPos.y;
float g = 20;
float v = velocity;
float angle1, angle2;
float tmp = pow(v, 4) - g * (g * pow(xp, 2) + 2 * y * pow(v, 2));
if(tmp < 0){
NSLog(#"No Firing Solution");
}else{
angle1 = atan2(pow(v, 2) + sqrt(tmp), g * xp);
angle2 = atan2(pow(v, 2) - sqrt(tmp), g * xp);
}
CGPoint direction = CGPointMake(cosf(angle1),sinf(angle1));
CGPoint force = CGPointMake(direction.x * v, direction.y * v);
NSLog(#"force = %#", NSStringFromCGPoint(force));
NSLog(#"direction = %#", NSStringFromCGPoint(direction));
return force;
}
The problem is I don't know how to apply this to my program, I have a gravity of -20 for y but putting 20 for g and a lower velocity like 10 for v gets me nothing but "No Firing Solution".
What am I doing wrong?
A lower velocity of 10 is never going to work the projectile doesn't have enough power to travel the distance.
The error in the calculation is that everything is in meters except for the distance calculations which are in pixels!
Changing the code to this fixed the crazy velocities i was getting:
+ (CGPoint) calculateShotForTarget:(CGPoint)target from:(CGPoint) launchPos with:(float) velocity
{
float xp = (target.x - launchPos.x) / PTM_RATIO;
float y = (target.y - launchPos.y) / PTM_RATIO;
float g = 20;
float v = velocity;
float angle1, angle2;
float tmp = pow(v, 4) - g * (g * pow(xp, 2) + 2 * y * pow(v, 2));
if(tmp < 0){
NSLog(#"No Firing Solution");
}else{
angle1 = atan2(pow(v, 2) + sqrt(tmp), g * xp);
angle2 = atan2(pow(v, 2) - sqrt(tmp), g * xp);
}
CGPoint direction = CGPointMake(cosf(angle1),sinf(angle1));
CGPoint force = CGPointMake(direction.x * v, direction.y * v);
NSLog(#"force = %#", NSStringFromCGPoint(force));
NSLog(#"direction = %#", NSStringFromCGPoint(direction));
return force;
}

2d collision between line and a point

Im trying to understanding collision detection in 2d world. I recently got this tutorials http://www.gotoandplay.it/_articles/2003/12/bezierCollision.php. I have question which puzzled me a lot - on the flash demo ball is dropping without responding if i try to swap the starting and end point.
Can someone explain me , how the simulation works.
I have modified this the sample code. It works perfect until the start and end point are swapped, Here is same code in objective c
Thanks in advance. .
-(void)render:(ccTime)dt {
if(renderer)
{
CGPoint b = ball.position;
float bvx = ball.vx;
float bvy = ball.vy;
bvx += .02;
bvy -= .2;
b.x += bvx;
b.y += bvy;
float br = ball.contentSize.width/2;
for ( int p = 0 ; p < [map count] ; p++ ) {
line *l = [map objectAtIndex:p];
CGPoint p0 = l.end;
CGPoint p1 = l.start;
float p0x = p0.x, p0y = p0.y, p1x = p1.x, p1y = p1.y;
// get Angle //
float dx = p0x - p1x;
float dy = p0y - p1y;
float angle = atan2( dy , dx );
float _sin = sin ( angle );
float _cos = cos ( angle );
// rotate p1 ( need only 'x' ) //
float p1rx = dy * _sin + dx * _cos + p0x;
// rotate ball //
float px = p0x - b.x;
float py = p0y - b.y;
float brx = py * _sin + px * _cos + p0x;
float bry = py * _cos - px * _sin + p0y;
float cp = ( b.x - p0x ) * ( p1y - p0y ) - ( b.y - p0y ) * ( p1x - p0x );
if ( bry > p0y - br && brx > p0x && brx < p1rx && cp > 0 ) {
// calc new Vector //
float vx = bvy * _sin + bvx * _cos;
float vy = bvy * _cos - bvx * _sin;
vy *= -.8;
vx *= .98;
float __sin = sin ( -angle );
float __cos = cos ( -angle );
bvx = vy * __sin + vx * __cos;
bvy = vy * __cos - vx * __sin;
// calc new Position //
bry = p0y - br;
dx = p0x - brx;
dy = p0y - bry;
b.x = dy * __sin + dx * __cos + p0x;
b.y = dy * __cos - dx * __sin + p0y;
}
}
ball.position = b;
ball.vx = bvx;
ball.vy = bvy;
if ( b.y < 42)
{
ball.position = ccp(50, size.height - 42);
ball.vx = .0f;
ball.vy = .0f;
}
}
}
The order of the points defines an orientation on the curve. If the start point is on the left and the end point on the right, then the curve is oriented so that "up" points above the curve. However, if you swap the start/end points the curve is oppositely oriented, so now "up" actually points below the curve.
When your code detects a collision and then corrects the velocity it is using the curve's orientation. That is why when the ball drops on the curve with the start/end points swapped it appears to jump through the curve.
To correct this your collision resolution code should check which side of the curve the ball is on (with respect to the curve's orientation), and adjust accordingly.
If you swap l.end and l.start it will serve for line without the segment (l.start, l.end). This is because all values are signed here.
Algorithm turns the plane so that line is horizontal and one of the segment ends doesn't move. After that it is easy to understand whether the ball touches the line. And if it does, its speed should change: in rotated plane it just reverses y-coordinate and we should rotate it back to get line not horizontal again.
In fact not a very good implementation. All this can be done without sin, cos, just vectors.

OpenGL Projection matrix won't allow displaying anything

I'm trying to get some basic OpenGL-ES with Shaders to run on the iPhone, based on some examples.
For some reason my projection matrix refuses to result in something on the screen. It feels like a clipping plane is set very near but that contradicts with the values I supply. If I render the same scene with an Orthogonal projection matrix I see my object just no perspective obviously.
Here's the code that generates the projection matrix:
esPerspective(&proj, 45.f, 768.0/1024.0, 1.f, 10000.f);
void esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ)
{
float frustumW, frustumH;
frustumH = tanf( fovy / 360.0f * PI ) * nearZ;
frustumW = frustumH * aspect;
esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ );
}
void esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
{
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
ESMatrix frust;
if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
(deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
return;
frust.m[0][0] = 2.0f * nearZ / deltaX;
frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
frust.m[1][1] = 2.0f * nearZ / deltaY;
frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
frust.m[2][0] = (right + left) / deltaX;
frust.m[2][1] = (top + bottom) / deltaY;
frust.m[2][2] = -(nearZ + farZ) / deltaZ;
frust.m[2][3] = -1.0f;
frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
esMatrixMultiply(result, &frust, result);
}
My projection matrix comes out as:
[3.21, 0, 0, 0]
[0, 2.41, 0, 0]
[0, 0, -1, -1]
[0, 0, -2, 0]
Even if I manually set the [3][3] cell to 1 I still don't see anything.
Any ideas?
Swap your rows and columns over (ie transpose).
Well your projection matrix is transposed either way. You have a row major projection matrix ...