iOS MapKit - Points per meter - cocoa

I am drawing a circle in a MKOverlayView subclass. I have a radius in meters. How would I convert said meters to points (at that zoom scale) for drawing in drawMapRect:zoomScale:inContext:?

see headers:
helpers:
// Conversion between distances and projected coordinates
MK_EXTERN CLLocationDistance MKMetersPerMapPointAtLatitude(CLLocationDegrees latitude) NS_AVAILABLE(NA, 4_0);
MK_EXTERN double MKMapPointsPerMeterAtLatitude(CLLocationDegrees latitude) NS_AVAILABLE(NA, 4_0);
MK_EXTERN CLLocationDistance MKMetersBetweenMapPoints(MKMapPoint a, MKMapPoint b) NS_AVAILABLE(NA, 4_0);
and from the MKOverlayView
// Convert screen points relative to this view to absolute MKMapPoints
- (CGPoint)pointForMapPoint:(MKMapPoint)mapPoint;
- (MKMapPoint)mapPointForPoint:(CGPoint)point;
so
double ppm = MKMapPointsPerMeterAtLatitude(centerCoordinate.latitude);
MKMapPoint mkptLeftmost = ptCenter.x -= ppm;
CGPoint ptLeftmost = [self pointForMapPoint:mkptLeftmost];

Related

Monogame - Rotate Sprite around centre of screen and itself

I have a problem and although I serached everywhere I couldn't find a solution.
I have a stacked sprite and I'm rotating this sprite around the center of the screen. So I iterate over a list of sprites (stacked) and increase the y-coordinate by 2 every loop (rotation is increased step by step by 0.01f outside of the loop):
foreach(var s in stacked)
{
Vector2 origin = new Vector2(Basic.width / 2, Basic.height / 2);
Rectangle newPosition = new Rectangle(position.X, position.Y - y, position.Width, position.Height);
float angle = 0f;
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
Vector2 pos = new Vector2(newPosition.X, newPosition.Y);
pos = Vector2.Transform(pos, transform);
newPosition.X = (int)pos.X;
newPosition.Y = (int)pos.Y;
angle += rotation;
s.Draw(newPosition, origin, angle, Color.White);
y += 2;
}
This works fine. But now my problem. I want not only to rotate the sprite around the center of the screen but also around itself. How to achieve this? I can only set one origin and one rotation per Draw. I would like to rotate the sprite around the origin 'Basic.width / 2, Basic.height / 2' and while it rotates, around 'position.Width / 2, position.Height / 2'. With different rotation speed each. How is this possible?
Thank you in advance!
Just to be clear:
When using SpriteBatch.Draw() with origin and angle, there is only one rotation: the final angle of the sprite.
The other rotations are positional offsets.
The origin in the Draw() call is a translation, rotation, translate back. Your transform matrix shows this quite well:
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
//Class level variables:
float ScreenRotation, ScreenRotationSpeed;
float ObjectRotation, ObjectRotationSpeed;
Vector2 ScreenOrigin, SpriteOrigin;
// ...
// In constructor and resize events:
ScreenOrigin = new Vector2(Basic.width <<1, Basic.height <<1);
// shifts are faster for `int` type. If "Basic.width" is `float`:
//ScreenOrigin = new Vector2(Basic.width, Basic.height) * 0.5f;
// In Update():
ScreenRotation += ScreenRotationSpeed; // * gameTime.ElapsedGameTime.Seconds; // for FPS invariant speed where speed = 60 * single frame speed
ObjectRotation+= ObjectRotationSpeed;
//Calculate the screen center rotation once per step
Matrix baseTransform = Matrix.CreateTranslation(-ScreenOrigin.X, -ScreenOrigin.Y, 0f) *
Matrix.CreateRotationZ(ScreenRotation) *
Matrix.CreateTranslation(ScreenOrigin.X, ScreenOrigin.Y, 0f);
// In Draw() at the start of your code snippet posted:
// moved outside of the loop for a translationally invariant vertical y interpretation
// or move it inside the loop and apply -y to position.Y for an elliptical effect
Vector2 ObjectOrigin = new Vector2(position.X, position.Y);
Matrix transform = baseTransform *
Matrix.CreateTranslation(-ObjectOrigin.X, -ObjectOrigin.Y, 0f) *
Matrix.CreateRotationZ(ObjectRotation) *
Matrix.CreateTranslation(ObjectOrigin.X, ObjectOrigin.Y, 0f);
foreach(var s in stacked)
{
Vector2 pos = new Vector2(ObjectOrigin.X, ObjectOrigin.Y - y);
pos = Vector2.Transform(pos, transform);
float DrawAngle = ObjectRotation;
// or float DrawAngle = ScreenRotation;
// or float DrawAngle = ScreenRotation + ObjectRotation;
// or float DrawAngle = 0;
s.Draw(pos, SpriteOrigin, DrawAngle, Color.White);
}
I suggest moving the Draw() parameter away from destinationRectangle and use the Vector2 position directly with scaling. Rotations within square rectangles can differ up to SQRT(2) in aspect ratio, i.e. stretching/squashing. Using Vector2 incurs a cost of higher collision complexity.
I am sorry for the ors, but without complete knowledge of the problem...YMMV
In my 2D projects, I use the vector form of polar coordinates.
The Matrix class requires more calculations than the polar equivalents in 2D. Matrix operates in 3D, wasting cycles calculating Z components.
With normalized direction vectors (cos t,sin t) and a radius(vector length),in many cases I use Vector2.LengthSquared() to avoid the square root when possible.
The only time I have used Matrices in 2D is display projection matrix(entire SpriteBatch) and Mouse and TouchScreen input deprojection(times the inverse of the projection matrix)

