I am building an AR application with unity and Mapbox. I have a point to represents a building. I can geolocate the point through Mapbox. I want to see this object everywhere. So, I change the size of objects according to distance.
Firstly, the code is working. But, I could not see the point really far away, 5 km away.
// Update is called once per frame
void Update()
{
// Get user location
// Latitude
x = getLocation.x1.ToString();
user_lat = Convert.ToDouble(x);
user_lat_rad = Math.PI * user_lat / 180.0; // Radian
// Longitude
y = getLocation.y1.ToString();
user_lon = Convert.ToDouble(y);
user_lon_rad = Math.PI * user_lon / 180.0; // Radian
// Change POIs sizes
distances = distance(user_lat_rad, user_lon_rad);
double s = 0.3; // size of the poi
double d = 50f; // specific distance to point (reference distance)
double size = (distances * s) / d;
float size2 = Convert.ToSingle(size);
temp = transform.localScale;
temp.x = size2;
temp.y = size2;
temp.z = size2;
transform.localScale = temp;
}
public double distance(double lat2, double lon2)
{
// Haversine Formula
// Lat2,Lon2 = User Location
// Lat1,Lon1 = POI Location
double dist1 = Sqrt((Pow(Sin((lat2 - lat1) / 2), 2)) + Cos(lat2) * Cos(lat2) * (Pow(Sin((lon2 - lon1) / 2), 2)));
double distance = 2 * r * Asin(dist1);
return distance;
}
Why I couldn't see the point far away even though object size is change? Is there any limitation for this?
As said in the comments the issue most probably is a too small value for the Camera's farClipPlane.
The furthest point relative to the camera that drawing will occur.
Any object/triangle that is further away from the Camera will not be rendered.
In the Inspector it is configured on the Camera component → Clipping Planes → Far
or using code
cameraReference.farClipPlane = XYZ;
Related
How would it be possible to move the 8 instantiatedObjects "cubes" closer to the pillar.
public void instantiateInCircle()
{
for (int i = 0; i < amount; i++)
{
float radius = 8;
float angle = i * Mathf.PI * 2f / radius;
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
instantiatedObject.transform.parent = spawnAroundThis.transform;
instantiatedObject.transform.localScale = new Vector3(scale, scale, scale);
//this seems to work-ish , not sure if its good math but hey :)
//Thanks BugFinder!
instantiatedObject.transform.position = instantiatedObject.transform.position += instantiatedObject.transform.forward * distance;
}
}
Ideally these could be moved closer to the pillar
Due to the fact your code already points the object towards where you are trying to get closer, you need only move the object forward until its at the correct distance.
Decreasing the value of the radius variable should spawn them closer to the pillar.
Since you are offsetting the cube position from the pillar position by the cosine and sine components of the radius, it will place them correctly spaced around the pillar.
Also, I believe
float angle = i * Mathf.PI * 2f / radius;
Should really be
float angle = i * Mathf.PI * 2f / amount;
The radius should not affect the angle the object is spawned, but the number of objects should.
I want to throw a ball that has a projectile motion. I have a monkey on centre of screen and onTouchBegin I am taking the starting point of the touch and onTouchEnded I am taking the ending points. From the starting and ending points I am taking the angle value between them. Like 30 degrees, 45 or 90 degree.
This is my code by which I have calculated angle of start to endpoint
float angleRadians = atan2(startTouchPoint.x - touchPoint.x, startTouchPoint.y - touchPoint.y);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
Now i am using Projectile motion formula to throw ball with angle i have calculated from above formula .
inside init method
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
and onTouchEnded i have called fire method which will throw ball .
-(void)fire:(ccTime) dt
{
CCLOG(#"Angle 1: %.2f",angle);
gameTime += dt*6;
// x = v0 * t * cos(angle)
X = (V0 * gameTime * cos(angle))/2+120;
// y = v0 * t * sin(angle) - 0.5 * g * t^2
Y = (V0 * gameTime * sin(angle) - 0.5 * gravity * pow(gameTime, 2))/2+255;
if (Y > 50)
{
sprite_webfire.position = ccp(X,Y);
flag = true;
}
else
{
//angleValue += 15;
angleValue = angle;
angle = [self DegreesToRadians:angleValue];
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
// [self pauseSchedulerAndActions];
}
if (Y < 50)
{
[self unschedule:#selector(fire:)];
}
NSLog(#"ball (%lf,%lf), dt = %lf angle value %d", X, Y, dt,angleValue);
}
this code is working . by this code i can throw ball in projectile motion but i cant throw it where i want to. i cant throw wrt to given angle from start to end point.
i can throw it like red mark but i want to throw it blue mark with swipe . but its not throwing like i am swiping screen.
I am not certain on what math you are using to do this, I find your documentation a bit confusing.
Generally, for project tile motion this is what you need to do:
Find out what the take off angle is relative to the horizontal. Then depending on whatever initial velocity you want the object to have, use that and you trig equations to put your initial velocities into rectangular components.
For example:
If initial velocity was 10, the initial velocity in the y direction would be 10sin(angle), and in the x direction it would be 10cos(angle).
Then in to update the position of the sprite you should use kinematics equations: http://www.physicsclassroom.com/class/1dkin/u1l6c.cfm
First update velocities:
Velocity in the Y direction: V = v(initial) + gravity*(Delta-time)
Velocity in the X direction is constant unless you want to factor in some sort of resistance to make things a lot more complicated.
then position y = oldPositionY + velocity(in Y direction)*(Delta-time) + 1/2(gravity)(delta-time)^2.
and position x = oldPositionX + Xvelocity*delta-time
I have done some projectile motion stuff, and I have found you need to make gravity a large constant, something around 500 to make it look life-like. Let me know if this is confusing or you don't know how to implement it.
I would suggest that you take a look at the following tutorial: http://www.raywenderlich.com/4756/how-to-make-a-catapult-shooting-game-with-cocos2d-and-box2d-part-1.
It shows you how to use a physics engine, so you don't need to do much of the math. All the 'bullets' in the tutorial are also moving with projectile motion.
I'll add a bit to what was already said (which was good). Firstly, you should not be wasting time computing any angles. Stick with vectors for your velocity. In other words, get the initial velocity vector from the touch start and end location, and that will be your (v0x, v0y). For example:
CGPoint initialVelocity = ccpSub(touchPoint, startTouchPoint);
float v0x = initialVelocity.x;
float v0y = initialVelocity.y;
If you wish to assign a different magnitude to the initial velocity vector, simply normalize it and then multiply it by a new magnitude.
CGPoint unitVelocity = ccpNormalize(initialVelocity);
float magnitude = 200; // or whatever you want it to be
CGPoint velocity = ccpMult(unitVelocity, magnitude);
Anyway, with this velocity set properly you can then use it in your position calculations as before, but without the added complexity of calculating the angles.
-(void) fire:(ccTime)dt
{
.
.
gameTime += dt;
// if x(t) = x0 + v0x*t, then dx = v0x*dt
x += v0x*dt;
// if y(t) = y0 + v0y*t - 0.5t^2, then dy = v0y*dt - g*t*dt
y += (v0y * dt - g*gameTime*dt);
.
.
}
Also you should not set v0 = 50. Calculate the velocity from the vector as I suggested.
Something important to consider is that you are calculating what the movement should be in a physical world based upon units of meters. The screen is operating in points, not meters, so you will probably have to apply a scaling factor to the new position (x,y) to get the look that you are going for.
Edit: my bad, I had to revisit my math in the position calculation. My differentials was a bit rusty.
I want to calculate the distance that users cover while walking using GPS. For example a user taps the start button and starts to walk or run than when he done he taps stop. What will be the minimum distance user has to travel to get the different lat long?
How can we do it in IPhone, asume we take Lat, long after every 0.3 sec than in the last we have a list of points?
You could do this by calculating the distance between 2 points (latitude, longitude):
(I haven't tested it):
-(double)distanceBetweenCoordinate:(CLLocationCoordinate2D)c1 andCoordinate:(CLLocationCoordinate2D)c2 {
double long1 = degreesToRadians(c1.longitude);
double lat1 = degreesToRadians(90 - c1.latitude);
double long2 = degreesToRadians(c2.longitude);
double lat2 = degreesToRadians(90 - c2.latitude);
double gamma = fabs(long1 - long2);
if (gamma > M_PI) {
gamma = 2 * M_PI - gamma;
}
double result = cos(lat2) * cos(lat1) + sin(lat2) * sin(lat1) * cos(gamma);
return acos(result) * 6366.1977; // Kilometers
};
CGFloat degreesToRadians(CGFloat degrees) {
return degrees * M_PI / 180;
};
UPDATE: Use distanceFromLocation - Calculate distance between two points instead
I'm trying to develop an application that use the GPS and Compass of the iPhone in order to point some sort of pointer to a specific location (like the compass always point to the North). The location is fixed and I always need the pointer to point to that specific location no matter where the user is located. I have the Lat/Long coordinates of this location but not sure how can I point to that location using the Compass and the GPS... just like http://www.youtube.com/watch?v=iC0Xn8hY80w this link 1:20'
I write some code, however, it can't rotate right direction.
-(float) angleToRadians:(double) a {
return ((a/180)*M_PI);
}
-(void)updateArrow {
double alon=[longi doubleValue];//source
double alat=[lati doubleValue];//source
double blon=[pointlongi doubleValue];//destination
double blat=[pointlati doubleValue];//destination
float fLat = [self angleToRadians:alat];
float fLng = [self angleToRadians:alon];
float tLat = [self angleToRadians:blat];
float tLng = [self angleToRadians:blon];
float temp = atan2(sin(tLng-fLng)*cos(tLat),
cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));
double temp2= previousHeading;
double temp1=temp-[self angleToRadians:temp2];
/*I using this,but it can't rotate by :point even i change the coordinate
in CGPointMake */
Compass2.layer.anchorPoint=CGPointMake(0, 0.5);
[Compass2 setTransform:CGAffineTransformMakeRotation(temp1)];
/* Compass2 is a UIImageView like below picture I want to rotate it around
: point in image
^
|
|
|
:
|
*/
There is a standard "heading" or "bearing" equation that you can use - if you are at lat1,lon1, and the point you are interested in is at lat2,lon2, then the equation is:
heading = atan2( sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1))
This gives you a bearing in radians, which you can convert to degrees by multiplying by 180/π. The value is then between -180 and 180 degrees, so to get a standard compass bearing add 360 to any negative answers.
atan2 is a standard function related to arctan, that does the right thing for the four possible quadrants that your destination point could be in compared to where you are.
1) Get your current location (from the GPS)
2) Get the differences in latitude and longitude
3) use the atan2 method to get the angle
i.e. (WARNING: untested code)
CLLocation *targetLocation = [CLLocation alloc] initWithLatitude:1 longitude:2];
CLLocation *sourceLocation = <get from GPS>
double dx = [targetLocation coordinate].latitude - [sourceLocation coordinate].latitude;
double dy = [targetLocation coordinate].longitude - [sourceLocation coordinate].longitude;
double angle = atan2(dx, dy);
You might have to tweak that to get it to compile but the idea is there!
I did this some time ago, here are two different implementations. The first is similar to your approach, the second is without the trig math. The first is what I used in my app, but the second seemed to work as well, though doesn't appear to be as clean. You will need to also remember to offset this bearing based on north in your UI.
- (double) toRadian: (double) val
{
return val * (M_PI / 180);
}
// Convert to degrees from radians
- (double) toDegrees: (double) val
{
return val * 180 / M_PI;
}
// convert from a radian to a 360 degree format.
- (double) toBearing: (double) val
{
return ( (int)([self toDegrees: val]) + 360 ) % 360; // use mod to get the degrees
}
// Calculate the bearing based off of the passed coordinates and destination.
//
- (double) calcBearingWithLatitude:(CLLocationDegrees)latSource
latitude:(CLLocationDegrees)latDest
longitude:(CLLocationDegrees)lonSrc
longitude:(CLLocationDegrees)lonDest
{
double lat1 = [self toRadian:latSource];
double lat2 = [self toRadian:latDest];
double dLon = [self toRadian:(lonDest - lonSrc)];
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
return [self toBearing:atan2(y, x)];
}
And the second.
// got this code from some forums and modified it, thanks for posting it coullis! Mostly here for reference on how to do this without sin and cos.
- (CLLocationDegrees) altCalcBearingWithLatitude:(CLLocationDegrees)latSource
latitude:(CLLocationDegrees)latDest
longitude:(CLLocationDegrees)lonSrc
longitude:(CLLocationDegrees)lonDest
{
CLLocationDegrees result;
// First You calculate Delta distances.
float dx = lonSrc - latSource;
float dy = lonDest - latDest;
// If x part is 0 we could get into division by zero problems, but in that case result can only be 90 or 270:
if (dx==0)
{
if (dy > 0)
result = 90;
else
result = 270;
}
else
{
result = [self toDegrees: atan(dy/dx)];
}
// This is only valid for two quadrants (for right side of the coordinate system) so modify result if necessary...
if (dx < 0)
result = result + 180;
// looks better if all numbers are positive (0 to 360 range)
if (result < 0)
result = result + 360;
// return our result.
return result;
}
Use this. You will have to subtract out your actual compass heading from the result of getHeadingForDirection to determine the proper relative heading. Return value is heading in radians.
-(float) angleToRadians:(float) a {
return ((a/180)*M_PI);
}
- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{
float fLat = [self angleToRadians:fromLoc.latitude];
float fLng = [self angleToRadians:fromLoc.longitude];
float tLat = [self angleToRadians:toLoc.latitude];
float tLng = [self angleToRadians:toLoc.longitude];
return atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));
}
I'm trying to develop an application that use the GPS and Compass of the iPhone in order to point some sort of pointer to a specific location (like the compass always point to the North). The location is fixed and I always need the pointer to point to that specific location no matter where the user is located. I have the Lat/Long coordinates of this location but not sure how can I point to that location using the Compass and the GPS... just like http://www.youtube.com/watch?v=iC0Xn8hY80w this link 1:20'
I write some code, however, it can't rotate right direction.
-(float) angleToRadians:(double) a {
return ((a/180)*M_PI);
}
-(void)updateArrow {
double alon=[longi doubleValue];//source
double alat=[lati doubleValue];//source
double blon=[pointlongi doubleValue];//destination
double blat=[pointlati doubleValue];//destination
float fLat = [self angleToRadians:alat];
float fLng = [self angleToRadians:alon];
float tLat = [self angleToRadians:blat];
float tLng = [self angleToRadians:blon];
float temp = atan2(sin(tLng-fLng)*cos(tLat),
cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));
double temp2= previousHeading;
double temp1=temp-[self angleToRadians:temp2];
/*I using this,but it can't rotate by :point even i change the coordinate
in CGPointMake */
Compass2.layer.anchorPoint=CGPointMake(0, 0.5);
[Compass2 setTransform:CGAffineTransformMakeRotation(temp1)];
/* Compass2 is a UIImageView like below picture I want to rotate it around
: point in image
^
|
|
|
:
|
*/
There is a standard "heading" or "bearing" equation that you can use - if you are at lat1,lon1, and the point you are interested in is at lat2,lon2, then the equation is:
heading = atan2( sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1))
This gives you a bearing in radians, which you can convert to degrees by multiplying by 180/π. The value is then between -180 and 180 degrees, so to get a standard compass bearing add 360 to any negative answers.
atan2 is a standard function related to arctan, that does the right thing for the four possible quadrants that your destination point could be in compared to where you are.
1) Get your current location (from the GPS)
2) Get the differences in latitude and longitude
3) use the atan2 method to get the angle
i.e. (WARNING: untested code)
CLLocation *targetLocation = [CLLocation alloc] initWithLatitude:1 longitude:2];
CLLocation *sourceLocation = <get from GPS>
double dx = [targetLocation coordinate].latitude - [sourceLocation coordinate].latitude;
double dy = [targetLocation coordinate].longitude - [sourceLocation coordinate].longitude;
double angle = atan2(dx, dy);
You might have to tweak that to get it to compile but the idea is there!
I did this some time ago, here are two different implementations. The first is similar to your approach, the second is without the trig math. The first is what I used in my app, but the second seemed to work as well, though doesn't appear to be as clean. You will need to also remember to offset this bearing based on north in your UI.
- (double) toRadian: (double) val
{
return val * (M_PI / 180);
}
// Convert to degrees from radians
- (double) toDegrees: (double) val
{
return val * 180 / M_PI;
}
// convert from a radian to a 360 degree format.
- (double) toBearing: (double) val
{
return ( (int)([self toDegrees: val]) + 360 ) % 360; // use mod to get the degrees
}
// Calculate the bearing based off of the passed coordinates and destination.
//
- (double) calcBearingWithLatitude:(CLLocationDegrees)latSource
latitude:(CLLocationDegrees)latDest
longitude:(CLLocationDegrees)lonSrc
longitude:(CLLocationDegrees)lonDest
{
double lat1 = [self toRadian:latSource];
double lat2 = [self toRadian:latDest];
double dLon = [self toRadian:(lonDest - lonSrc)];
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
return [self toBearing:atan2(y, x)];
}
And the second.
// got this code from some forums and modified it, thanks for posting it coullis! Mostly here for reference on how to do this without sin and cos.
- (CLLocationDegrees) altCalcBearingWithLatitude:(CLLocationDegrees)latSource
latitude:(CLLocationDegrees)latDest
longitude:(CLLocationDegrees)lonSrc
longitude:(CLLocationDegrees)lonDest
{
CLLocationDegrees result;
// First You calculate Delta distances.
float dx = lonSrc - latSource;
float dy = lonDest - latDest;
// If x part is 0 we could get into division by zero problems, but in that case result can only be 90 or 270:
if (dx==0)
{
if (dy > 0)
result = 90;
else
result = 270;
}
else
{
result = [self toDegrees: atan(dy/dx)];
}
// This is only valid for two quadrants (for right side of the coordinate system) so modify result if necessary...
if (dx < 0)
result = result + 180;
// looks better if all numbers are positive (0 to 360 range)
if (result < 0)
result = result + 360;
// return our result.
return result;
}
Use this. You will have to subtract out your actual compass heading from the result of getHeadingForDirection to determine the proper relative heading. Return value is heading in radians.
-(float) angleToRadians:(float) a {
return ((a/180)*M_PI);
}
- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{
float fLat = [self angleToRadians:fromLoc.latitude];
float fLng = [self angleToRadians:fromLoc.longitude];
float tLat = [self angleToRadians:toLoc.latitude];
float tLng = [self angleToRadians:toLoc.longitude];
return atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));
}