How to create an own struct and constants for this struct? - objective-c

I want to create a struct which is like a CGPoint, but with 3 coordinates instead of 2.
I create it in the following way:
typedef struct {CGFloat x;CGFloat y;CGFloat z;} CG3Vector;
CG_INLINE CG3Vector CG3VectorMake(CGFloat x, CGFloat y, CGFloat z)
{
CG3Vector p; p.x = x; p.y = y; p.z = z; return p;
}
It works fine. But I now want to improve this struct so that it has the constants like for CGPoint: CGPointZero
Also what is the way to introduce the limits for particular components of the struct, like it is for the CGSize, where components are never lower than 0?
Thanks.

You could create constants like this:
const CG3Vector CG3VectorZero = { 0, 0, 0 };
If you want limits, I suppose you can do some checking like this:
CG_INLINE CG3Vector CG3VectorMake(CGFloat x, CGFloat y, CGFloat z)
{
// normalize the values
x = fmod(x, 360);
y = fmod(y, 360);
z = fmod(z, 360);
x = (x < 0) ? 360 + x : x;
y = (y < 0) ? 360 + y : y;
z = (z < 0) ? 360 + z : z;
return (CG3Vector) { x, y, z };
}

Related

How to limit floats generated by Quickcheck to a range?

I would like to generate random floats for Quickcheck that are limited to a certain range such as 0.0 to 1.0 for testing functions working on probabilities. I would like to be able to do something where this would be successful:
quickcheck! {
fn prop(x: f64, y: f64) -> bool {
assert!(x <= 1.0);
assert!(y <= 1.0);
(x * y < x) && (x * y < y)
}
}
Create a new type that represents your desired range, then implement quickcheck::Arbitrary for it:
#[macro_use]
extern crate quickcheck;
#[derive(Debug, Copy, Clone)]
struct Probability(f64);
impl quickcheck::Arbitrary for Probability {
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
Probability(g.gen_range(0.0, 1.0))
}
}
quickcheck! {
fn prop(x: Probability, y: Probability) -> bool {
let x = x.0;
let y = y.0;
assert!(x <= 1.0);
assert!(y <= 1.0);
(x * y < x) && (x * y < y)
}
}
Arbitrary is passed a type that implements quickcheck::Gen, which is a light wrapper on top of rand::Rng.
Note that Rng::gen_range has an exclusive upper bound, so this example isn't exactly what you want, but it shows the process.
Implementing Arbitrary for a new type is still probably the best way to do this, but gen_range() is now a private method, so you can't use that. As pointed out by the crate's author, you can use the modulus to restrict values to a range.
You can even do this without creating a new type (note that I'm using newer Rust syntax and the quickcheck_macros crate):
#[quickcheck]
fn prop(x: f64, y: f64) -> bool {
let x = x.abs() % 1.0;
let y = y.abs() % 1.0;
assert!(x <= 1.0);
assert!(y <= 1.0);
(x * y < x) && (x * y < y)
}
However, when it fails, it will report the original values of x and y, not the modified ones. So for better test failure reporting, you should use this in code similar to #Shepmaster's:
#[derive(Debug, Copy, Clone)]
struct Probability(f64);
impl quickcheck::Arbitrary for Probability {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Probability(f64::arbitrary(g).abs() % 1.0)
}
}
#[quickcheck]
fn prop2(x: Probability, y: Probability) {
let x = x.0;
let y = y.0;
// ...
}
Of course, once you do all this, you'll notice your code failing for two reasons:
Since x and y could be exactly equal to 1.0, that means it's not a strict inequality. The true comparison should actually be (x * y <= x) && (x * y <= y).
f64::arbitrary can return NaN. If you want to skip NaNs, you could do that by either:
Returning quickcheck::TestCase from prop(), and returning TestCase::discard() if it sees a NaN input, or:
Looping inside Probability::arbitrary until you generate a non-NaN number.

Bezier path see if it crosses