Having a point from 3 static cameras prespectives how to restore its position in 3d space?

We have same rectangle position relative to 3 same type of staticly installed web cameras that are not on the same line. Say on a flat basketball field. Thus we have tham all inside one 3d space and (x, y, z); (ax, ay, az); positionas and orientations set for all of them.
We have a ball color and we found its position on all 3 images im1, im2, im3. Now having its position on 2d frames (p1x, p1y);(p2x, p2y);(p3x, p3y), and cameras pos\orientations how to get ball position in 3d space?
You need to unproject 2D screen coordinates into 3D coordinates in space.
You need to solve system of equation to find real point in 3D from 3 rays you got on the first step.
You can find source code for gluUnProject here. I also provide here my code for it:
public Vector4 Unproject(float x, float y, Matrix4 View)
{
var ndcX = x / Viewport.Width * 2 - 1.0f;
var ndcY = y / Viewport.Height * 2 - 1.0f;
var invVP = Matrix4.Invert(View * ProjectionMatrix);
// We don't z-coordinate of the point, so we choose 0.0f for it.
// We are going to find out it later.
var screenPos = new Vector4(ndcX, -ndcY, 0.0f, 1.0f);
var res = Vector4.Transform(screenPos, invVP);
return res / res.W;
}
Vector3 ComputeRay(Camera camera, Vector2 p)
{
var worldPos = Unproject(p.X, p.Y, camera.View);
var dir = new Vector3(worldPos) - camera.Eye;
return new Ray(camera.Eye, Vector3.Normalize(dir));
}
Now you need to find intersection of three such rays. Theoretically that would be enough to use only two rays. It depends on positions of your cameras.
If we had infinite precision floating point arithmetic and input was without noise that would be trivial. But in reality you might need to exploit some simple numerical scheme to find the point with an appropriate precision.

Rotate a Sprite around another Sprite -libGDX-

