Rotating a sprite on a Bezier curve in cocos2d - cocos2d-iphone

I am trying to make a sprite follow a bezier curve. I found a few forum posts over on the cocos2d site and followed the directions but i still dont seem to be able to get the sprite to rotate correctly. Can anyone help.
The code i have added into the update method of the BezierBy function is as follows
float qx = (powf(1-t,2)*xa + 2*(1-t)*t*xb+powf(t,2)*xc);
float qy = (powf(1-t,2)*ya + 2*(1-t)*t*yb+powf(t,2)*yc);
double deltaX = x-qx;
double deltaY = y-qy;
double degrees = (-180/M_PI)*ccpToAngle(CGPointMake(deltaX,deltaY));
[target_ setRotation:degrees];
The original article can be found here
Any help would be great at the moment the rotation seems quite erratic

Whenever I need a sprite to follow on a particular Bezier path and rotate accordingly. I create a bezier path using CCBezier.
And use CCRotateTo method for rotating the sprite to a particular angle. The duration of rotation is duration of bezierAction and angle of rotation can be calculated manually. Like in your pic angle is from -45 to 45.
So code might look like this..
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(0, s.height/2);
bezier.controlPoint_2 = ccp(300, -s.height/2);
bezier.endPosition = ccp(300,100);
id bezierForward = [CCBezierBy actionWithDuration:10 bezier:bezier];
[sprite runAction:bezierForward];
[sprite setRotation:-45];
[sprite runAction:[CCRotateTo actionWithDuration:10 angle:45]];
Fill values accordingly.. This is just a snippet code.. :)

I would suggest you calculate the angle of the sprites movement during the last frame and use this value to rotate the sprite accordingly. This method will work for every type of movement including complicated bezier paths. This will also save you the work of timing the rotation to the movement compared to the other solution offered.
CGPoint vector = ccpSub(sprite.position, lastPosition);
sprite.rotation = atan2(vector.x, vector.y) * 180 / M_PI;
lastPosition = sprite.position;
You will of course need to put this code in an update loop with lastPosition as a global variable.

Related

GeoDjango: How to create a circle anywhere on earth based on point and radius?

I have a similar question to this one. Using geodjango, I want to draw a circle on a map with a certain radius in km. However, the suggested solution
a) does not use km but instead degrees, and
b) becomes an oval further north or south.
Here is what I do:
from django.contrib.gis import geos
lat = 49.17
lng = -123.96
center = geos.Point(lng, lat)
radius = 0.01
circle = center.buffer(radius)
# And I then use folium to show a map on-screen:
map = folium.Map(
location=[lat,lng],
zoom_start=14,
attr="Mapbox"
)
folium.GeoJson(
circle.geojson,
name="geojson",
).add_to(map)
The result is this:
How can I
a) draw a circle that is always 3 km in radius, independent from the position on the globe, and
b) ensure this is a circle and not an oval at all latitudes?
Here is the Code
from django.contrib.gis import geos
import folium
lat = 49.17
lng = -123.96
center = geos.Point(x=lng, y=lat, srid=4326)
center.transform(3857) # Transform Projection to Web Mercator
radius = 3000 # now you can use meters
circle = center.buffer(radius)
circle.transform(4326) # Transform back to WGS84 to create geojson
# And I then use folium to show a map on-screen:
map = folium.Map(
location=[lat,lng],
zoom_start=14,
attr="Mapbox"
)
geojson = folium.GeoJson(
circle.geojson,
name="geojson",
)
geojson.add_to(map)
Explanation
This problem occurs due to Map Projections.
Lat/Long Coordinates are represented by the Map Projection WGS84. The Values are in degrees.
The map you see in folium has another map projection (Web Mercator). It tries to represent the world as a plane, which produces distortions to the north and south. The coordinate values are in meters.
On a globe your created circle would look completely round, but because folium uses another projection it gets distorted.
It is also important to know that every projection is represented by a number (EPSG Code). With this epsg codes, you can transform your coordinates from one projection into another.
Web Mercator -> EPSG 3857
WGS84 -> EPSG 4326
With my Code you now get a round circle in folium for Web Mercator, but be aware that it would look oval and distorted, when looking at it on a globe.
This is just a very easy explanation. You might have a look at Map Projections to better understand the problem.
This guide gives a good overview:
Map Projections
try this
folium.Circle(
radius=3000,
location=[lat,lng],
popup="Whatever name",
color="#3186cc",
fill=True,
fill_color="#3186cc",
).add_to(m)