I have a code that lets the user draw a shape, I'm using UIBezierPath for this. But I need to see if the shape crosses itself, for example like this: http://upload.wikimedia.org/wikipedia/commons/0/0f/Complex_polygon.svg
Then it's not a a valid shape.
How can I find this?
Edit:
I still haven't solved this. I save all the points between the lines in the path in a array. And then I loop through the array and try to find if any lines intersects. But it does not work, sometimes it says that there is an intersection when it isn't.
I think that the problem is somewhere in this method.
-(BOOL)pathIntersects:(double *)x:(double *)y {
int count = pathPoints.count;
CGPoint p1, p2, p3, p4;
for (int a=0; a<count; a++) {
//Line 1
if (a+1<count) {
p1 = [[pathPoints objectAtIndex:a] CGPointValue];
p2 = [[pathPoints objectAtIndex:a+1] CGPointValue];
}else{
return NO;
}
for (int b=0; b<count; b++) {
//Line 2
if (b+1<count) {
p3 = [[pathPoints objectAtIndex:b] CGPointValue];
p4 = [[pathPoints objectAtIndex:b+1] CGPointValue];
}else{
return NO;
}
if (!CGPointEqualToPoint(p1, p3) && !CGPointEqualToPoint(p2, p3) && !CGPointEqualToPoint(p4, p1) && !CGPointEqualToPoint(p4, p2)
&& !CGPointEqualToPoint(p1, p2) && !CGPointEqualToPoint(p3, p4)) {
if (LineIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, x, y)) {
return YES;
}
}
}
}
return NO;
}
This is the code I found to see if two lines intersects, It's in C but I should work.
int LineIntersect(
double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4,
double *x, double *y)
{
double mua,mub;
double denom,numera,numerb;
denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1);
numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
/* Are the line coincident? */
if (ABS(numera) < 0.00001 && ABS(numerb) < 0.00001 && ABS(denom) < 0.00001) {
*x = (x1 + x2) / 2;
*y = (y1 + y2) / 2;
return(TRUE);
}
/* Are the line parallel */
if (ABS(denom) < 0.00001) {
*x = 0;
*y = 0;
return(FALSE);
}
/* Is the intersection along the the segments */
mua = numera / denom;
mub = numerb / denom;
if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
*x = 0;
*y = 0;
return(FALSE);
}
*x = x1 + mua * (x2 - x1);
*y = y1 + mua * (y2 - y1);
return(TRUE);
}
It depends on how complex the polygon drawn by the user can be and the number of points in the path. Ideally, there would be a point for all the vertices in the shape and nothing more. Get a CGPath from the UIBezierPath and use GCPathApply to hand the elements to a function, which adds each point to an array. Traverse the array with two for loops, one nested in the other, which checks each line segment against every line segment after it using a standard line-line intersection test. As soon as an intersection has been found, break from the loop. Or, if this were a convenience method, return a BOOL. That's the simplest way.
EDIT: Here's an example of a line-line intersection function which returns a BOOL telling you whether or not two segments cross. Pass in the two points that create the first segment followed by the two points that make the second segment. It was hastily modified from a piece of source code I found online quickly, but it works.
CGPoint lineSegmentsIntersect(CGPoint L1P1, CGPoint L1P2, CGPoint L2P1, CGPoint L2P2)
{
float x1 = L1P1.x, x2 = L1P2.x, x3 = L2P1.x, x4 = L2P2.x;
float y1 = L1P1.y, y2 = L1P2.y, y3 = L2P1.y, y4 = L2P2.y;
float bx = x2 - x1;
float by = y2 - y1;
float dx = x4 - x3;
float dy = y4 - y3;
float b_dot_d_perp = bx * dy - by * dx;
if(b_dot_d_perp == 0) {
return NO;
}
float cx = x3 - x1;
float cy = y3 - y1;
float t = (cx * dy - cy * dx) / b_dot_d_perp;
if(t < 0 || t > 1) {
return NO;
}
float u = (cx * by - cy * bx) / b_dot_d_perp;
if(u < 0 || u > 1) {
return NO;
}
return YES;
}
You can use it like this.
if (lineSegmentsIntersect(lineOnePointOne,lineOnePointTwo,lineTwoPointOne,lineTwoPointTwo)){
//segments intersect
} else {
//segments did not intersect
}
It's up to you to create the double loop to check the correct segments against one another.

I don't understand the -(CGAffineTransform) nodeToParentTransform on Cocos2D+Box2D example

