I've got a question that's driving me nuts! :) I've been working on it day and night now :) :)
What is my goal?
Say 2 outside. 2 inside. With Illustrator it is easy :)
My approach so far
Work clockwise. Get angle between P1 & P2
Use trigonometry to calculate the X & Y offset
Add the X & Y offset to P1 & P2. This is how I get the angle between P1 and P2:
float getAngle = (atan((P1.y-P2.y)/(P1.x-p2.x))) * (180/PI) ;
// ( COS(angle) = (adjacent side) / (hypotenuse) ) || 2 = 6 / 3
// ( COS(angle) * (hypotenuse) = (adjacent side) || 2 * 3 = 6
// ( SIN(angle) = (opposite side) / (hypotenuse) ) || 2 = 6 / 3
// ( SIN(angle) * (hypotenuse) = (opposite side) || 2 * 3 = 6
My Problem
I know how to offset the path. But only on 1 side. Always +x and -Y. So this is the result. Almost like just moving the path entirely. Instead of offsetting all around.:
It needs to stay outside the centre/original line.
What would I like from you?
Is there a logic/formula to do this?
Or is there a library that already has this??
I just cannot wrap my head around how I can keep the line offset outside the first/centre line.
Could you get away with scaling the vertices ?
void setup(){
size(400,400);
PVector[] originalPath = randomPath(7,100);
PVector[] insetPath = scalePoints(originalPath,0.75);
PVector[] outsetPath = scalePoints(originalPath,1.25);
background(255);
noFill();
translate(width * .5, height * .5);
stroke(0,192,0);
drawPath(originalPath);
stroke(192,0,0);
drawPath(insetPath);
stroke(0,0,192);
drawPath(outsetPath);
fill(0);
text("original path",originalPath[0].x,originalPath[0].y);
text("inset path",insetPath[1].x,insetPath[1].y);
text("outset path",outsetPath[2].x,outsetPath[2].y);
text("click\nto\nreset",0,0);
}
void drawPath(PVector[] pts){
beginShape();
for(PVector p : pts) vertex(p.x,p.y);
endShape(CLOSE);
}
PVector[] scalePoints(PVector[] pts,float scale){
int numPoints = pts.length;
PVector[] result = new PVector[numPoints];
for(int i = 0 ; i < numPoints; i++){
result[i] = pts[i].get();
result[i].mult(scale);
}
return result;
}
PVector[] randomPath(int numPoints,float r){
PVector[] result = new PVector[numPoints];
float ai = TWO_PI / numPoints;
for(int i = 0 ; i < numPoints; i++){
float radius = random(r-r*.25,r+r*.25);
result[i] = new PVector(cos(ai * i) * radius, sin(ai * i) * radius);
}
return result;
}
void mousePressed(){
setup();
}
void draw(){}
Related
There is a code for a drawing circle with LineRenderer.
but I want to draw multiple circles with different radius, I used "for loop" but there is one circle instead of multiple
public float ThetaScale = 0.01f;
public float radius = 3f;
private int Size;
private LineRenderer LineDrawer;
private float Theta = 0f;
void Start ()
{
LineDrawer = GetComponent<LineRenderer>();
}
void Update ()
{
Theta = 0f;
Size = (int)((1f / ThetaScale) + 1f);
LineDrawer.SetVertexCount(Size);
for (int l = 0; l < 5; l++)
{
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
LineDrawer.SetPosition(i, new Vector3(x, 0, y));
}
}
}
In every loop you always overwrite the same positions indices in the same line renderer. So you will always only have the last circle.
Note that it is also quite expensive to use SetPoisition repeatedly. As it says in the API you should rather work on an array and then use SetPoisitions to assign all positions at once.
One thing is a bit unclear though: If you use one single LineRenderer you won't get independent circles but they will always be connected at some point. Otherwise you would need 5 separated LineRenderer instances.
Option A: 5 circles but connected to each other since part of a single LineRenderer
void Start ()
{
LineDrawer = GetComponent<LineRenderer>();
LineDrawer.loop = false;
Theta = 0f;
// Use one position more to close the circle
Size = (int)((1f / ThetaScale) + 1f) + 1;
LineDrawer.positionCount = 5 * Size;
var positions = new Vector3[5 * Size];
for (int l = 0; l < 5; l++)
{
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
positions[5 * l + i] = new Vector3(x, 0, y);
}
}
LineDrawer.SetPositions(positions);
}
Option B: 5 separated circles in 5 separated LineRenderers
// Drag 5 individual LineRenderer here via the Inspector
public LineRenderer[] lines = new LineRenderer[5];
void Start ()
{
foreach(var line in lines)
{
line.loop = true;
Theta = 0f;
Size = (int)((1f / ThetaScale) + 1f);
line.positionCount = Size;
var positions = new Vector3[Size];
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
positions[5 * l + i] = new Vector3(x, 0, y);
}
line.SetPositions(positions);
}
}
You missed few details here and there. Here, this will work:
using UnityEngine;
[ExecuteAlways]
[RequireComponent( typeof(LineRenderer) )]
public class CircularBehaviour : MonoBehaviour
{
[SerializeField][Min(3)] int _numSegments = 16;
[SerializeField][Min(1)] int _numCircles = 5;
[SerializeField] float _radius = 3f;
LineRenderer _lineRenderer;
void Awake ()
{
_lineRenderer = GetComponent<LineRenderer>();
_lineRenderer.loop = false;
_lineRenderer.useWorldSpace = false;
}
void Update ()
{
const float TAU = 2f * Mathf.PI;
float theta = TAU / (float)_numSegments;
int numVertices = _numSegments + 1;
_lineRenderer.positionCount = numVertices * _numCircles;
int vert = 0;
for( int l=1 ; l<=_numCircles ; l++ )
{
float r = _radius * (float)l;
for( int i=0 ; i<numVertices ; i++ )
{
float f = theta * (float)i;
Vector3 v = new Vector3{ x=Mathf.Cos(f) , y=Mathf.Sin(f) } * r;
_lineRenderer.SetPosition( vert++ , v );
}
}
}
}
But
as #derHugo explained, this is not what you're looking for exactly as all circles will be drawn connected.
I am suppose to implement a CatMull Rom Spline, and I have it implemented, but the sphere moves to the points extremely fast. I thought if I used Time.DeltaTime it would slow it down, but it moves too rapidly.
Function to compute point on curve:
Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
// TODO - compute and return a point as a Vector3
// Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
// Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
// etc...
Vector3 point = new Vector3();
float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
float c3 = ((u - 1f) * u * u) * 0.5f;
Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];
point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);
return point;
}
**Update Function: **
void Update ()
{
// TODO - use time to determine values for u and segment_number in this function call
// 0.5 Can be used as u
time += DT;
segCounter++;
Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
transform.position = temp;
}
Variables:
const int NumberOfPoints = 8;
Vector3[] controlPoints;
const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;
const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;
float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
EDIT: Sorry the calculations, and all of that is correct. It's straight from the slides, I just need help with the update function :(
Using Time.deltaTime allows you to be framerate independent. This means that if the framerate drops, or a frame takes longer than the others, your object will adapt the moving distance to keep a constant speed. This is generally a good idea.
Back to your case: Basically you want to pass a position to your function. You currently pass the time. If your catmull rom considers that 0 is the start and 1 is the destination, then after exactly 1 second, you will be at the end of the spline. (Note that this is where being framerate independent is interesting: Whatever the frame rate is. you reach the end in one second). Now, how to convert from time to position. Easy
position = time*speed;
Since time is in second, speed is in units per seconds. Say your catmullrom is one unit long. If speed is two, if will take one second to travel it twice. so half a second to travel it. Since you want to lower the speed, you might want to use values below 1. Try this:
void Update ()
{
time += Time.deltaTime;
var speed = 0.1f;
var splinePos = speed * time;
segCounter++;
Vector3 temp = ComputePointOnCatmullRomCurve(splinePos, segCounter);
transform.position = temp;
}
I am looking to create smooth paths for my 2D game. Looking at CatmullRomSpline it is just the thing i need. Every post, even here on SE is giving it a type and passing all the control points and a Boolean with the constructor. This seems to be obsolete now, CatmullRomSpline does not accept any type parameters anymore and without it it can only work with V3 paths. Neither does the constructor accept a list of control points.
cp = new Vector2[]
{
new Vector2(0,100), new Vector2(100,600), new Vector2(300,300), new Vector2(600, 400)
};
CatmullRomSpline<Vector2> path = new CatmullRomSpline<Vector2>(cp, true);
This gives the following error: The type CatmullRomSpline is not generic; it cannot be parameterized with arguments <Vector2>.
Am i missing something or does CatmullRomSpline work differently nowadays, and how?
This is the CatmullRomSpline Class from badlogic. It surely looks like things changed, i am getting this class from "import com.badlogic.gdx.math.CatmullRomSpline;"
public class CatmullRomSpline implements Serializable { private
static final long serialVersionUID = -3290464799289771451L; private
List controlPoints = new ArrayList(); Vector3 T1 =
new Vector3(); Vector3 T2 = new Vector3();
/** Adds a new control point * * #param point the point */
public void add (Vector3 point) { controlPoints.add(point); }
/** #return all control points */ public List
getControlPoints () { return controlPoints; }
/** Returns a path, between every two control points numPoints are
generated and the control points themselves are added too. * The
first and the last controlpoint are omitted. if there's less than 4
controlpoints an empty path is returned. * * #param numPoints
number of points returned for a segment * #return the path */
public List getPath (int numPoints) { ArrayList
points = new ArrayList();
if (controlPoints.size() < 4) return points;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) {
points.add(controlPoints.get(i)); float increment = 1.0f /
(numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
for (int j = 0; j < numPoints; j++) {
float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis
// function 1
float h2 = -2 * t * t * t + 3 * t * t; // calculate basis
// function 2
float h3 = t * t * t - 2 * t * t + t; // calculate basis
// function 3
float h4 = t * t * t - t * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
points.add(point);
t += increment; } }
if (controlPoints.size() >= 4)
points.add(controlPoints.get(controlPoints.size() - 2));
return points; }
/** Returns a path, between every two control points numPoints are
generated and the control points themselves are added too. * The
first and the last controlpoint are omitted. if there's less than 4
controlpoints an empty path is returned. * * #param points the
array of Vector3 instances to store the path in * #param numPoints
number of points returned for a segment */ public void getPath
(Vector3[] points, int numPoints) { int idx = 0; if
(controlPoints.size() < 4) return;
for (int i = 1; i <= controlPoints.size() - 3; i++) {
points[idx++].set(controlPoints.get(i)); float increment = 1.0f
/ (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
for (int j = 0; j < numPoints; j++) {
float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis
// function 1
float h2 = -2 * t * t * t + 3 * t * t; // calculate basis
// function 2
float h3 = t * t * t - 2 * t * t + t; // calculate basis
// function 3
float h4 = t * t * t - t * t; // calculate basis function 4
Vector3 point = points[idx++].set(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
t += increment; } }
points[idx].set(controlPoints.get(controlPoints.size() - 2)); }
/** Returns all tangents for the points in a path. Same semantics as
getPath. * * #param numPoints number of points returned for a
segment * #return the tangents of the points in the path */ public
List getTangents (int numPoints) { ArrayList
tangents = new ArrayList();
if (controlPoints.size() < 4) return tangents;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) { float
increment = 1.0f / (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
tangents.add(new Vector3(T1).nor());
for (int j = 0; j < numPoints; j++) {
float h1 = 6 * t * t - 6 * t; // calculate basis function 1
float h2 = -6 * t * t + 6 * t; // calculate basis function 2
float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3
float h4 = 3 * t * t - 2 * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
tangents.add(point.nor());
t += increment; } }
if (controlPoints.size() >= 4)
tangents.add(T1.set(controlPoints.get(controlPoints.size() -
1)).sub(controlPoints.get(controlPoints.size() - 3))
.mul(0.5f).cpy().nor());
return tangents; }
/** Returns all tangent's normals in 2D space for the points in a
path. The controlpoints have to lie in the x/y plane for this * to
work. Same semantics as getPath. * * #param numPoints number of
points returned for a segment * #return the tangents of the points
in the path */ public List getTangentNormals2D (int
numPoints) { ArrayList tangents = new ArrayList();
if (controlPoints.size() < 4) return tangents;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) { float
increment = 1.0f / (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
Vector3 normal = new Vector3(T1).nor(); float x = normal.x;
normal.x = normal.y; normal.y = -x; tangents.add(normal);
for (int j = 0; j < numPoints; j++) {
float h1 = 6 * t * t - 6 * t; // calculate basis function 1
float h2 = -6 * t * t + 6 * t; // calculate basis function 2
float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3
float h4 = 3 * t * t - 2 * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
point.nor();
x = point.x;
point.x = point.y;
point.y = -x;
tangents.add(point);
t += increment; } }
return tangents; }
/** Returns the tangent's normals using the tangent and provided up
vector doing a cross product. * * #param numPoints number of
points per segment * #param up up vector * #return a list of
tangent normals */ public List getTangentNormals (int
numPoints, Vector3 up) { List tangents =
getTangents(numPoints); ArrayList normals = new
ArrayList();
for (Vector3 tangent : tangents) normals.add(new
Vector3(tangent).crs(up).nor());
return normals; }
public List getTangentNormals (int numPoints, List
up) { List tangents = getTangents(numPoints);
ArrayList normals = new ArrayList();
int i = 0; for (Vector3 tangent : tangents) normals.add(new
Vector3(tangent).crs(up.get(i++)).nor());
return normals; } }
Your code should work fine according to the api and the source.
The class IS generic. You must be using some old version of the class.
Update to the latest version and the error should be solved.
Hope this helps.
I am following the quaternion tutorial: http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl and am trying to rotate a globe to some XYZ location. I have an initial quaternion and generate a random XYZ location on the surface of the globe. I pass that XYZ location into the following function. The idea was to generate a lookAt vector with GLKMatrix4MakeLookAt and define the end Quaternion for the slerp step from the lookAt matrix.
- (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {
// Turn on the interpolation for smooth rotation
_slerping = YES; // Begin auto rotating to this location
_slerpCur = 0;
_slerpMax = 1.0;
_slerpStart = _quat;
// The eye location is defined by the look at location multiplied by this modifier
float modifier = 1.0;
// Create a look at vector for which we will create a GLK4Matrix from
float xEye = x;
float yEye = y;
float zEye = z;
//NSLog(#"%f %f %f %f %f %f",xEye, yEye, zEye, x, y, z);
_currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
_currentSatelliteLocation = GLKMatrix4Multiply(_currentSatelliteLocation,self.effect.transform.modelviewMatrix);
// Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
//_currentSatelliteLocation = GLKMatrix4Translate(_currentSatelliteLocation, 0.0f, 0.0f, GLOBAL_EARTH_Z_LOCATION);
_slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);
// Print info on the quat
GLKVector3 vec = GLKQuaternionAxis(_slerpEnd);
float angle = GLKQuaternionAngle(_slerpEnd);
//NSLog(#"%f %f %f %f",vec.x,vec.y,vec.z,angle);
NSLog(#"Quat end:");
[self printMatrix:_currentSatelliteLocation];
//[self printMatrix:self.effect.transform.modelviewMatrix];
}
The interpolation works, I get a smooth rotation, however the ending location is never the XYZ I input - I know this because my globe is a sphere and I am calculating XYZ from Lat Lon. I want to look directly down the 'lookAt' vector toward the center of the earth from that lat/lon location on the surface of the globe after the rotation. I think it may have something to do with the up vector but I've tried everything that made sense.
What am I doing wrong - How can I define a final quaternion that when I finish rotating, looks down a vector to the XYZ on the surface of the globe? Thanks!
Is the following your meaning:
Your globe center is (0, 0, 0), radius is R, the start position is (0, 0, R), your final position is (0, R, 0), so rotate the globe 90 degrees around X-asix?
If so, just set lookat function eye position to your final position, the look at parameters to the globe center.
m_target.x = 0.0f;
m_target.y = 0.0f;
m_target.z = 1.0f;
m_right.x = 1.0f;
m_right.y = 0.0f;
m_right.z = 0.0f;
m_up.x = 0.0f;
m_up.y = 1.0f;
m_up.z = 0.0f;
void CCamera::RotateX( float amount )
{
Point3D target = m_target;
Point3D up = m_up;
amount = amount / 180 * PI;
m_target.x = (cos(PI / 2 - amount) * up.x) + (cos(amount) * target.x);
m_target.y = (cos(PI / 2 - amount) * up.y) + (cos(amount) * target.y);
m_target.z = (cos(PI / 2 - amount) * up.z) + (cos(amount) * target.z);
m_up.x = (cos(amount) * up.x) + (cos(PI / 2 + amount) * target.x);
m_up.y = (cos(amount) * up.y) + (cos(PI / 2 + amount) * target.y);
m_up.z = (cos(amount) * up.z) + (cos(PI / 2 + amount) * target.z);
Normalize(m_target);
Normalize(m_up);
}
void CCamera::RotateY( float amount )
{
Point3D target = m_target;
Point3D right = m_right;
amount = amount / 180 * PI;
m_target.x = (cos(PI / 2 + amount) * right.x) + (cos(amount) * target.x);
m_target.y = (cos(PI / 2 + amount) * right.y) + (cos(amount) * target.y);
m_target.z = (cos(PI / 2 + amount) * right.z) + (cos(amount) * target.z);
m_right.x = (cos(amount) * right.x) + (cos(PI / 2 - amount) * target.x);
m_right.y = (cos(amount) * right.y) + (cos(PI / 2 - amount) * target.y);
m_right.z = (cos(amount) * right.z) + (cos(PI / 2 - amount) * target.z);
Normalize(m_target);
Normalize(m_right);
}
void CCamera::RotateZ( float amount )
{
Point3D right = m_right;
Point3D up = m_up;
amount = amount / 180 * PI;
m_up.x = (cos(amount) * up.x) + (cos(PI / 2 - amount) * right.x);
m_up.y = (cos(amount) * up.y) + (cos(PI / 2 - amount) * right.y);
m_up.z = (cos(amount) * up.z) + (cos(PI / 2 - amount) * right.z);
m_right.x = (cos(PI / 2 + amount) * up.x) + (cos(amount) * right.x);
m_right.y = (cos(PI / 2 + amount) * up.y) + (cos(amount) * right.y);
m_right.z = (cos(PI / 2 + amount) * up.z) + (cos(amount) * right.z);
Normalize(m_right);
Normalize(m_up);
}
void CCamera::Normalize( Point3D &p )
{
float length = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
if (1 == length || 0 == length)
{
return;
}
float scaleFactor = 1.0 / length;
p.x *= scaleFactor;
p.y *= scaleFactor;
p.z *= scaleFactor;
}
The answer to this question is a combination of the following rotateTo function and a change to the code from Ray's tutorial at ( http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl ). As one of the comments on that article says there is an arbitrary factor of 2.0 being multiplied in GLKQuaternion Q_rot = GLKQuaternionMakeWithAngleAndVector3Axis(angle * 2.0, axis);. Remove that "2" and use the following function to create the _slerpEnd - after that the globe will rotate smoothly to XYZ specified.
// Rotate the globe using Slerp interpolation to an XYZ coordinate
- (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {
// Turn on the interpolation for smooth rotation
_slerping = YES; // Begin auto rotating to this location
_slerpCur = 0;
_slerpMax = 1.0;
_slerpStart = _quat;
// Create a look at vector for which we will create a GLK4Matrix from
float xEye = x;
float yEye = y;
float zEye = z;
_currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
// Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
_slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);
}
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;
}