video game link
I'm trying to make a game (see link above) , and I need to have the stick rotate around himself to maintain the orientation face to center of the circle.
this is how I declare the Sprite, and how I move it around the circle:
declaration:
line = new Sprite(new Texture(Gdx.files.internal("drawable/blockLine.png")));
line.setSize(140, 20);
lineX = Gdx.graphics.getWidth()/2 - line.getWidth()/2;
lineY = (Gdx.graphics.getHeight()/2 - line.getHeight()/2) + circle.getHeight()/2;
movement:
Point point = rotatePoint(new Point(lineX, lineY), new Point(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), angle+= Gdx.graphics.getDeltaTime() * lineSpeed);
line.setPosition(point.x, point.y);
rotatePoint function:
Point rotatePoint(Point point, Point center, double angle){
angle = (angle ) * (Math.PI/180); // Convert to radians
float rotatedX = (int) (Math.cos(angle) * (point.x - center.x) - Math.sin(angle) * (point.y-center.y) + center.x);
float rotatedY = (int) (Math.sin(angle) * (point.x - center.x) + Math.cos(angle) * (point.y - center.y) + center.y);
return new Point(rotatedX,rotatedY);
}
Any sugestions ?
I can't test right now but I think the rotation of the line should simply be:
Math.atan2(rotatedPoint.getOriginX() - middlePoint.getOriginX(), rotatedPoint.getOriginY() - middlePoint.getOriginY()));
Then you'll have to adjust rad to degrees or whatever you'll use. Tell me if it doesn't work!
I would take a different approach, I just created a method that places n Buttons around a click on the screen. I am using something that looks like this:
float rotation; // in degree's
float distance; //Distance from origin (radius of circle).
vector2 originOfRotation; //Center of circle
vector2 originOfSprite; //Origin of rotation sprite we are calculating
Vector2 direction = new vector2(0, 1); //pointing up
//rotate the direction
direction.rotate(rotation);
// add distance based of the direction. Warning: originOfRotation will change because of chaining method.
// use originOfRotation.cpy() if you do not want to init each frame
originOfSprite = originOfRotation.add(direction.scl(distance));
Now you have the position of your sprite. You need to increment rotation by x each frame to have it rotate. If you want the orientation of the sprite to change you can use the direction vector, probably rotated by 180 again. Efficiency wise I'm not sure what the difference would be.

How to make clock ticks stuck to the clock border?

I try to make a clock, in swift, but now i want to make something strange. I want make border radius settable. This is the easy part (is easy because I already did that). I drew 60 ticks around the clock. The problem is that 60 ticks are a perfect circle. If I change the border radius I obtain this clock:
All ticks are made with NSBezierPath, and code for calculate position for every tick is :
tickPath.moveToPoint(CGPoint(
x: center.x + cos(angle) * point1 ,
y: center.y + sin(angle) * point1
))
tickPath.lineToPoint(CGPoint(
x: center.x + cos(angle) * point2,
y: center.y + sin(angle) * point2
))
point1 and point2 are points for 12 clock tick.
My clock background is made with bezier path:
let bezierPath = NSBezierPath(roundedRect:self.bounds, xRadius:currentRadius, yRadius:currentRadius)
currentRadius - is a settable var , so my background cam be, from a perfect circle (when corner radius = height / 2) to a square (when corner radius = 0 ).
Is any formula to calculate position for every tick so, for any border radius , in the end all ticks to be at same distance to border ?
The maths is rather complicated to explain without recourse to graphics diagrams, but basically if you consider a polar coordinates approach with the origin at the clock centre then there are two cases:
where the spoke from the origin hits the straight side of the square - easy by trigonometry
where it hits the circle arc at the corner - we use the cosine rule to solve the triangle formed by the centre of the clock, the centre of the corner circle and the point where the spoke crosses the corner. The origin-wards angle of that triangle is 45º - angleOfSpoke, and two of the sides are of known length. Solve the cosine equation as a quadratic and you have it.
This function does it:
func radiusAtAngle(angleOfSpoke: Double, radius: Double, cornerRadius: Double) -> Double {
// radius is the half-width of the square, = the full radius of the circle
// cornerRadius is, of course, the corner radius.
// angleOfSpoke is the (maths convention) angle of the spoke
// the function returns the radius of the spoke.
let theta = atan((radius - cornerRadius) / radius) // This determines which case
let modAngle = angleOfSpoke % M_PI_2 // By symmetry we need only consider the first quadrant
if modAngle <= theta { // it's on the vertical flat
return radius / cos(modAngle)
} else if modAngle > M_PI_2 - theta { // it's on the horizontal flat
return radius / cos(M_PI_2 - modAngle)
} else { // it's on the corner arc
// We are using the cosine rule to solve the triangle formed by
// the clock centre, the curved corner's centre,
// and the point of intersection of the spoke.
// Then use quadratic solution to solve for the radius.
let diagonal = hypot(radius - cornerRadius, radius - cornerRadius)
let rcosa = diagonal * cos(M_PI_4 - modAngle)
let sqrTerm = rcosa * rcosa - diagonal * diagonal + cornerRadius * cornerRadius
if sqrTerm < 0.0 {
println("Aaargh - Negative term") // Doesn't happen - use assert in production
return 0.0
} else {
return rcosa + sqrt(sqrTerm) // larger of the two solutions
}
}
}
In the diagram OP = diagonal, OA = radius, PS = PB = cornerRadius, OS = function return, BÔX = theta, SÔX = angleOfSpoke