I write this question because I don't understand a piece of code in an example provided by Cocos2D for iPhone:
-(CGAffineTransform) nodeToParentTransform
{
b2Vec2 pos = body_->GetPosition();
float x = pos.x * PTM_RATIO;
float y = pos.y * PTM_RATIO;
if ( ignoreAnchorPointForPosition_ ) {
x += anchorPointInPoints_.x;
y += anchorPointInPoints_.y;
}
// Make matrix
float radians = body_->GetAngle();
float c = cosf(radians);
float s = sinf(radians);
if( ! CGPointEqualToPoint(anchorPointInPoints_, CGPointZero) ){
x += c*-anchorPointInPoints_.x + -s*-anchorPointInPoints_.y;
y += s*-anchorPointInPoints_.x + c*-anchorPointInPoints_.y;
}
// Rot, Translate Matrix
transform_ = CGAffineTransformMake( c, s,
-s, c,
x, y );
return transform_;
}
It's in the PhysicsSprite.mm file.
Maybe it's because I'm very bad with space geometry, but if someone can explain me, I very appreciate.
Thanks a lot.
if( ! CGPointEqualToPoint(anchorPointInPoints_, CGPointZero) ){
x += c*-anchorPointInPoints_.x + -s*-anchorPointInPoints_.y;
y += s*-anchorPointInPoints_.x + c*-anchorPointInPoints_.y;
}
The above piece of code simply rotates the xy coordinate axes anticlockwise by $180-\theta$
degrees, and adds the new coordinates to the previous x,y coordinates that were obtained from the piece of code before the above mentioned lines.
http://en.wikipedia.org/wiki/Rotation_of_axes provides the rotation of axes formula

How to calculate points on a circle on the globe centred on GPS coordinates?