How to do location based query with simple Django filter?

I've saved user's coordinates in the User model. Post model has latitude, longitude and radius field. Only the users in that vicinity(of Post) will be able to see that post. I don't know how to use filter() here so I used the following approach:
post=Posts.objects.all()
for a in post:
distance= geopy.distance.geodesic((lat1,lng1), (a.latitude, a.longitude)).km
print(distance)
if distance < a.radius:
p.append(a)
else:
continue
Here, lat1 and lng1 are the coordinates of current User. Suggest if there is any better way as this seems very inefficient.
Depending on your requirements, you could use a square instead of a circle. Pre-calculate the x-max, x-min, y-max and y-min boundaries for your square and then do a simple User.filter(lat__gt=lat_min, user.lng__gt=lng_min, user.lat__lt=lat_max ... lookup in the database.
In a past project, I used this:
def get_latlng_bounderies(lat, lng, distance):
"""
Return min/max lat/lng values for a distance around a latlng.
:lat:, :lng: the center of the area.
:distance: in km, the "radius" around the center point.
:returns: Two corner points of a square that countains the circle,
lat_min, lng_min, lat_max, lng_max.
"""
gc = great_circle(kilometers=distance)
p0 = gc.destination((lat, lng), 0)
p90 = gc.destination((lat, lng), 90)
p180 = gc.destination((lat, lng), 180)
p270 = gc.destination((lat, lng), 270)
ret = p180[0], p270[1], p0[0], p90[1]
return ret
Its not a circle, so its not exact around the "corners" of the square, but its much faster, because its a simple float comparision in the database.

Axis rotation with an oriented bounding box

I'm trying to put an oriented bounding box around the stamford rabbit for a project. To do this, I create a covariance matrix with the vertices and use the eigenvector columns as the new axis vectors for the OBB.
To draw the OBB, I take the cross product of the vector columns with the x,y and z axes to find the vector perpendicular both, then I use the dot product to find the angle between them.
//rv,uv,fv are the normalised column vectors from the eigenvector matrix.
// Calculate cross product for normal
crossv1x[0] = xaxis[1]*rv[2] - xaxis[2]*rv[1];
crossv1x[1] = xaxis[2]*rv[0] - xaxis[0]*rv[2];
crossv1x[2] = xaxis[0]*rv[1] - xaxis[1]*rv[0];
// Calculate cross product for normal
crossv2y[0] = yaxis[1]*uv[2] - yaxis[2]*uv[1];
crossv2y[1] = yaxis[2]*uv[0] - yaxis[0]*uv[2];
crossv2y[2] = yaxis[0]*uv[1] - yaxis[1]*uv[0];
// Calculate cross product for normal
crossv3z[0] = zaxis[1]*fv[2] - zaxis[2]*fv[1];
crossv3z[1] = zaxis[2]*fv[0] - zaxis[0]*fv[2];
crossv3z[2] = zaxis[0]*fv[1] - zaxis[1]*fv[0];
//dot product:
thetaX = dot(xaxis,rv,1)*180/PI;
thetaY = dot(yaxis,uv,1)*180/PI;
thetaZ = dot(zaxis,fv,1)*180/PI;
I then apply a rotation around the cross product vector with an angle determined by the dot product (glRotatef(angle,cross[0],cross1,cross[2]) for each axis). I then draw an axis aligned bounding box, then to the inverse rotation back to the original position.
glRotatef(thetaY,crossv2y[0],crossv2y[1],crossv2y[2]);
glRotatef(thetaZ,crossv3z[0],crossv3z[1],crossv3z[2]);
glRotatef(thetaX,crossv1x[0],crossv1x[1],crossv1x[2]);
glTranslatef(-meanX, -meanY, -meanZ);
glColor3f(1.0f,0.0f,0.0f);
AOBB(1); //Creates an axis aligned box.
glRotatef(-thetaX,crossv1x[0],crossv1x[1],crossv1x[2]);
glRotatef(-thetaZ,crossv3z[0],crossv3z[1],crossv3z[2]);
glRotatef(-thetaY,crossv2y[0],crossv2y[1],crossv2y[2]);
As you can see below, the box does not fit exactly onto the rabbit, nor does it align with the axis I have drawn... Am I missing something here? Ive fried my brain trying to find the solution but to no avail...
To draw the OBB, I take the cross product of the vector columns with the x,y and z axes to find the vector perpendicular both, then I use the dot product to find the angle between them.
Those "vector columns?" Those are actually the columns of the rotation matrix you want to generate.
So instead of using these vectors to compute rotation angles, just build a matrix with those (normalized) vectors as the columns. Upload it with glMultMatrix, and you should be fine.

GeoDjango: Determine the area of a polygon

In my model I have a polygon field defined via
polygon = models.PolygonField(srid=4326, geography=True, null=True, blank=True)
When I want to determine the area of the polygon, I call
area_square_degrees = object.polygon.area
But how can I convert the result in square degrees into m2 with GeoDjango?
This answer does not work, since area does not have a method sq_m. Is there any built-in conversion?
You need to transform your data to the correct spatial reference system.
area_square_local_units = object.polygon.transform(srid, clone=False).area
In the UK you might use the British National Grid SRID of 27700 which uses meters.
area_square_meters = object.polygon.transform(27700, clone=False).area
You may or may not want to clone the geometry depending on whether or not you need to do anything else with it in its untransformed state.
Docs are here https://docs.djangoproject.com/en/1.8/ref/contrib/gis/geos/
I have struggled a lot with this, since i could'nt find a clean solution. The trick is you have to use the postgis capabilities (and and thus its only working with postgis..):
from django.contrib.gis.db.models.functions import Area
loc_obj = Location.objects.annotate(area_=Area("poly")).get(pk=??)
# put the primary key of the object
print(loc_obj.area_) # distance object, result should be in meters, but you can change to the unit you want, e.g .mi for miles etc..
The models.py:
class Location(models.Model):
poly = gis_models.PolygonField(srid=4326, geography=True)
It's i think the best way to do it if you have to deal with geographic coordinates instead of projections. It does handle the curve calculation of the earth, and the result is precise even with big distance/area
I needed an application to get the area of poligons around the globe and if I used an invalid country/region projection I got the error OGRException: OGR failure
I ended using an OpenLayers implementation
using the 4326 projection (is the default projection) to avoid concerning about every country/region specific projection.
Here is my code:
import math
def getCoordsM2(coordinates):
d2r = 0.017453292519943295 # Degrees to radiant
area = 0.0
for coord in range(0, len(coordinates)):
point_1 = coordinates[coord]
point_2 = coordinates[(coord + 1) % len(coordinates)]
area += ((point_2[0] - point_1[0]) * d2r) *\
(2 + math.sin(point_1[1] * d2r) + math.sin(point_2[1] * d2r))
area = area * 6378137.0 * 6378137.0 / 2.0
return math.fabs(area)
def getGeometryM2(geometry):
area = 0.0
if geometry.num_coords > 2:
# Outer ring
area += getCoordsM2(geometry.coords[0])
# Inner rings
for counter, coordinates in enumerate(geometry.coords):
if counter > 0:
area -= getCoordsM2(coordinates)
return area
Simply pass your geometry to getGeometryM2 function and you are done!
I use this function in my GeoDjango model as a property.
Hope it helps!
If Its earths surface area that you are talking about, 1 square degree has 12,365.1613 square km. So multiple your square degree and multiply by 10^6 to convert to meters.

SetViewBox moving the paper

I am using the setViewBox() function in Raphael 2. The width and height is multiplied by a value like (1.2, 1.3 ...). This changes the magnification/ zooming properly but the x and y which I have given as 0,0 makes the paper display its contents after some offset. If i modify the x and y to some positive value after the rendering( using firebug!!) then the top left of the paper moves back and above to its right position. I want to know how will the value be calculated. I have no idea about how the x,y affect the viewbox. If anybody can give me any pointers for this it will be a real help.
I have tried giving the difference between the width/ height divided by 2. Also I must mention that I am not rendering an image but various raphael shapes e.g. rects, paths text etc. in my paper.
Looking forward to some help!
Kavita
this is an example showing how to calculate the setViewBox values, I included jquery (to get my SVG cocntainer X and Y : $("#"+map_name).offset().left and $("#"+map_name).offset().top) and after that I calculated how much zoom I need :
var original_width = 777;
var original_height = 667;
var zoom_width = map_width*100/original_width/100;
var zoom_height = map_height*100/original_height/100;
if(zoom_width<=zoom_height)
zoom = zoom_width;
else
zoom = zoom_height;
rsr.setViewBox($("#"+map_name).offset().left, $("#"+map_name).offset().top, (map_width/zoom), (map_height/zoom));
did you put the center of your scaling to 0,0 like:
element.scale(1.2,1.2,0,0);
this can scale your element without moving the coordinates of the top left corner.