Seems there is no way to compute line line intersection using boost::geometry, but I wonder what is the most common way to do it in C++?
I need intersection algorithms for two infinite lines in 2D, if it will be faster it can be two different functions like:
bool line_intersection(line,line);
point line_intersetion(line,line);
P.S. I really try to avoid a wheel invention, so incline to use some library.
The best algorithms that I've found for finding the intersection of lines are in: Real Time Collision Detection by Christer Ericson, a copy of the book can be found here.
Chapter 5 from page 146 onwards describes how to find the closest point of 3D lines which is also the crossing point of 2D lines... with example code in C.
Note: beware of parallel lines, they can cause divide by zero errors.
Express one of the lines in parametric form and the other in implicit form:
X = X0 + t (X1 - X0), Y= Y0 + t (Y1 - Y0)
S(X, Y) = (X - X2) (Y3 - Y2) - (Y - Y2) (X3 - X2) = 0
By linearity of the relations, you have
S(X, Y) = S(X0, Y0) + t (S(X1, Y1) - S(X0, Y0)) = S0 + t (S1 - S0) = 0
From this you get t, and from t the coordinates of the intersection.
It takes a total of 15 adds, 6 multiplies and a single divide.
Degeneracy is indicated by S1 == S0, meaning that the lines are parallel. In practice, the coordinates may not be exact because of truncation errors or others, so that test for equality to 0 can fail. A workaround is to consider the test
|S0 - S1| <= µ |S0|
for small µ.
You can try my code, I'm using boost::geometry and I put a small test case in the main function.
I define a class Line with two points as attributes.
Cross product is very a simple way to know if two lines intersect. In 2D, you can compute the perp dot product (see perp function) that is a projection of cross product on the normal vector of 2D plane. To compute it, you need to get a direction vector of each line (see getVector method).
In 2D, you can get the intersection point of two lines using perp dot product and parametric equation of line. I found an explanation here.
The intersect function returns a boolean to check if two lines intersect. If they intersect, it computes the intersection point by reference.
#include <cmath>
#include <iostream>
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
namespace bg = boost::geometry;
// Define two types Point and Vector for a better understanding
// (even if they derive from the same class)
typedef bg::model::d2::point_xy<double> Point;
typedef bg::model::d2::point_xy<double> Vector;
// Class to define a line with two points
class Line
{
public:
Line(const Point& point1,const Point& point2): p1(point1), p2(point2) {}
~Line() {}
// Extract a direction vector
Vector getVector() const
{
Vector v(p2);
bg::subtract_point(v,p1);
return v;
}
Point p1;
Point p2;
};
// Compute the perp dot product of vectors v1 and v2
double perp(const Vector& v1, const Vector& v2)
{
return bg::get<0>(v1)*bg::get<1>(v2)-bg::get<1>(v1)*bg::get<0>(v2);
}
// Check if lines l1 and l2 intersect
// Provide intersection point by reference if true
bool intersect(const Line& l1, const Line& l2, Point& inter)
{
Vector v1 = l1.getVector();
Vector v2 = l2.getVector();
if(std::abs(perp(v1,v2))>0.)
{
// Use parametric equation of lines to find intersection point
Line l(l1.p1,l2.p1);
Vector v = l.getVector();
double t = perp(v,v2)/perp(v1,v2);
inter = v1;
bg::multiply_value(inter,t);
bg::add_point(inter,l.p1);
return true;
}
else return false;
}
int main(int argc, char** argv)
{
Point p1(0.,0.);
Point p2(1.,0.);
Point p3(0.,1.);
Point p4(0.,2.);
Line l1(p1,p2);
Line l2(p3,p4);
Point inter;
if( intersect(l1,l2,inter) )
{
std::cout<<"Coordinates of intersection: "<<inter.x()<<" "<<inter.y()<<std::endl;
}
return 0;
}
EDIT: more detail on cross product and perp dot product + delete tol argument (off topic)
This code should work for you. You may be able to optimize it a bit:
template <class Tpoint>
Tpoint line<Tpoint>::intersect(const line& other) const{
Tpoint x = other.first - first;
Tpoint d1 = second - first;
Tpoint d2 = other.second - other.first;
auto cross = d1.x*d2.y - d1.y*d2.x;
auto t1 = (x.x * d2.y - x.y * d2.x) / static_cast<float>(cross);
return first + d1 * t1;
}
Perhaps a common way is to approximate the infinity? From my library using boost::geometry:
// prev and next are segments and RAY_LENGTH is a very large constant
// create 'lines'
auto prev_extended = extendSeg(prev, -RAY_LENGTH, RAY_LENGTH);
auto next_extended = extendSeg(next, -RAY_LENGTH, RAY_LENGTH);
// intersect!
Points_t isection_howmany;
bg::intersection(prev_extended, next_extended, isection_howmany);
then you could test whether the 'lines' intersect like this:
if (isection_howmany.empty())
cout << "parallel";
else if (isection_howmany.size() == 2)
cout << "collinear";
extendSeg() simply extends the segment in both directions by the given amounts.
Also bear in mind - to support an infinite line arithmetic the point type should also support an infinite value. However here the assumption is that you are looking for a numerical solution!
To solve this problem, I pieced together the following function, but unexpectedly found that it cannot calculate the intersection of line segments, but the intersection of lines.
class Solution {
typedef complex<double> point;
#define x real()
#define y imag()
struct LinePara
{
double k;
double b;
};
LinePara getLinePara(float x1, float y1, float x2, float y2)
{
LinePara ret;
double m = x2 - x1;
if (m == 0)
{
ret.k = 1000.0;
ret.b = y1 - ret.k * x1;
}
else
{
ret.k = (y2 - y1) / (x2 - x1);
ret.b = y1 - ret.k * x1;
}
return ret;
}
struct line {
double a, b, c;
};
const double EPS = 1e-6;
double det(double a, double b, double c, double d) {
return a * d - b * c;
}
line convertLineParaToLine(LinePara s)
{
return line{ s.k,-1,s.b };
}
bool intersect(line m, line n, point& res) {
double zn = det(m.a, m.b, n.a, n.b);
if (abs(zn) < EPS)
return false;
res.real(-det(m.c, m.b, n.c, n.b) / zn);
res.imag(-det(m.a, m.c, n.a, n.c) / zn);
return true;
}
bool parallel(line m, line n) {
return abs(det(m.a, m.b, n.a, n.b)) < EPS;
}
bool equivalent(line m, line n) {
return abs(det(m.a, m.b, n.a, n.b)) < EPS
&& abs(det(m.a, m.c, n.a, n.c)) < EPS
&& abs(det(m.b, m.c, n.b, n.c)) < EPS;
}
vector<double> mian(vector<vector<double>> line1, vector<vector<double>> line2)
{
vector<point> points;
points.push_back(point(line1[0][0], line1[0][1]));
points.push_back(point(line1[1][0], line1[1][1]));
points.push_back(point(line2[0][0], line2[0][1]));
points.push_back(point(line2[1][0], line2[1][1]));
line li1 = convertLineParaToLine(getLinePara(line1[0][0], line1[0][1], line1[1][0], line1[1][1]));
line li2 = convertLineParaToLine(getLinePara(line2[0][0], line2[0][1], line2[1][0], line2[1][1]));
point pos;
if (intersect(li1, li2, pos))
{
return{ pos.x ,pos.y };
}
else
{
if (equivalent(li1, li2)) {
if (points[1].x < points[2].x)
{
return vector<double>{ points[1].x, points[1].y };
}
else if (points[1].x > points[2].x)
{
return vector<double>{ points[2].x, points[2].y };
}
else if (points[1].x == points[2].x)
{
if (points[1].y < points[2].y)
{
return vector<double>{ points[1].x, points[1].y };
}
else if (points[1].y > points[2].y)
{
return vector<double>{ points[2].x, points[2].y };
}
}
else
{
return vector<double>{ points[2].x, points[2].y };
}
}
else
{
return {}/* << "平行!"*/;
}
return {};
}
}
public:
vector<double> intersection(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
vector<vector<double>> line1{ {(double)start1[0],(double)start1[1]},{(double)end1[0],(double)end1[1] } };
vector<vector<double>> line2{ {(double)start2[0],(double)start2[1]},{(double)end2[0],(double)end2[1] } };
return mian(line1, line2);
}
};
From there
Related
The following is the three vertices with x,y and z co-ordinates of a triangle in 3D:
-0.2035416, 0.1107585, 0.9516008 (vertex A)
-0.0334390, -0.2526040, 0.9751212 (vertex B)
0.2569092, 0.0913718, 0.9817184 (Vertex C)
The projection plane is divided into a grid of (height*width) pixels.
I want to traverse every pixel inside the triangle inside the projection plane manually starting from the bottom to top of the triangle and print each pixel co-ordinates inside the triangle on the screen in c++. Say, I have already found the top and bottom vertex of the triangle. But now, how will I traverse from bottom to top and print each pixel co-ordinate? What's the logic behind this?
I have an idea of making two nested for loops like below but what will I do inside the loops? how will I make the sideway move after each x and y increment?
for (int y = ymin; y <= ymax; ++y) {
for (int x = xmin; x <= xmax; ++x) {
//what to to here?
}
}
Traversing demo:
#include <iostream>
template <size_t kD>
class Vector{
public:
template <class... Args>
Vector(double coord, Args&&... args) {
static_assert( sizeof...(args)+1 == kD, "Unmatched vector dimension" );
InitCoord(0, coord, std::forward<Args>(args)...);
}
Vector(const Vector &) = default;
Vector &operator=(const Vector &) = default;
double &operator[](const size_t i) {
return coord_[i];
}
double operator[](const size_t i) const {
return coord_[i];
}
friend Vector<kD> operator-(const Vector<kD> &A, const Vector<kD> &B) {
Vector v;
for (size_t i=0; i<kD; ++i)
v[i] = A[i]-B[i];
return v;
}
private:
Vector() = default;
template <class... Args>
void InitCoord(const int pos, double coord, Args&&... args) {
coord_[pos] = coord;
InitCoord(pos+1, std::forward<Args>(args)...);
}
void InitCoord(const int pos) {}
double coord_[kD];
};
class Line {
public:
Line(const double x1, const double y1, const double x2, const double y2)
: x1_(x1), y1_(y1), x2_(x2), y2_(y2) {}
Line(const Vector<2> A, const Vector<2> B)
: x1_(A[0]), y1_(A[1]), x2_(B[0]), y2_(B[1]) {}
double operator()(const double x, const double y) const {
return (y-y1_)*(x2_-x1_) - (x-x1_)*(y2_-y1_);
}
int_fast8_t Sign(const double x, const double y) const {
return Signum( (y-y1_)*(x2_-x1_) - (x-x1_)*(y2_-y1_) );
}
private:
int_fast8_t Signum(const double x) const {
return (0.0 < x) - (x < 0.0);
}
const double x1_,y1_;
const double x2_,y2_;
};
void Transpos(Vector<2> &v) {
v[0] = (v[0]+1)/2*720; // col
v[1] = (v[1]+1)/2*480; // row
}
double CalculateZ(const Vector<2> &D, const Vector<2> &AB, const Vector<2> &AC,
const Vector<3> &AB3, const Vector<3> &AC3) {
const double b = (D[1]*AB[0]-D[0]*AB[1]) / (AC[1]*AB[0]-AC[0]*AB[1]);
const double a = AB[0]==0 ? (D[1]-b*AC[1])/AB[1] : (D[0]-b*AC[0])/AB[0];
std::cout << a << " " << b << std::endl;
return a*AB3[2]+b*AC3[2];
}
int main()
{
const auto A3 = Vector<3>(0.0, 0.0, 7.0);
const auto B3 = Vector<3>(0.0, 0.3, 9.0);
const auto C3 = Vector<3>(0.4, 0.0, 1.0);
const auto AB3 = B3-A3;
const auto AC3 = C3-A3;
const auto BC3 = C3-B3;
// Some projection works here, which I am not good at.
// A B C store the projected triangle coordiate in the [-1,1][-1,1] area
auto A = Vector<2>(0.0, 0.0);
auto B = Vector<2>(0.0, 0.3);
auto C = Vector<2>(0.4, 0.0);
Transpos(A);
Transpos(B);
Transpos(C);
const auto AB2 = B-A;
const auto AC2 = C-A;
const auto BC2 = C-B;
const Line AB(A, B);
const Line AC(A, C);
const Line BC(B, C);
const auto signAB = AB.Sign(C[0],C[1]);
const auto signAC = AC.Sign(B[0],B[1]);
const auto signBC = BC.Sign(A[0],A[1]);
// top
// 0------------720 (col x)
// |
// |
// |
// |
// 480 (row y)
// bottom
for (int row=480-1; row>=0; --row) {
for (int col=0; col<720; ++col) {
if (signAB*AB.Sign(col,row)>=0 && signAC*AC.Sign(col,row)>=0 &&
signBC*BC.Sign(col,row)>=0 )
std::cout << row << "," << col << " Z:"
<< CalculateZ(Vector<2>(col, row)-A, AB2, AC2, AB3, AC3) + A3[2]
<< std::endl;
}
}
return 0;
}
Projection:
first space [-1,1][-1,1]
second space [0,720][0,480]
Let's say we have a (x1,y1) in the first space, then (x_,y_) with x_=(x1+1)/2*720, y_=(y1+1)/2*480 will be in the second space.
More generalize:
first space [xmin,xmax][ymin,ymax]
second space [xmin_,xmax_][ymin_,ymax_]
(x1,y1)
->
( (x1-xmin)/(xmax-xmin)*(xmax_-xmin_)+xmin_ ,
(y1-ymin)/(ymax-ymin)*(ymax_-ymin_)+ymin_ )
If you just want to zoom it, not twist it or something...
Edit #1:
Thanks to #Adrian Colomitchi's advices, which is outstanding, I have
improved the demo.
Ax Ay Bx By Cx Cy are now coordinates in the first space, they are
then "transposed" into the second space. As a result, Line AB AC BC
are now "in" the second space. And the two loops are modified
accordingly, they now iterate the points of the second space.
How to find z value from (x,y):
AB represents a vector from A(Ax,Ay) to B(Bx,By), i.e. AB = B-A = (Bx-Ax,By-Ay).
For any given point D(Dx,Dy) in the triangle, represent it into AD = aAB + bAC : (Dx-Ax, Dy-Ay) = a*(Bx-Ax, By-Ay) + b*(Cx-Ax, Cy-Ay) where Dx Dy Ax Ay Bx By Cx Cy is known. Find out a and b, and then Dz = a*(Bz-Az) + b*(Cz-Az). Dx Dy in the 3D space can be calculated the same way.
Edit #2:
Z value calculation added to the demo.
I tried to keep the demo simple, but calculating the Z value really involved lots of variables and calculations. I declare a new class called Vector to manage points and vectors, while the Line class remains unchanged.
You need to change the inner loop slightly; don't go from xmin to xmax. For each value of y from ymin to ymax there will be exactly two different pixels (two different x values) which lie exactly on the two edges of the triangle. Calculate those points and then all points between them will be inside the triangle. And you'll have to handle some edge cases such as when one of the edges is horizontal.
First you must transform your {0,1} ranges (vert & horz) to pixel coordinates. You speak of 720x480. This is not a square, but a rectangle. If you decide to keep one-to-one scale, you'll get a distorted triangle. If not, perhaps you only use 480x480 pixels.
Second, now you have your three vertices in pixel-space, you can iterate every pixel in this pixel-space and tell if it belongs to the triangle or not. The function 'InTriangle' for this job is what #felix posted in the code of his solution:
if (signAB*AB(i,j)>=0 && signAC*AC(i,j)>=0 && signBC*BC(i,j)>=0 )
I am using C++ set container to remove duplicates, but am having a problem with a user-defined class. I defined the comparison operator as below and it works well:
bool operator < (const TLineSegment& other) const
{
int cx1 = (int)((x1 + x2) / 2.0);
int cy1 = (int)((y1 + y2) / 2.0);
int cx2 = (int)((other.x1 + other.x2) / 2.0);
int cy2 = (int)((other.y1 + other.y2) / 2.0);
if (cx1 == cx2)
return (cy1 < cy2);
else
return (cx1 < cx2);
}
However, the below code by adding more condition (no duplicate within a certain range) contains a very few duplicates. I found it working in most cases, but it sometimes doesn't work, really weird. One case I found was two TLineSegments are the same (but not the same instance) and both of them were inserted.
bool operator < (const TLineSegment& other) const
{
const int epi = 5;
int cx1 = (int)((x1 + x2) / 2.0);
int cy1 = (int)((y1 + y2) / 2.0);
int cx2 = (int)((other.x1 + other.x2) / 2.0);
int cy2 = (int)((other.y1 + other.y2) / 2.0);
if (abs(cx1 - cx2) < epi) {
if (abs(cy1 - cy2) < epi) {
return false;
}
else {
return (cy1 < cy2);
}
}
else {
return (cx1 < cx2);
}
Let's compare the line segment (-n,0):(n,0) to the line segment (-x,-y):(x,y). So (cx1,cy1) and (cx2,cy2) are both (0,0). For both implementations of operator<, the result will be false in either direction, which implies that the two line segments are equivalent. That is, any line segment centered at (0,0) is equivalent to every other such line segment?!
This is obviously incorrect.
The simplest thing is to take advantage of std::tuple having operator< defined and do:
std::tuple<int, int, int, int> tied() const {
// can be just auto in C++14. typically I'd say use std::tie()
// but we're dealing with ints right?
return std::make_tuple(x1, y1, x2, y2);
}
bool operator < (const TLineSegment& other) const
{
return tied() < other.tied();
}
I defined the following map:
class xy_angle {
public:
int x;
int y;
int angle;
xy_angle(int x, int y, int angle) :x(x), y(y), angle(angle){};
};
class xy_angleComparator {
public:
bool operator () (const xy_angle &a, const xy_angle &b) const {
if (a.x != b.x)
return a.x < b.x;
else if (a.y != b.y)
return a.y < b.y;
else if (a.angle != b.angle)
return a.angle < b.angle;
else
return false;
}
};
std::map<xy_angle, std::pair<int, int>, xy_angleComparator> transformed_coordinates_lut_;
I fill it up when I initialize the class that contains it:
//creating LUTs
int half_patch_size=48;
for (int x_start = -half_patch_size; x_start <= half_patch_size; x_start++){
for (int y_start = -half_patch_size; y_start <= half_patch_size; y_start++){
for (int angle = -314; angle < 314; angle++){
float angle_f = (float)angle / 100.f;
double cos_theta = cos(angle_f);
double sin_theta = sin(angle_f);
int x_tranformed = (int)(((float)x_start)*cos_theta - ((float)y_start)*sin_theta);
int y_tranformed = (int)(((float)x_start)*sin_theta + ((float)y_start)*cos_theta);
if (x_tranformed > half_patch_size)
x_tranformed = half_patch_size;
if (x_tranformed < -half_patch_size)
x_tranformed = -half_patch_size;
if (y_tranformed > half_patch_size)
y_tranformed = half_patch_size;
if (y_tranformed < -half_patch_size)
y_tranformed = -half_patch_size;
transformed_coordinates_lut_[xy_angle(x_start, y_start, angle)] = std::pair<int, int>(x_tranformed, y_tranformed);
}
}
}
And I access it using the following code:
int ax2 = transformed_coordinates_lut_[xy_angle(ax, ay, theta)].first;
int ay2 = transformed_coordinates_lut_[xy_angle(ax, ay, theta)].second;
I measured the map's access running time using a large set of random keys and it's quite insane. It totally dominates the running time of the functions that uses it.
It there any way to speed it up?
Thanks!
Gil.
You can use a 3-D array instead: f[x_start][y_start][angle]. It would occupy the same(or less) space because you have all possible keys anyway. Of course, you can also emulate a 3-D array with a flat vector using appropriate indices. This approach guarantees you constant time lookup.
Regardless of which container you use, this code is bad:
int ax2 = transformed_coordinates_lut_[xy_angle(ax, ay, theta)].first;
int ay2 = transformed_coordinates_lut_[xy_angle(ax, ay, theta)].second;
You're doing the same lookup twice! Definitely cache the result:
auto& a2 = transformed_coordinates_lut_[xy_angle(ax, ay, theta)];
int ax2 = a2.first;
int ay2 = a2.second;
Now as far as speeding up the work goes. The least work up front would be just to sub out a different associative container type:
using MapType = std::unordered_map<xy_angle,
std::pair<int, int>,
xy_angle_hash>; // implement this hash
That will give you O(1) lookup instead of the O(lg N) you are currently seeing in your code with std::map. But if you really want to spend a lot of time exploring this container, I'd suggest just wrapping it so you can control the implementation:
class TransformMap
{
public:
std::pair<int, int>& operator()(const xy_angle& );
private:
// is it std::map?
// or std::unordered_map?
// or 3D-array or vector or ... ?
};
If I have a simple 2-D matrix with normalized values on x-axis between 0 and 1 and y-axys between 0 and 1, and I have 3 points in this matrix e.g. P1 (x=0.2,y=0.9), P2 (x=0.5,y=0.1) and P3 (x=0.9,y=0.4).
How can I simply calculate a curve thru this points, meaning having a function which is giving me the y for any x.
I now that there are any number of possible curves thru 3 points. But hey, you know what I mean: I want a smooth curve thru it, usable for audio-sample-interpolation, usable for calculation a volume-fade-curve, usable for calculating a monster-walking-path in a game.
Now I have searched the net for this question about 3 days, and I cannot believe that there is no usable solution for this task. All the text dealing about Catmull-rom-Splines, bezier-curves and all that theroretical stuff has all at least one point which doesn't make it for me usable. For example Catmull-Rom-splines need to have a fix distance between the control-points (I would use this code and set the 4. point-y to the 3. point y) :
void CatmullRomSpline(float *x,float *y,float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4,float u)
{
//x,y are calculated for x1,y1,x2,y2,x3,y3 and x4,y4 if u is the normalized distance (0-1) in relation to the distance between x2 and x3 for my whiched point
float u3,u2,f1,f2,f3,f4;
u3=u*u*u;
u2=u*u;
f1=-0.5f * u3 + u2 -0.5f *u;
f2= 1.5f * u3 -2.5f * u2+1.0f;
f3=-1.5f * u3 +2.0f * u2+0.5f*u;
f4=0.5f*u3-0.5f*u2;
*x=x1*f1+x2*f2+x3*f3+x4*f4;
*y=y1*f1+y2*f2+y3*f3+y4*f4;
}
But I don't see that x1 to x4 have any affect on the calculation of y, so I think x1 to x4 must have the same distance?
...
Or bezier-code doesn't calcuate the curve thru the points. The points (at least the 2. point) seem only to have a force-effect on the line.
typedef struct Point2D
{
double x;
double y;
} Point2D;
class bezier
{
std::vector<Point2D> points;
bezier();
void PushPoint2D( Point2D point );
Point2D GetPoint( double time );
~bezier();
};
void bezier::PushPoint2D(Point2D point)
{
points.push_back(point);
}
Point2D bezier::GetPoint( double x )
{
int i;
Point2D p;
p.x=0;
p.y=0;
if( points.size() == 1 ) return points[0];
if( points.size() == 0 ) return p;
bezier b;
for (i=0;i<(int)points.size()-1;i++)
{
p.x = ( points[i+1].x - points[i].x ) * x + points[i].x;
p.y = ( points[i+1].y - points[i].y ) * x + points[i].y;
if (points.size()<=2) return p;
b.PushPoint2D(p);
}
return b.GetPoint(x);
}
double GetLogicalYAtX(double x)
{
bezier bz;
Point2D p;
p.x=0.2;
p.y=0.9;
bz.PushPoint2D(p);
p.x=0.5;
p.y=0.1;
bz.PushPoint2D(p);
p.x=0.9;
p.y=0.4;
bz.PushPoint2D(p);
p=bz.GetPoint(x);
return p.y;
}
This is better than nothing, but it is 1. very slow (recursive) and 2. as I said doesn't really calculate the line thru the 2. point.
Is there a mathematical brain outside which could help me?
Thank you TOCS (Scott) for providing your code, I will also try it if I have some time. But what I have tested now is the hint by INFACT (answer 3): This "Largrange polynomials" are very very close to what I am searching for:
I have renamed my class bezier to curve, because I have added some code for lagrangeinterpolation. I also have added 3 pictures of graphical presentation what the code is calculation.
In Picture 1 you can see the loose middle point of the old bezier-function.
In Picture 2 you can now see the going thru all-points-result of lagrange interpolation.
In Picture 3 you can see the only problem, or should I say "thing which I also need to be solved" (anyway its the best solution till now): If I move the middle point, the curve to going to fast, to quick to the upper or lower boundaries). I would like it to go more smoothely to the upper and lower. So that it looks more logarithm-function like. So that it doesn't exeed the y-boundaries between 0 and 1 too soon.
Now my code looks like this:
curve::curve(void)
{
}
void curve::PushPoint2D(Point2D point)
{
points.push_back(point);
}
Point2D curve::GetPoint( double x )
{
//GetPoint y for x with bezier-mathematics...
//was the only calculating function in old class "bezier"
//now the class is renamed "curve"
int i;
Point2D p;
p.x=0;
p.y=0;
if( points.size() == 1 ) return points[0];
if( points.size() == 0 ) return p;
curve b;
for (i=0;i<(int)points.size()-1;i++)
{
p.x = ( points[i+1].x - points[i].x ) * x + points[i].x;
p.y = ( points[i+1].y - points[i].y ) * x + points[i].y;
if (points.size()<=2) return p;
b.PushPoint2D(p);
}
return b.GetPoint(x);
}
//THIS IS NEW AND VERY VERY COOL
double curve::LagrangeInterpolation(double x)
{
double y = 0;
for (int i = 0; i <= (int)points.size()-1; i++)
{
double numerator = 1;
double denominator = 1;
for (int c = 0; c <= (int)points.size()-1; c++)
{
if (c != i)
{
numerator *= (x - points[c].x);
denominator *= (points[i].x - points[c].x);
}
}
y += (points[i].y * (numerator / denominator));
}
return y;
}
curve::~curve(void)
{
}
double GetLogicalYAtX(double x)
{
curve cv;
Point2D p;
p.x=0; //always left edge
p.y=y1; //now by var
cv.PushPoint2D(p);
p.x=x2; //now by var
p.y=y2; //now by var
cv.PushPoint2D(p);
p.x=1; //always right edge
p.y=y3; //now by var
cv.PushPoint2D(p);
//p=cv.GetPoint(x);
//return p.y;
return cv.LagrangeInterpolation(x);
}
Do you have any ideas how I could get the new solution a little bit more "soft"? So that I can move the 2. Point in larger areas without the curve going out of boundaries? Thank you
static bezier From3Points(const Point2D &a, const Point2D &b, const Point2D &c)
{
bezier result;
result.PushPoint2D(a);
Point2D middle;
middle.x = 2*b.x - a.x/2 - c.x/2;
middle.y = 2*b.y - a.y/2 - c.y/2;
result.PushPoint2D(middle);
result.PushPoint2D(c);
return result;
}
Untested, but should return a bezier curve where at t=0.5 the curve passes through point 'b'.
Additionally (more untested code ahead), you can calculate your points using bernstein basis polynomials like so.
static int binomialcoefficient (int n, int k)
{
if (k == 0)
return 1;
if (n == 0)
return 0;
int result = 0;
for (int i = 1; i <= k; ++i)
{
result += (n - (k - i))/i;
}
return result;
}
static double bernstein (int v, int n, double t)
{
return binomialcoefficient(v,n) * pow(t,v) * pow(1 - t,n - v);
}
Point2D GetPoint (double t)
{
Point2D result;
result.x = 0;
result.y = 0;
for (int i = 0; i < points.size(); ++i)
{
double coeff = bernstein (i,points.size(),t);
result.x += coeff * points[i].x;
result.y += coeff * points[i].y;
}
return result;
}
How would you solve the problem of finding the points of a (integer) grid within a circle centered on the origin of the axis, with the results ordered by norm, as in distance from the centre, in C++?
I wrote an implementation that works (yeah, I know, it is extremely inefficient, but for my problem anything more would be overkill). I'm extremely new to C++, so my biggest problem was finding a data structure capable of
being sort-able;
being able to save an array in one of its elements,
rather than the implementation of the algorithm. My code is as follows. Thanks in advance, everyone!
typedef std::pair<int, int[2]> norm_vec2d;
bool norm_vec2d_cmp (norm_vec2d a, norm_vec2d b)
{
bool bo;
bo = (a.first < b.first ? true: false);
return bo;
}
int energy_to_momenta_2D (int energy, std::list<norm_vec2d> *momenta)
{
int i, j, norm, n=0;
int energy_root = (int) std::sqrt(energy);
norm_vec2d temp;
for (i=-energy_root; i<=energy_root; i++)
{
for (j =-energy_root; j<=energy_root; j++)
{
norm = i*i + j*j;
if (norm <= energy)
{
temp.first = norm;
temp.second[0] = i;
temp.second[1] = j;
(*momenta).push_back (temp);
n++;
}
}
}
(*momenta).sort(norm_vec2d_cmp);
return n;
}
How would you solve the problem of finding the points of a (integer) grid within a circle centered on the origin of the axis, with the results ordered by norm, as in distance from the centre, in C++?
I wouldn't use a std::pair to hold the points. I'd create my own more descriptive type.
struct Point {
int x;
int y;
int square() const { return x*x + y*y; }
Point(int x = 0, int y = 0)
: x(x), y(y) {}
bool operator<(const Point& pt) const {
if( square() < pt.square() )
return true;
if( pt.square() < square() )
return false;
if( x < pt.x )
return true;
if( pt.x < x)
return false;
return y < pt.y;
}
friend std::ostream& operator<<(std::ostream& os, const Point& pt) {
return os << "(" << pt.x << "," << pt.y << ")";
}
};
This data structure is (probably) exactly the same size as two ints, it is less-than comparable, it is assignable, and it is easily printable.
The algorithm walks through all of the valid points that satisfy x=[0,radius] && y=[0,x] && (x,y) inside circle:
std::set<Point>
GetListOfPointsInsideCircle(double radius = 1) {
std::set<Point> result;
// Only examine bottom half of quadrant 1, then
// apply symmetry 8 ways
for(Point pt(0,0); pt.x <= radius; pt.x++, pt.y = 0) {
for(; pt.y <= pt.x && pt.square()<=radius*radius; pt.y++) {
result.insert(pt);
result.insert(Point(-pt.x, pt.y));
result.insert(Point(pt.x, -pt.y));
result.insert(Point(-pt.x, -pt.y));
result.insert(Point(pt.y, pt.x));
result.insert(Point(-pt.y, pt.x));
result.insert(Point(pt.y, -pt.x));
result.insert(Point(-pt.y, -pt.x));
}
}
return result;
}
I chose a std::set to hold the data for two reasons:
It is stored is sorted order, so I don't have to std::sort it, and
It rejects duplicates, so I don't have to worry about points whose reflection are identical
Finally, using this algorithm is dead simple:
int main () {
std::set<Point> vp = GetListOfPointsInsideCircle(2);
std::copy(vp.begin(), vp.end(),
std::ostream_iterator<Point>(std::cout, "\n"));
}
It's always worth it to add a point class for such geometric problem, since usually you have more than one to solve. But I don't think it's a good idea to overload the 'less' operator to satisfy the first need encountered. Because:
Specifying the comparator where you sort will make it clear what order you want there.
Specifying the comparator will allow to easily change it without affecting your generic point class.
Distance to origin is not a bad order, but for a grid but it's probably better to use row and columns (sort by x first then y).
Such comparator is slower and will thus slow any other set of points where you don't even care about norm.
Anyway, here is a simple solution using a specific comparator and trying to optimize a bit:
struct v2i{
int x,y;
v2i(int px, int py) : x(px), y(py) {}
int norm() const {return x*x+y*y;}
};
bool r_comp(const v2i& a, const v2i& b)
{ return a.norm() < b.norm(); }
std::vector<v2i> result;
for(int x = -r; x <= r; ++x) {
int my = r*r - x*x;
for(int y = 0; y*y <= my; ++y) {
result.push_back(v2i(x,y));
if(y > 0)
result.push_back(v2i(x,-y));
}
}
std::sort(result.begin(), result.end(), r_comp);