How to convert bezier curve to box2d object? - cocos2d-iphone

I am drawing line using bezier curve and i need to convert that bezier curve into box2d object. Which object can i use in box2d? any suggestions?

Try to understand it...
+(b2ChainShape)curveWithPoints:(CGPoint*)points Times:(int)times
{
//points.count must be 3
b2ChainShape shape;
float step = 1/(float)times;
float t = 0;
b2Vec2 *p = new b2Vec2[times];
b2Vec2 v1 = [CCMethod toMeter:points[0]];
b2Vec2 v2 = [CCMethod toMeter:points[1]];
b2Vec2 v3 = [CCMethod toMeter:points[2]];
for(int i = 0;i < times;i++){
b2Vec2 pa = v1;
pa *= ( (t-1)*(t-1)*0.5 );
b2Vec2 pb = v2;
pb *= ( (-t)*t+t+0.5 );
b2Vec2 pc = v3;
pc *= ( t*t*0.5 );
p[i] = pa+pb+pc;
t+=step;
}
shape.CreateChain(p, times);
return shape;
}
The only thing you need to do next is to create body and fixture with this shape.
I hope it is hopeful to you ...

Related

Intersection in box2d not working right

I'm trying to use the code here
http://www.iforce2d.net/b2dtut/raycasting
So I can know whether a line cross a box2d object or not. It half works, in that when the line crosses the object it does show as an intersection, however, if you click before the object, it still shows as an intersection, as if it doesn't know the line stops before the object. From reading about this code, it should not do this.
Here's a screen shot of the issue.
And here's the method I'm using for the check
-(b2Vec2)rayCheckWithInput:(b2Vec2)p1 andX:(b2Vec2)p2
{
b2RayCastInput input;
input.p1 = p1;
input.p2 = p2;
input.maxFraction = 1;
//check every fixture of every body to find closest
float closestFraction = 1; //start with end of line as p2
b2Vec2 intersectionNormal(0,0);
//for (b2Body* b = self.world.world->GetBodyList(); b; b = b->GetNext()) {
for (b2Fixture* f = box.body->GetFixtureList(); f; f = f->GetNext()) {
b2RayCastOutput output;
if ( ! f->RayCast( &output, input, 0 ) )
{
NSLog(#"Not Intersected");
continue;
}
if ( output.fraction < closestFraction ) {
closestFraction = output.fraction;
intersectionNormal = output.normal;
NSLog(#"Intersected");
NSLog(#"%f %f,", output.normal.x, output.normal.y);
NSLog(#"%f", output.fraction);
}
else{
NSLog(#"Intersected2");
NSLog(#"%f %f,", output.normal.x, output.normal.y);
NSLog(#"%f", output.fraction);
}
}
//}
b2Vec2 intersectionPoint = p1 + closestFraction * (p2 - p1);
NSLog(#"I point %f, %f", intersectionPoint.x, intersectionPoint.y);
return intersectionPoint;
}
I can't see how in that check I can tell if the click point is before (no intersection) or beyond (intersection) the bird, it seems to give the same result regardless of either of those possibilities.
Any ideas?
It's a problem of unit of measure: you should convert p1 and p2 coordinates (pixel or points) to box2d coordinates (meters).

Build Circle from 3 Points in 3D space implementation in C or C++

We have 3(three) xyz points that define a circle in 3D space, this circle needs to be converted into a polyline(for further rendering). I'm looking for a ready C or C++ function or free library that can do the job.
Don't understand why this was closed. And I can't even answer my own question there. Shame on you guys. But you will not stop the knowledge spreading!
There's a much simpler solution to find the circle parameters in real 3D, just take a look at the "barycentric coordinates" section in http://en.wikipedia.org/wiki/Circumscribed_circle .
You can extract the following optimized code from that:
// triangle "edges"
const Vector3d t = p2-p1;
const Vector3d u = p3-p1;
const Vector3d v = p3-p2;
// triangle normal
const Vector3d w = t.crossProduct(u);
const double wsl = w.getSqrLength();
if (wsl<10e-14) return false; // area of the triangle is too small (you may additionally check the points for colinearity if you are paranoid)
// helpers
const double iwsl2 = 1.0 / (2.0*wsl);
const double tt = t*t;
const double uu = u*u;
// result circle
Vector3d circCenter = p1 + (u*tt*(u*v) - t*uu*(t*v)) * iwsl2;
double circRadius = sqrt(tt * uu * (v*v) * iwsl2*0.5);
Vector3d circAxis = w / sqrt(wsl);
You can then calculate the points on the circle in real 3D too and e.g. draw them using GL_LINE_STRIP in OpenGL. This should be much faster than using the 2D sin/cos approach.
// find orthogonal vector to the circle axis
const Vector3d an = circAxis.getNormalized();
const Vector3d ao = Vector3d(4.0+an[0], 4.0+an[0]+an[1], 4.0+an[0]+an[1]+an[2]).crossProduct(an).getNormalized();
// 4x4 rotation matrix around the circle axis
const int steps = 360; // maybe adjust according to circle size on screen
Matrix4d R = makeRotMatrix4d(circCenter, circAxis, 2.0*M_PI/double(steps));
// one point on the circle
Vector3d cp = circCenter + ao*circRadius;
// rotate point on the circle
for (int i=0; i<steps; ++i)
{
circlePoints.push_back(cp);
cp = transformPoint(cp, R); // apply the matrix
}
For the creation of the transformation matrix (i.e. makeRotMatrix4d()) see http://paulbourke.net/geometry/rotate/ for example.
Please note that I did not test if the above code really compiles, but it should give you enough hints.
There is a nice article and a code sample on how to build a circle by 3 points in 2D, XY plane.
http://paulbourke.net/geometry/circlesphere/
http://paulbourke.net/geometry/circlesphere/Circle.cpp
To build a 3D circle we'll have to:
rotate our 3 points into XY plane
Calculate circle center
build a circle in XY plane using the code in the article
rotate it back into it's original plane
For rotations it is best to use quaternions.
To find a correct quaternion I looked at Ogre3d source code:
void Quaternion::FromAngleAxis (const Radian& rfAngle, const Vector3& rkAxis)
There is one more useful function there:
Quaternion getRotationTo(const Vector3& dest, const Vector3& fallbackAxis = Vector3::ZERO) const
But I didn't use it.
For quaterions and vectors I used our own classes. Here is the full source code of the function that does the job:
bool IsPerpendicular(Point3d *pt1, Point3d *pt2, Point3d *pt3);
double CalcCircleCenter(Point3d *pt1, Point3d *pt2, Point3d *pt3, Point3d *center);
void FindCircleCenter(const Point3d *V1, const Point3d *V2, const Point3d *V3, Point3d *center)
{
Point3d *pt1=new Point3d(*V1);
Point3d *pt2=new Point3d(*V2);
Point3d *pt3=new Point3d(*V3);
if (!IsPerpendicular(pt1, pt2, pt3) ) CalcCircleCenter(pt1, pt2, pt3, center);
else if (!IsPerpendicular(pt1, pt3, pt2) ) CalcCircleCenter(pt1, pt3, pt2, center);
else if (!IsPerpendicular(pt2, pt1, pt3) ) CalcCircleCenter(pt2, pt1, pt3, center);
else if (!IsPerpendicular(pt2, pt3, pt1) ) CalcCircleCenter(pt2, pt3, pt1, center);
else if (!IsPerpendicular(pt3, pt2, pt1) ) CalcCircleCenter(pt3, pt2, pt1, center);
else if (!IsPerpendicular(pt3, pt1, pt2) ) CalcCircleCenter(pt3, pt1, pt2, center);
else {
delete pt1;
delete pt2;
delete pt3;
return;
}
delete pt1;
delete pt2;
delete pt3;
}
bool IsPerpendicular(Point3d *pt1, Point3d *pt2, Point3d *pt3)
// Check the given point are perpendicular to x or y axis
{
double yDelta_a= pt2->y - pt1->y;
double xDelta_a= pt2->x - pt1->x;
double yDelta_b= pt3->y - pt2->y;
double xDelta_b= pt3->x - pt2->x;
// checking whether the line of the two pts are vertical
if (fabs(xDelta_a) <= 0.000000001 && fabs(yDelta_b) <= 0.000000001){
return false;
}
if (fabs(yDelta_a) <= 0.0000001){
return true;
}
else if (fabs(yDelta_b) <= 0.0000001){
return true;
}
else if (fabs(xDelta_a)<= 0.000000001){
return true;
}
else if (fabs(xDelta_b)<= 0.000000001){
return true;
}
else
return false ;
}
double CalcCircleCenter(Point3d *pt1, Point3d *pt2, Point3d *pt3, Point3d *center)
{
double yDelta_a = pt2->y - pt1->y;
double xDelta_a = pt2->x - pt1->x;
double yDelta_b = pt3->y - pt2->y;
double xDelta_b = pt3->x - pt2->x;
if (fabs(xDelta_a) <= 0.000000001 && fabs(yDelta_b) <= 0.000000001){
center->x= 0.5*(pt2->x + pt3->x);
center->y= 0.5*(pt1->y + pt2->y);
center->z= pt1->z;
return 1;
}
// IsPerpendicular() assure that xDelta(s) are not zero
double aSlope=yDelta_a/xDelta_a; //
double bSlope=yDelta_b/xDelta_b;
if (fabs(aSlope-bSlope) <= 0.000000001){ // checking whether the given points are colinear.
return -1;
}
// calc center
center->x= (aSlope*bSlope*(pt1->y - pt3->y) + bSlope*(pt1->x + pt2 ->x)
- aSlope*(pt2->x+pt3->x) )/(2* (bSlope-aSlope) );
center->y = -1*(center->x - (pt1->x+pt2->x)/2)/aSlope + (pt1->y+pt2->y)/2;
return 1;
}
//! Builds a circle in 3D space by 3 points on it and an optional center
void buildCircleBy3Pt(const float *pt1,
const float *pt2,
const float *pt3,
const float *c, // center, can be NULL
std::vector<float> *circle)
{
/* Get the normal vector to the triangle formed by 3 points
Calc a rotation quaternion from that normal to the 0,0,1 axis
Rotate 3 points using quaternion. Points will be in XY plane
Build a circle by 3 points on XY plane
Rotate a circle back into original plane using quaternion
*/
Point3d p1(pt1[0], pt1[1], pt1[2]);
Point3d p2(pt2[0], pt2[1], pt2[2]);
Point3d p3(pt3[0], pt3[1], pt3[2]);
Point3d center;
if (c)
{
center.set(c[0], c[1], c[2]);
}
const Vector3d p2top1 = p1 - p2;
const Vector3d p2top3 = p3 - p2;
const Vector3d circle_normal = p2top1.crossProduct(p2top3).normalize();
const Vector3d xy_normal(0, 0, 1);
Quaternion rot_quat;
// building rotation quaternion
{
// Rotation axis around which we will rotate our circle into XY plane
Vector3d rot_axis = xy_normal.crossProduct(circle_normal).normalize();
const double rot_angle = xy_normal.angleTo(circle_normal); // radians
const double w = cos(rot_angle * 0.5);
rot_axis *= sin(rot_angle * 0.5);
rot_quat.set(w, rot_axis.x, rot_axis.y, rot_axis.z);
}
Quaternion rot_back_quat;
// building backward rotation quaternion, same as prev. but -angle
{
const double rot_angle = -(xy_normal.angleTo(circle_normal)); // radians
const double w_back = cos(rot_angle * 0.5);
Vector3d rot_back_axis = xy_normal.crossProduct(circle_normal).normalize();
rot_back_axis *= sin(rot_angle * 0.5);
rot_back_quat.set(w_back, rot_back_axis.x, rot_back_axis.y, rot_back_axis.z);
}
rot_quat.rotate(p1);
rot_quat.rotate(p2);
rot_quat.rotate(p3);
rot_quat.rotate(center);
if (!c)
{
// calculate 2D center
FindCircleCenter(&p1, &p2, &p3, &center);
}
// calc radius
const double radius = center.distanceTo(p1);
const float DEG2RAD = 3.14159f / 180.0f;
// build circle
for (int i = 0; i < 360; ++i)
{
float degInRad = i * DEG2RAD;
Point3d pt(cos(degInRad) * radius + center.x, sin(degInRad) * radius + center.y, 0);
// rotate the point back into original plane
rot_back_quat.rotate(pt);
circle->push_back(pt.x);
circle->push_back(pt.y);
circle->push_back(pt.z);
}
}
The following is the C#/Unity port of Mark's answer. It uses types and utility functions from Unity's scripting API.
// triangle "edges"
var t = p2 - p1;
var u = p3 - p1;
var v = p3 - p2;
// triangle normal
var w = Vector3.Cross(t, u);
var wsl = Vector3.Dot(w, w);
// TODO: if (wsl<10e-14) return false; // area of the triangle is too small (you may additionally check the points for colinearity if you are paranoid)
// helpers
var iwsl2 = 1f / (2f * wsl);
var tt = Vector3.Dot(t, t);
var uu = Vector3.Dot(u, u);
// result circle
Vector3 circCenter = p1 + (u * tt * (Vector3.Dot(u, v)) - t * uu * (Vector3.Dot(t, v))) * iwsl2;
var circRadius = Mathf.Sqrt(tt * uu * (Vector3.Dot(v, v)) * iwsl2 * 0.5f);
Vector3 circAxis = w / Mathf.Sqrt(wsl);
Using Unity's Gizmos, the circle can be drawn as follows (using 30 line segments to approximate it in this case):
// Draw the circle:
Gizmos.color = Color.white;
for (int i = 0; i < 30; ++i)
{
Gizmos.DrawLine(
circCenter + Quaternion.AngleAxis(360f / 30f * i , circAxis) * (p1 - circCenter),
circCenter + Quaternion.AngleAxis(360f / 30f * (i + 1), circAxis) * (p1 - circCenter)
);
}
The result looks like follows for vertex positions var p1 = new Vector3(0f, 1.44f, 0f); var p2 = new Vector3(0f, 0.73f, 0.65f); var p3 = new Vector3(0f, -1.04f, 0f);:

OpenCV StereoRectifyUncalibrated to 3D Point Cloud

I have some code that works out all of the parts up to calculating values with cv::stereoRectifyUncalibrated. However, I am not sure where to go from there to get a 3D Point cloud from it.
I have code that works with the calibrated version that gives me a Q matrix and I then use that with reprojectImageTo3D and StereoBM to give me a point cloud.
I want to compare the results of the two different methods as sometimes I will not be able to calibrate the camera.
http://blog.martinperis.com/2012/01/3d-reconstruction-with-opencv-and-point.html I think this will be helpful. It has a code which converts Disparity Image to Point cloud using PCL and shows in 3D viewer.
Since you have Q, two images and other camera params(from calibration), you should use ReprojectTo3D to get depth map.
Use StereoBM or stereoSGBM to get Disparity Map and use that Disparit Map and Q to get depth image.
StereoBM sbm;
sbm.state->SADWindowSize = 9;
sbm.state->numberOfDisparities = 112;
sbm.state->preFilterSize = 5;
sbm.state->preFilterCap = 61;
sbm.state->minDisparity = -39;
sbm.state->textureThreshold = 507;
sbm.state->uniquenessRatio = 0;
sbm.state->speckleWindowSize = 0;
sbm.state->speckleRange = 8;
sbm.state->disp12MaxDiff = 1;
sbm(g1, g2, disp); // g1 and g2 are two gray images
reprojectImageTo3D(disp, Image3D, Q, true, CV_32F);
And that code basically converts depth map to Point cloud.
pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr (new pcl::PointCloud<pcl::PointXYZRGB>);
double px, py, pz;
uchar pr, pg, pb;
for (int i = 0; i < img_rgb.rows; i++)
{
uchar* rgb_ptr = img_rgb.ptr<uchar>(i);
uchar* disp_ptr = img_disparity.ptr<uchar>(i);
double* recons_ptr = recons3D.ptr<double>(i);
for (int j = 0; j < img_rgb.cols; j++)
{
//Get 3D coordinates
uchar d = disp_ptr[j];
if ( d == 0 ) continue; //Discard bad pixels
double pw = -1.0 * static_cast<double>(d) * Q32 + Q33;
px = static_cast<double>(j) + Q03;
py = static_cast<double>(i) + Q13;
pz = Q23;
// Normalize the points
px = px/pw;
py = py/pw;
pz = pz/pw;
//Get RGB info
pb = rgb_ptr[3*j];
pg = rgb_ptr[3*j+1];
pr = rgb_ptr[3*j+2];
//Insert info into point cloud structure
pcl::PointXYZRGB point;
point.x = px;
point.y = py;
point.z = pz;
uint32_t rgb = (static_cast<uint32_t>(pr) << 16 |
static_cast<uint32_t>(pg) << 8 | static_cast<uint32_t>(pb));
point.rgb = *reinterpret_cast<float*>(&rgb);
point_cloud_ptr->points.push_back (point);
}
}
point_cloud_ptr->width = (int) point_cloud_ptr->points.size();
point_cloud_ptr->height = 1;
//Create visualizer
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
viewer = createVisualizer( point_cloud_ptr );

Box2d & Cocos2d properly point of colision

I have collision detection in my game. Now I need point of collison.
I get it with:
int numPoints = contact.b2contact->GetManifold()->pointCount;
b2WorldManifold worldManifold;
contact.b2contact->GetWorldManifold( &worldManifold );
for (int i = 0; i < numPoints; i++)
{
NSLog(#"%#" NSStringFormCGPoint(ccp(worldManifold.points[i].x,worldManifold.points[i].y));
}
This log shows position but in box2d standards. How I should properly convert it to Cocos2d v2 cords? Because multiply by PTM_RATIO not working very well.
UPDATE
At this moment I came up with this.
b2Manifold* mainfold = contact->GetManifold();
int numPoints = mainfold->pointCount;
for (int i=0; i<numPoints; i++) {
b2ManifoldPoint *p = mainfold->points;
NSLog(#"Dot:%#",NSStringFromCGPoint(ccp(p->localPoint.x * PTM_RATIO, p->localPoint.y * PTM_RATIO);));
}
But that shows correct point only for one body.
I think your first example was correct, but you were not properly converting the points to world points. Something like this might work (I'm not at my computer to test it out, but I think this will give you the right direction anyway.
int numPoints = contact.b2contact->GetManifold()->pointCount;
b2WorldManifold worldManifold;
contact.b2contact->GetWorldManifold( &worldManifold );
for (int i = 0; i < numPoints; i++)
{
b2Vec2 worldPoint = worldManifold.points[i]->GetWorldPoint();
NSLOG(#"(%f,%f)", worldPoint.x*PTM_RATIO, worldPoint.y*PTM_RATIO);
}

How to draw a curved line using ccBezier?

I drew a line with -(void)draw method:
-(void)draw // code for line draw
{
glEnable(GL_LINE_SMOOTH);
CGPoint start;
start.x = 50;
start.y = 50;
CGPoint end;
end.x = 50;
end.y = 200;
if (pointOne.x>300){
pointOne.x = 300;
}
if (pointOne.y>200){
pointOne.y = 200;
}
ccDrawLine(start, pointOne);//get a line
[self Bezier:location.x:location.y:pointOne.x:pointOne.y];
}
and now I want to curve this line through Bezier in cocos2d. When I move finger that time line should draw the curve.
Bezier Code is:
- (void) Bezier:(NSInteger) CP_x:(NSInteger) CP_y:(NSInteger) end_x:(NSInteger) end_y
{
CGPoint start;
start.x = 50;
start.y = 50;
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(CP_x, CP_y);
bezier.controlPoint_2 = ccp(CP_x,CP_y);
bezier.endPosition = ccp(end_x,end_y);
}
How can I implement this line in bezier?
try this.
CCDrawBezier in last of your -(void)Bezier methord
ccDrawCubicBezier(StartPoint, controlPoint_1, controlPoint_2, EndPoint,NSInteger);
This is a method is wrote to my game.
//Bezier calculation on multiple points
//Can be set to any number of points
//The t parameter is the time 0 = start point -> 1 = end point.
//Made by Sebastian Winbladh
-(CGPoint)getBezerAtTime:(float)t array:(NSArray*)a{
int count = [a count];
float xPoints[count],yPoints[count];
int c=0;
//Makeup an array for our points
for(int i=0;i<count;i++){
CGPoint p = CGPointMake([[[a objectAtIndex:i] objectAtIndex:0] floatValue], [[[a objectAtIndex:i] objectAtIndex:1] floatValue]);
xPoints[i] = p.x;
yPoints[i] = p.y;
c++;
}
//Calculate our bezier curve here
while(c != 0){
for(int i=0;i<c-1;i++){
CGPoint p0 = CGPointMake(xPoints[i], yPoints[i]);
CGPoint p1 = CGPointMake(xPoints[i+1], yPoints[i+1]);
float dx = p1.x - p0.x;
float dy = p1.y - p0.y;
dx = p0.x + (dx * t);
dy = p0.y + (dy * t);
xPoints[i] = dx;
yPoints[i] = dy;
}c--;
}
return CGPointMake(xPoints[0], yPoints[0]);
}