Draw a circle in KML
How do you take the GPS coordinates of a point on the globe (say in decimal degree format) and generate the coordinates for a polygon approximating a circle centred on that point?
A polygon with 20+ data points looks like a circle. The more data points - the better looking the circle.
I am writing a program that will generate KML and dont know how to calculate the coordinates of the polygon vertices.
Example of data inputs:
Latitude, Longitude, Circle radius (in feet), NumberOfDataPoints
26.128477, -80.105149, 500, 20
I don't know if this is the simplest solution and it assumes the world is a sphere.
Define:
R is the radius of the sphere (i.e. the earth).
r is the radius of the circle (in the same units).
t is the angle subtended by a great-circle arc of length r at the centre of the sphere so t=r/R radians.
Now suppose the sphere has radius 1 and is centred at the origin.
C is a unit vector representing the centre of the circle.
Imagine a circle round the North pole and consider the point where the plane of the circle intersects the line from the centre of the earth to the North pole. Clearly this point will be somewhere below the North pole.
K is the corresponding point "below" C (i.e. where the plane of your circle intersects C) so K=cos(t)C
s is the radius of the circle measured in 3D space (i.e. not on the sphere) so s=sin(t)
Now we want points on the circle in 3D space with centre K, radius s and lying in the plane passing through and perpendicular to K.
This answer (ignore the rotation stuff) explains how to find a basis vector for the plane (i.e. a vector orthogonal to the normal K or C). Use the cross product to find a second.
Call these basis vectors U and V.
// Pseudo-code to calculate 20 points on the circle
for (a = 0; a != 360; a += 18)
{
// A point on the circle and the unit sphere
P = K + s * (U * sin(a) + V * cos(a))
}
Convert each point to spherical coordinates and you are done.
Being bored, I coded this up in C#. The results are plausible: they are in a circle and lie on the sphere. Most of the code implements a struct representing a vector. The actual calculation is very simple.
using System;
namespace gpsCircle
{
struct Gps
{
// In degrees
public readonly double Latitude;
public readonly double Longtitude;
public Gps(double latitude, double longtitude)
{
Latitude = latitude;
Longtitude = longtitude;
}
public override string ToString()
{
return string.Format("({0},{1})", Latitude, Longtitude);
}
public Vector ToUnitVector()
{
double lat = Latitude / 180 * Math.PI;
double lng = Longtitude / 180 * Math.PI;
// Z is North
// X points at the Greenwich meridian
return new Vector(Math.Cos(lng) * Math.Cos(lat), Math.Sin(lng) * Math.Cos(lat), Math.Sin(lat));
}
}
struct Vector
{
public readonly double X;
public readonly double Y;
public readonly double Z;
public Vector(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public double MagnitudeSquared()
{
return X * X + Y * Y + Z * Z;
}
public double Magnitude()
{
return Math.Sqrt(MagnitudeSquared());
}
public Vector ToUnit()
{
double m = Magnitude();
return new Vector(X / m, Y / m, Z / m);
}
public Gps ToGps()
{
Vector unit = ToUnit();
// Rounding errors
double z = unit.Z;
if (z > 1)
z = 1;
double lat = Math.Asin(z);
double lng = Math.Atan2(unit.Y, unit.X);
return new Gps(lat * 180 / Math.PI, lng * 180 / Math.PI);
}
public static Vector operator*(double m, Vector v)
{
return new Vector(m * v.X, m * v.Y, m * v.Z);
}
public static Vector operator-(Vector a, Vector b)
{
return new Vector(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
}
public static Vector operator+(Vector a, Vector b)
{
return new Vector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
public override string ToString()
{
return string.Format("({0},{1},{2})", X, Y, Z);
}
public double Dot(Vector that)
{
return X * that.X + Y * that.Y + Z * that.Z;
}
public Vector Cross(Vector that)
{
return new Vector(Y * that.Z - Z * that.Y, Z * that.X - X * that.Z, X * that.Y - Y * that.X);
}
// Pick a random orthogonal vector
public Vector Orthogonal()
{
double minNormal = Math.Abs(X);
int minIndex = 0;
if (Math.Abs(Y) < minNormal)
{
minNormal = Math.Abs(Y);
minIndex = 1;
}
if (Math.Abs(Z) < minNormal)
{
minNormal = Math.Abs(Z);
minIndex = 2;
}
Vector B;
switch (minIndex)
{
case 0:
B = new Vector(1, 0, 0);
break;
case 1:
B = new Vector(0, 1, 0);
break;
default:
B = new Vector(0, 0, 1);
break;
}
return (B - minNormal * this).ToUnit();
}
}
class Program
{
static void Main(string[] args)
{
// Phnom Penh
Gps centre = new Gps(11.55, 104.916667);
// In metres
double worldRadius = 6371000;
// In metres
double circleRadius = 1000;
// Points representing circle of radius circleRadius round centre.
Gps[] points = new Gps[20];
CirclePoints(points, centre, worldRadius, circleRadius);
}
static void CirclePoints(Gps[] points, Gps centre, double R, double r)
{
int count = points.Length;
Vector C = centre.ToUnitVector();
double t = r / R;
Vector K = Math.Cos(t) * C;
double s = Math.Sin(t);
Vector U = K.Orthogonal();
Vector V = K.Cross(U);
// Improve orthogonality
U = K.Cross(V);
for (int point = 0; point != count; ++point)
{
double a = 2 * Math.PI * point / count;
Vector P = K + s * (Math.Sin(a) * U + Math.Cos(a) * V);
points[point] = P.ToGps();
}
}
}
}
I have written Polycircles, small open-source package in Python that does it. It uses geographiclib for the geospatial calculation.

Angle between two lines is wrong

I want to get angles between two line.
So I used this code.
int posX = (ScreenWidth) >> 1;
int posY = (ScreenHeight) >> 1;
double radians, degrees;
radians = atan2f( y - posY , x - posX);
degrees = -CC_RADIANS_TO_DEGREES(radians);
NSLog(#"%f %f",degrees,radians);
But it doesn't work .
The Log is that: 146.309935 -2.553590
What's the matter?
I can't know the reason.
Please help me.
If you simply use
radians = atan2f( y - posY , x - posX);
you'll get the angle with the horizontal line y=posY (blue angle).
You'll need to add M_PI_2 to your radians value to get the correct result.
Here's a function I use. It works great for me...
float cartesianAngle(float x, float y) {
float a = atanf(y / (x ? x : 0.0000001));
if (x > 0 && y > 0) a += 0;
else if (x < 0 && y > 0) a += M_PI;
else if (x < 0 && y < 0) a += M_PI;
else if (x > 0 && y < 0) a += M_PI * 2;
return a;
}
EDIT: After some research I found out you can just use atan2(y,x). Most compiler libraries have this function. You can ignore my function above.
If you have 3 points and want to calculate an angle between them here is a quick and correct way of calculating the right angle value:
double AngleBetweenThreePoints(CGPoint pointA, CGPoint pointB, CGPoint pointC)
{
CGFloat a = pointB.x - pointA.x;
CGFloat b = pointB.y - pointA.y;
CGFloat c = pointB.x - pointC.x;
CGFloat d = pointB.y - pointC.y;
CGFloat atanA = atan2(a, b);
CGFloat atanB = atan2(c, d);
return atanB - atanA;
}
This will work for you if you specify point on one of the lines, intersection point and point on the other line.