draw uiimage along CGMutablePathRef

How do i draw a custom uiimage along a CGMutablePathRef ? I can get the points from CGMutablePathRef but it does not give the smooth points that create the path.
I want to know if i can extract all of them plus the one that creat the smooth path.
i've used CGPathApply but i only get the control points, and when i draw my image it does not stay smooth as the original CGMutablePathRef
void pathFunction(void *info, const CGPathElement *element){
if (element->type == kCGPathElementAddQuadCurveToPoint)
{
CGPoint firstPoint = element->points[1];
CGPoint lastPoint = element->points[0];
UIImage *tex = [UIImage imageNamed:#"myimage.png"];
CGPoint vector = CGPointMake(lastPoint.x - firstPoint.x, lastPoint.y - firstPoint.y);
CGFloat distance = hypotf(vector.x, vector.y);
vector.x /= distance;
vector.y /= distance;
for (CGFloat i = 0; i < distance; i += 1.0f) {
CGPoint p = CGPointMake(firstPoint.x + i * vector.x, firstPoint.y + i * vector.y);
[tex drawAtPoint:p blendMode:kCGBlendModeNormal alpha:1.0f];
}
}
}
It seems like you are looking for the function that is used to draw a cubic Bézier curve from a start point and an end point and two control points.
start⋅(1-t)^3 + 3⋅c1⋅t(1-t)^2 + 3⋅c2⋅t^2(1-t) + end⋅t^3
By setting a value for t between 0 and 1 you will get a point on the curve at a certain percentage of the curve length. I have a short description of how it works in the end of this blog post.
Update
To find the point to draw the image somewhere between the start and end points you pick a t (for example 0.36 and use it to calculate the x and y value of that points.
CGPoint start, end, c1, c2; // set to some value of course
CGFloat t = 0.36;
CGFloat x = start.x*pow((1-t),3) + 3*c1.x*t*pow((1-t),2) + 3*c2.x*pow(t,2)*(1-t) + end.x*pow(t,3);
CGFloat y = start.y*pow((1-t),3) + 3*c1.y*t*pow((1-t),2) + 3*c2.y*pow(t,2)*(1-t) + end.y*pow(t,3);
CGPoint point = CGPointMake(x,y); // this is 36% along the line of the curve
Which given the path in the image would correspond to the orange circle
If you do this for many points along the curve you will have many images positioned along the curve.
Update 2
You are missing that kCGPathElementAddQuadCurveToPoint (implicitly) has 3 points: start (the current/previous points, the control point (points[0]) and the end point (points[1]). For a quad curve both control points are the same so c1 = c2;. For kCGPathElementAddCurveToPoint you would get 2 different control points.

Resources