Traversal a KDTree - c++

I have some problem with my render, when I try to render a scene.
This is my traversal algorithm:
bool KDTree::traverse(Ray &ray, Node &node, double &tMin, double &tMax, double &tNear, double &u, double &v, Triangle* &hitObject)
{
if(node.tris.size() == 0) return 0;
bool current = false;
//bool intersected = false;
if(!node.isLeaf)
{
int axis = node.split_axis;
double tSplit = (node.split_pos - ray.orig[axis]) / ray.dir[axis];
Node* nearNode = ray.orig[axis] < node.split_pos ? node.leftNode : node.rightNode;
Node* farNode = ray.orig[axis] < node.split_pos ? node.rightNode : node.leftNode;
if (tSplit > tMax)
return traverse(ray, *nearNode , tMin, tMax, tNear, u, v, hitObject);//case A
else if (tSplit < tMin)
{
if(tSplit>0)
return traverse(ray, *farNode, tMin, tMax, tNear, u, v, hitObject);//case B
else if(tSplit<0)
return traverse(ray, *nearNode, tMin, tMax, tNear, u, v, hitObject);//case C
else
{//tSplit==0
if(ray.dir[axis]<0)
return traverse(ray, *farNode, tMin, tMax, tNear, u, v, hitObject);//case D
else
return traverse(ray, *nearNode, tMin, tMax, tNear, u, v, hitObject);//case E
}
}
else
{
if(tSplit>0)
{//case F
current = traverse(ray, *nearNode, tMin, tSplit, tNear, u, v, hitObject);
if (current != false)
return current;
else
return traverse(ray, *farNode, tSplit, tMax, tNear, u, v, hitObject);
}
else
{
return traverse(ray, *nearNode,tSplit, tMax, tNear, u, v, hitObject);//case G
}
}
}
else
{
tNear = 9999999;
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
double t = 9999999;
if(node.tris[i]->intersect(ray, t, u, v) && t < tNear)
{
hitObject = node.tris[i];
tNear = t;
}
}
return (hitObject != nullptr);
}
}
And this is my build algorithm:
void KDTree::buildkdtree(Node &node)
{
std::cout << "stò inizializzando il nodo di profondità: " << node.depth << std::endl;
if(node.tris.size() <= 30 || node.depth >= 15)
{
std::cout << "ho creato una foglia di livello: " << node.depth << " , con " << node.tris.size() << " triangoli" << std::endl;
node.isLeaf = true;
return;
}
int axis = (node.depth % 3);
std::vector<Vec3d> midPoints;
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
midPoints.push_back(node.tris[i]->getMidPoint());
}
std::vector<double> mid;
node.split_axis = axis;
node.rightNode = new struct Node;
node.leftNode = new struct Node;
double max, min, med;
switch(node.split_axis)
{
case(0):
std::cout << "splitto su x" << std::endl;
for(unsigned int i = 0; i < midPoints.size(); ++i)
{
mid.push_back(midPoints[i].x);
}
std::sort(mid.begin(), mid.end());
if(mid.size() % 2 == 0)
med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
else
med = mid[mid.size()/2];
node.split_pos = med;
std::cout << "l'intervallo e': (" << node.bbox->xMin << " ," << node.bbox->xMax << ")\n";
std::cout << "split_pos = " << node.split_pos << std::endl;
node.rightNode->bbox = new Bbox(node.bbox->xMax, node.split_pos, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);
node.leftNode->bbox = new Bbox(node.split_pos, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
node.tris[i]->getExtreme(max, min, axis);
if(min <= node.split_pos)
node.leftNode->tris.push_back(node.tris[i]);
if(max >= node.split_pos)
node.rightNode->tris.push_back(node.tris[i]);
}
break;
case(1):
std::cout << "splitto su y" << std::endl;
for(unsigned int i = 0; i < midPoints.size(); ++i)
{
mid.push_back(midPoints[i].y);
}
std::sort(mid.begin(), mid.end());
if(mid.size() % 2 == 0)
med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
else
med = mid[mid.size()/2];
node.split_pos = med;
std::cout << "l'intervallo e': (" << node.bbox->yMin << " ," << node.bbox->yMax << ")\n";
std::cout << "split_pos = " << node.split_pos << std::endl;
node.rightNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.split_pos, node.bbox->yMin, node.bbox->zMax, node.bbox->zMin);
node.leftNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.split_pos, node.bbox->zMax, node.bbox->zMin);
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
node.tris[i]->getExtreme(max, min, axis);
if(min <= node.split_pos)
node.leftNode->tris.push_back(node.tris[i]);
if(max >= node.split_pos)
node.rightNode->tris.push_back(node.tris[i]);
}
break;
case(2):
std::cout << "splitto su z" << std::endl;
for(unsigned int i = 0; i < midPoints.size(); ++i)
{
mid.push_back(midPoints[i].z);
}
std::sort(mid.begin(), mid.end());
if(mid.size() % 2 == 0)
med = (mid[mid.size()/2 - 1] + mid[mid.size()/2]) / 2;
else
med = mid[mid.size()/2];
node.split_pos = med;
std::cout << "l'intervallo e': (" << node.bbox->zMin << " ," << node.bbox->zMax << ")\n";
std::cout << "split_pos = " << node.split_pos << std::endl;
node.rightNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.split_pos, node.bbox->zMin);
node.leftNode->bbox = new Bbox(node.bbox->xMax, node.bbox->xMin, node.bbox->yMax, node.bbox->yMin, node.bbox->zMax, node.split_pos);
for(unsigned int i = 0; i < node.tris.size(); ++i)
{
node.tris[i]->getExtreme(max, min, axis);
if(min <= node.split_pos)
node.leftNode->tris.push_back(node.tris[i]);
if(max >= node.split_pos)
node.rightNode->tris.push_back(node.tris[i]);
}
break;
default:
std::cout << "Errore, non ho uno dei tre assi" << std::endl;
break;
}
std::cout << "i " << node.tris.size() << " triangoli del padre sono stati divisi così\n";
std::cout << node.rightNode->tris.size() << " nel nodo di destra\n";
std::cout << node.leftNode->tris.size() << " nel nodo di sinistra\n" << std::endl;
node.rightNode->depth = node.depth + 1;
node.leftNode->depth = node.depth + 1;
std::cout << "sto processando figlio di destra del nodo di profondità: " << node.depth << std::endl;
buildkdtree(*(node.rightNode));
std::cout << "sto processando figlio di sinistra del nodo di profondità: " << node.depth << std::endl;
buildkdtree(*(node.leftNode));}
Someone can help me?
PS: this is the image I get:

I had this same issue when writing my ray tracer. The problem could actually be in your build code or in your traversal code. Consider that if you build a bad tree, a "correct" traversal will also result in artifacts.
I found the issue by building a simple OpenGL renderer on top of my ray tracer. This involved the following:
Create an OpenGL rendering instance and feed it your scene & camera info. It looks like all you have are triangles and a light or two, so this should be pretty easy. OpenGL renders a good-enough approximation for our purposes.
Create an output window using GLUT and display the OpenGL output in a continuous rendering loop. Modify the output window such that it accepts user input (keyboard, mouse, whatever) to move the camera's position and direction around.
Modify your OpenGL renderer to also draw all the KDNode bounding boxes. Make the bounding boxes semi-transparent.
Create a second window that contains a tree control. Bind your KDTree to the tree control such that every element in the KDTree corresponds to exactly one node in your tree control. You should be able to visually inspect your KDTree now.
Modify the tree window such it accepts user input to select, expand, and collapse nodes.
Modify your OpenGL renderer such that the currently selected treenode's (KDNode's) bounding box, and the triangles assigned to that KDNode, are drawn in a special color.
Now, by selecting a node in the tree window, you can see the associated KDNode's bounding boxes, what triangles are assigned to the KDNode, and you can move the camera around to verify that the triangles you think are assigned to the KDNode are actually assigned to the node.
When I first did this, I was taken aback by how different my mental model of the tree was from what my algorithm was actually creating. With this tool, you ought to be able to verify that your build code is doing what you think it's doing. You can also use it to fine-tune your build code's parameters to get a more efficient tree.
Your output window ought to look something like this (courtesy Michele Bosi):
EDIT: Another example courtesy of Yining Karl Li
EDIT: A third example courtesy of Apollo Ellis

Related

Molecular dynamic, velocity verlet: Kinetic energy divergence

I'm trying to write a simple MD program in C/C++ (I'm used to C but I'm trying to learning C++, so my code is a little "mix"... I know that this is suboptimal and I will move to full C++ as soon as I fully understand it).
Everything seems to run but I have divergences in Kinetic energy, the system does not thermalize and temperature (prop to K) goes from order(10°K) to order(10000°K) in a single step.
I'm working with a low time-step of 0.002 (total time of simulation: 30) so I should not have this enormous error...
This is my code, if something is not clear I can try to explain it better
int main(){
...
int n, t, m, i;
double r, K, U, E,P, totalE, temperature, d, x,y,z, temp;
...
double data[5][PARTICELLE], vel[3][PARTICELLE],dataNew[3][PARTICELLE]; //0,1,2 are x,y,z. 3, 4 for data are Energy and Pressure
double force[3][PARTICELLE], forceNew[3][PARTICELLE];
double velQ[PARTICELLE]; //square velocity
ofstream out(OUTDATA);
//inizio MD
for(t=0; t<PASSI; t++){
//inizialization
K=0;
U=0;
E=0;
P=0;
fill(data[3], data[3]+PARTICELLE, 0); //E=0 for each particle
fill(data[4], data[4]+PARTICELLE, 0);
fill(velQ, velQ+PARTICELLE, 0);
for(i=0; i<3; i++){
fill(force[i], force[i]+PARTICELLE, 0);
fill(forceNew[i], forceNew[i]+PARTICELLE, 0);
}
for(n=0; n<PARTICELLE; n++) { //for on the n_ particle. A step is a move of n=PARTICELLE particles
for (i = 0; i < 3; i++) { //compute vSquare
velQ[n] += vel[i][n] * vel[i][n];
}
K += 0.5 * MASSA * velQ[n]; //compute Kinetic Energy
for(m=0; m<PARTICELLE; m++){ //loop on m!=n to compute F, E, P
if(m!=n){
r=0;
for(i=0; i<3; i++){ //calculation of radius and x,y,z
d = data[i][m] - data[i][n];
d = d - (NINT(d / LATO) * LATO);
if(i==0)x=d;
if(i==1)y=d;
if(i==2)z=d;
r += d * d;
}
//if (t<2) cout << "x y z" << x << " " << y << " " << z << endl;
r=sqrt(r);
if (r < R) {
data[3][n] += energy(r); //update Energy of n
for(i=0; i<3; i++){
if(i==0)temp=x;
if(i==1)temp=y;
if(i==2)temp=z;
force[i][n]+=forza(r,temp); //compute force (cartesian components)
//if(t<2)cout << "force " <<n << " " << m << " "<< force[i][n] << endl;
}
if (m < n)data[4][n] += (-energy(r) * (1 + r)); //pressure
}
}
}
U+=data[3][n]; //total potential energy
P+=data[4][n]; //total pressure
for (i = 0; i < 3; i++) { //Verlet update, part 1
dataNew[i][n] = data[i][n] + vel[i][n] * DeltaT + 0.5 * force[i][n] * DeltaT * DeltaT / MASSA;
}
for(m=0; m<PARTICELLE; m++){ //update force
if(m!=n){
r=0;
for(i=0; i<3; i++){
d = data[i][m] - dataNew[i][n];
d = d - (NINT(d / LATO) * LATO);
if(i==0)x=d;
if(i==1)y=d;
if(i==2)z=d;
r += d * d;
}
r=sqrt(r);
if (r < R) {
for(i=0; i<3; i++) {
if (i == 0)temp = x;
if (i == 1)temp = y;
if (i == 2)temp = z;
forceNew[i][n] += forza(r, temp);
}
}
}
}
for(i=0; i<3; i++){ //new position and Verlet part 2
data[i][n]=dataNew[i][n];
vel[i][n]=vel[i][n] + DeltaT * 0.5*(forceNew[i][n] + force[i][n]) / MASSA;
}
}
totalE=U+K; //total energy
temperature = 2*K/(PARTICELLE*3);
out << t*DeltaT << " " << U << " " << P << " " << totalE << " " << temperature << endl;
}
out.close();
return 0;
}
where my system is under a potential e^-r/r, so I have:
double energy( double r){
return (A*SIGMA*exp(-r/SIGMA)/r);
}
double forza(double r, double h){ //h is for x,y,z
double bubba;
bubba= (A*SIGMA*(exp(-r)*h*(r+1)/(r*r*r)));
return bubba;
}
Thanks for any help. I'm working on this code since April and still I have no solution...
edit: to be clearer: CAPITAL terms and DeltaT are values defined in DEFINE

Program ignoring condition?

In my code, I'm trying to prevent circles from overlapping so I specified it as a condition on the distance between the centres of the circles but it seems to not work all the time
as you can see :
could it be some kind of numerical precision rounding problem ?
Here is the relevant code (I can post the whole code if needed):
const double win_size = 800;
const double L = 50e-9; //box size (m)
const double k = 1.38e-23; // Boltzmann constant = 1.38e-23 J/K
const double R = 1.6e-10*30; //N2 radius = 1.6e-10 m
const double m = 4.65e-26; //N2 mass = 4.65e-26 kg
struct parameters{
double x;
double y;
double v_x;
double v_y;
};
bool empty_space(double x, double y, struct parameters gas[], int N, int i){
if (i == 0) return true;
for (int i = 0; i<N; i++){
if (pow(x-gas[i].x,2) + pow(y-gas[i].y,2) <= 4*R*R){
cout << gas[i].x << " " << gas[i].y << endl;
return false;
}
}
return true;
}
void initialize(struct parameters gas[], int N, double T){ // Sets initial conditions (velocity depends on temperature)
int tries = 0;
double x, y;
for (int i=0; i<N; i++){
if (tries == 10000){
cout << "Couldn't fit " << N << " molecules in the box, aborting simulation... " << endl;
exit(1);
}
x = R + (L - 2*R)*rand()/RAND_MAX;
y = R + (L - 2*R)*rand()/RAND_MAX;
if (empty_space(x,y,gas,N,i)){
gas[i].x = x;
gas[i].y = y;
}
else {
i--;
tries++;
}
gas[i].v_x = sqrt(2*k*T/m)*(1-2.0*rand()/RAND_MAX);
gas[i].v_y = (2*(rand()%2) - 1)*sqrt(2*k*T/m - pow(gas[i].v_x, 2));
}
}
void draw(int window, struct parameters gas[], int N, int automatic){
g2_pen(window,g2_ink(window,0.8,0.3,0.4));
for (int i=0; i<N; i++){
g2_circle(window,gas[i].x*win_size/L,gas[i].y*win_size/L,R*win_size/L);
}
g2_flush(window);
usleep(10000);
g2_pen(window,0);
g2_filled_rectangle(window,0,0,win_size,win_size);
if (!automatic) getchar();
}
The first debugging step is to print the coordinates of the circles that have clashed somehow, then see what the "distance" function is returning for their centers. My guess it it's somehow a rounding problem but this seems to be what you need to do next.

Objects in instance-variable list not being retained? Pointer issues?

I have a global variable vector<BezierPatch*> listOfBezierPatches that I populate from a command line parsing function. I then have a series of methods that populates two instance variable lists of a BezierPatch:
// final list of subdivided triangles, ready to feed to OpenGL display system
std::vector<Triangle*> listOfTriangles;
// list of differential geometries (i.e. points) that we are evaluating the given patch at
std::vector<DifferentialGeometry*> listOfDifferentialGeometries;
main.cpp:
void parseBezierFile(string filename) {
...
BezierPatch* currentBezierPatch = new BezierPatch();
while (getline(file, str)) {
...
vector<Eigen::Vector3f> bezierCurve;
bezierCurve.push_back(vector_from_command_line);
...
currentBezierPatch->addCurve(bezierCurve);
...
listOfBezierPatches.push_back(currentBezierPatch);
}
perform_subdivision();
}
void perform_subdivision() {
// Iterate through each of the Bezier patches...
for (std::vector<BezierPatch*>::size_type i = 0; i < listOfBezierPatches.size(); i++) {
BezierPatch currentBezierPatch = *(listOfBezierPatches[i]);
currentBezierPatch.performUniformSubdivision(subdivisionParameter);
}
}
BezierPatch.h:
void performUniformSubdivision(float stepSize) {
int numberOfSteps = 1.0 / stepSize;
for (int u = 0; u < numberOfSteps; u++) {
for (int v = 0; v < numberOfSteps; v++) {
listOfDifferentialGeometries.push_back(evaluateDifferentialGeometry(u * stepSize, v * stepSize));
}
}
// Iterate through all of our differential geometries, but do NOT touch the right-most column and the bottom-most row
for (int u = 0; u < (numberOfSteps - 1); u++) {
for (int v = 0; v < (numberOfSteps - 1); v++) {
// (u, v) represents the index in the above grid that we're triangulating
// This index represents the TOP LEFT corner of the 4-point rectangle that is described above
// Index of listOfDifferentialGeometries that corresponds with position (u, v)
int differentialGeometrixIndex = (u * numberOfSteps) + v;
// Construct tri-1
listOfTriangles.push_back(new Triangle(
*listOfDifferentialGeometries[differentialGeometrixIndex], // top left
*listOfDifferentialGeometries[differentialGeometrixIndex + numberOfSteps], // move one unit right
*listOfDifferentialGeometries[differentialGeometrixIndex + 1])); // move one unit down from top left
// Construct tri-2
listOfTriangles.push_back(new Triangle(
*listOfDifferentialGeometries[differentialGeometrixIndex + numberOfSteps], // top right
*listOfDifferentialGeometries[differentialGeometrixIndex + 1], // bottom left
*listOfDifferentialGeometries[differentialGeometrixIndex + numberOfSteps + 1])); // bottom right
}
}
// We should have (numberOfSteps - 1) * (numberOfSteps - 1) * 2 triangles
}
DifferentialGeometry* evaluateDifferentialGeometry(float u, float v) {
...
return new DifferentialGeometry(finalVCurve.point, normal, Eigen::Vector2f(u, v));
}
The problem:
After all of the above code has been run, if I iterate through the BezierPatches in listOfBezierPatches, the listOfTriangles and listOfDifferentialGeometries are both empty. I know this is obviously something to do with local pointers/variables, but I can't seem to figure it out. Here's a detailed look at the perform_subdivision method, where the problem occurs:
void perform_subdivision(bool adaptive_subdivision) {
// Iterate through each of the Bezier patches...
for (std::vector<BezierPatch*>::size_type i = 0; i < listOfBezierPatches.size(); i++) {
BezierPatch currentBezierPatch = *(listOfBezierPatches[i]);
currentBezierPatch.performUniformSubdivision(subdivisionParameter);
// ***** TESTING: This successfully prints out our differential geometries ***** //
// Iterate through Triangles in the current Bezier patch
for (std::vector<DifferentialGeometry>::size_type j = 0; j < currentBezierPatch.listOfDifferentialGeometries.size(); j++) {
DifferentialGeometry* currentDifferentialGeometry = currentBezierPatch.listOfDifferentialGeometries[j];
cout << " DifferentialGeometry " << (j + 1) << ":\n";
Eigen::Vector3f currentPosition = currentDifferentialGeometry->position;
cout << " (" << currentPosition.x() << " , " << currentPosition.y() << " , " << currentPosition.z() << ")\n";
}
// This does NOT successfully print out our differential geometries...
printDifferentialGeometriesInBezierPatches();
}
}
}
where printDifferentialGeometriesInBezierPatches() is defined as:
//****************************************************
// function that prints all differential geometries in every Bezier Patch
//***************************************************
void printDifferentialGeometriesInBezierPatches() {
if (debug) {
// Iterate through Bezier Patches
for (std::vector<BezierPatch*>::size_type i = 0; i < listOfBezierPatches.size(); i++) {
cout << " Bezier patch " << (i + 1) << ":\n\n";
// Iterate through Triangles in the current Bezier patch
for (std::vector<DifferentialGeometry>::size_type j = 0; i < listOfBezierPatches[i]->listOfDifferentialGeometries.size(); j++) {
DifferentialGeometry* currentDifferentialGeometry = listOfBezierPatches[i]->listOfDifferentialGeometries[j];
cout << " DifferentialGeometry " << (j + 1) << ":\n";
Eigen::Vector3f currentPosition = currentDifferentialGeometry->position;
cout << " (" << currentPosition.x() << " , " << currentPosition.y() << " , " << currentPosition.z() << ")\n";
}
}
}
}
Any suggestions would be greatly appreciated. Thanks!
Maybe your problem in the next line in perform_subdivision
BezierPatch currentBezierPatch = *(listOfBezierPatches[i]);
For each element you create a copy which removed in the end of the loop
void perform_subdivision() {
// Iterate through each of the Bezier patches...
for (std::vector<BezierPatch*>::size_type i = 0; i < listOfBezierPatches.size(); i++) {
// ! Here you create a copy of i-th element
BezierPatch currentBezierPatch = *(listOfBezierPatches[i]);
// populate its memebers
currentBezierPatch.performUniformSubdivision(subdivisionParameter);
}
}
I guess this would be correct
void perform_subdivision() {
// Iterate through each of the Bezier patches...
for (std::vector<BezierPatch*>::size_type i = 0; i < listOfBezierPatches.size(); i++) {
BezierPatch* currentBezierPatch = listOfBezierPatches[i];
currentBezierPatch->performUniformSubdivision(subdivisionParameter);
}
}

C++ Spline interpolation from an array of points

I am writing a bit of code to animate a point using a sequence of positions. In order to have a decent result, I'd like to add some spline interpolation
to smoothen the transitions between positions. All the positions are separated by the same amount of time (let's say 500ms).
int delay = 500;
vector<Point> positions={ (0, 0) , (50, 20), (150, 100), (30, 120) };
Here is what i have done to make a linear interpolation (which seems to work properly), juste to give you an idea of what I'm looking for later on :
Point getPositionAt(int currentTime){
Point before, after, result;
int currentIndex = (currentTime / delay) % positions.size();
before = positions[currentIndex];
after = positions[(currentIndex + 1) % positions.size()];
// progress between [before] and [after]
double progress = fmod((((double)currentTime) / (double)delay), (double)positions.size()) - currentIndex;
result.x = before.x + (int)progress*(after.x - before.x);
result.y = before.y + (int)progress*(after.y - before.y);
return result;
}
So that was simple, but now what I would like to do is spline interpolation. Thanks !
I had to write a Bezier spline creation routine for an "entity" that was following a path in a game I am working on. I created a base class to handle a "SplineInterface" and the created two derived classes, one based on the classic spline technique (e.g. Sedgewick/Algorithms) an a second one based on Bezier Splines.
Here is the code. It is a single header file, with a few includes (most should be obvious):
#ifndef __SplineCommon__
#define __SplineCommon__
#include "CommonSTL.h"
#include "CommonProject.h"
#include "MathUtilities.h"
/* A Spline base class. */
class SplineBase
{
private:
vector<Vec2> _points;
bool _elimColinearPoints;
protected:
protected:
/* OVERRIDE THESE FUNCTIONS */
virtual void ResetDerived() = 0;
enum
{
NOM_SIZE = 32,
};
public:
SplineBase()
{
_points.reserve(NOM_SIZE);
_elimColinearPoints = true;
}
const vector<Vec2>& GetPoints() { return _points; }
bool GetElimColinearPoints() { return _elimColinearPoints; }
void SetElimColinearPoints(bool elim) { _elimColinearPoints = elim; }
/* OVERRIDE THESE FUNCTIONS */
virtual Vec2 Eval(int seg, double t) = 0;
virtual bool ComputeSpline() = 0;
virtual void DumpDerived() {}
/* Clear out all the data.
*/
void Reset()
{
_points.clear();
ResetDerived();
}
void AddPoint(const Vec2& pt)
{
// If this new point is colinear with the two previous points,
// pop off the last point and add this one instead.
if(_elimColinearPoints && _points.size() > 2)
{
int N = _points.size()-1;
Vec2 p0 = _points[N-1] - _points[N-2];
Vec2 p1 = _points[N] - _points[N-1];
Vec2 p2 = pt - _points[N];
// We test for colinearity by comparing the slopes
// of the two lines. If the slopes are the same,
// we assume colinearity.
float32 delta = (p2.y-p1.y)*(p1.x-p0.x)-(p1.y-p0.y)*(p2.x-p1.x);
if(MathUtilities::IsNearZero(delta))
{
_points.pop_back();
}
}
_points.push_back(pt);
}
void Dump(int segments = 5)
{
assert(segments > 1);
cout << "Original Points (" << _points.size() << ")" << endl;
cout << "-----------------------------" << endl;
for(int idx = 0; idx < _points.size(); ++idx)
{
cout << "[" << idx << "]" << " " << _points[idx] << endl;
}
cout << "-----------------------------" << endl;
DumpDerived();
cout << "-----------------------------" << endl;
cout << "Evaluating Spline at " << segments << " points." << endl;
for(int idx = 0; idx < _points.size()-1; idx++)
{
cout << "---------- " << "From " << _points[idx] << " to " << _points[idx+1] << "." << endl;
for(int tIdx = 0; tIdx < segments+1; ++tIdx)
{
double t = tIdx*1.0/segments;
cout << "[" << tIdx << "]" << " ";
cout << "[" << t*100 << "%]" << " ";
cout << " --> " << Eval(idx,t);
cout << endl;
}
}
}
};
class ClassicSpline : public SplineBase
{
private:
/* The system of linear equations found by solving
* for the 3 order spline polynomial is given by:
* A*x = b. The "x" is represented by _xCol and the
* "b" is represented by _bCol in the code.
*
* The "A" is formulated with diagonal elements (_diagElems) and
* symmetric off-diagonal elements (_offDiagElemns). The
* general structure (for six points) looks like:
*
*
* | d1 u1 0 0 0 | | p1 | | w1 |
* | u1 d2 u2 0 0 | | p2 | | w2 |
* | 0 u2 d3 u3 0 | * | p3 | = | w3 |
* | 0 0 u3 d4 u4 | | p4 | | w4 |
* | 0 0 0 u4 d5 | | p5 | | w5 |
*
*
* The general derivation for this can be found
* in Robert Sedgewick's "Algorithms in C++".
*
*/
vector<double> _xCol;
vector<double> _bCol;
vector<double> _diagElems;
vector<double> _offDiagElems;
public:
ClassicSpline()
{
_xCol.reserve(NOM_SIZE);
_bCol.reserve(NOM_SIZE);
_diagElems.reserve(NOM_SIZE);
_offDiagElems.reserve(NOM_SIZE);
}
/* Evaluate the spline for the ith segment
* for parameter. The value of parameter t must
* be between 0 and 1.
*/
inline virtual Vec2 Eval(int seg, double t)
{
const vector<Vec2>& points = GetPoints();
assert(t >= 0);
assert(t <= 1.0);
assert(seg >= 0);
assert(seg < (points.size()-1));
const double ONE_OVER_SIX = 1.0/6.0;
double oneMinust = 1.0 - t;
double t3Minust = t*t*t-t;
double oneMinust3minust = oneMinust*oneMinust*oneMinust-oneMinust;
double deltaX = points[seg+1].x - points[seg].x;
double yValue = t * points[seg + 1].y +
oneMinust*points[seg].y +
ONE_OVER_SIX*deltaX*deltaX*(t3Minust*_xCol[seg+1] - oneMinust3minust*_xCol[seg]);
double xValue = t*(points[seg+1].x-points[seg].x) + points[seg].x;
return Vec2(xValue,yValue);
}
/* Clear out all the data.
*/
virtual void ResetDerived()
{
_diagElems.clear();
_bCol.clear();
_xCol.clear();
_offDiagElems.clear();
}
virtual bool ComputeSpline()
{
const vector<Vec2>& p = GetPoints();
_bCol.resize(p.size());
_xCol.resize(p.size());
_diagElems.resize(p.size());
for(int idx = 1; idx < p.size(); ++idx)
{
_diagElems[idx] = 2*(p[idx+1].x-p[idx-1].x);
}
for(int idx = 0; idx < p.size(); ++idx)
{
_offDiagElems[idx] = p[idx+1].x - p[idx].x;
}
for(int idx = 1; idx < p.size(); ++idx)
{
_bCol[idx] = 6.0*((p[idx+1].y-p[idx].y)/_offDiagElems[idx] -
(p[idx].y-p[idx-1].y)/_offDiagElems[idx-1]);
}
_xCol[0] = 0.0;
_xCol[p.size()-1] = 0.0;
for(int idx = 1; idx < p.size()-1; ++idx)
{
_bCol[idx+1] = _bCol[idx+1] - _bCol[idx]*_offDiagElems[idx]/_diagElems[idx];
_diagElems[idx+1] = _diagElems[idx+1] - _offDiagElems[idx]*_offDiagElems[idx]/_diagElems[idx];
}
for(int idx = (int)p.size()-2; idx > 0; --idx)
{
_xCol[idx] = (_bCol[idx] - _offDiagElems[idx]*_xCol[idx+1])/_diagElems[idx];
}
return true;
}
};
/* Bezier Spline Implementation
* Based on this article:
* http://www.particleincell.com/blog/2012/bezier-splines/
*/
class BezierSpine : public SplineBase
{
private:
vector<Vec2> _p1Points;
vector<Vec2> _p2Points;
public:
BezierSpine()
{
_p1Points.reserve(NOM_SIZE);
_p2Points.reserve(NOM_SIZE);
}
/* Evaluate the spline for the ith segment
* for parameter. The value of parameter t must
* be between 0 and 1.
*/
inline virtual Vec2 Eval(int seg, double t)
{
assert(seg < _p1Points.size());
assert(seg < _p2Points.size());
double omt = 1.0 - t;
Vec2 p0 = GetPoints()[seg];
Vec2 p1 = _p1Points[seg];
Vec2 p2 = _p2Points[seg];
Vec2 p3 = GetPoints()[seg+1];
double xVal = omt*omt*omt*p0.x + 3*omt*omt*t*p1.x +3*omt*t*t*p2.x+t*t*t*p3.x;
double yVal = omt*omt*omt*p0.y + 3*omt*omt*t*p1.y +3*omt*t*t*p2.y+t*t*t*p3.y;
return Vec2(xVal,yVal);
}
/* Clear out all the data.
*/
virtual void ResetDerived()
{
_p1Points.clear();
_p2Points.clear();
}
virtual bool ComputeSpline()
{
const vector<Vec2>& p = GetPoints();
int N = (int)p.size()-1;
_p1Points.resize(N);
_p2Points.resize(N);
if(N == 0)
return false;
if(N == 1)
{ // Only 2 points...just create a straight line.
// Constraint: 3*P1 = 2*P0 + P3
_p1Points[0] = (2.0/3.0*p[0] + 1.0/3.0*p[1]);
// Constraint: P2 = 2*P1 - P0
_p2Points[0] = 2.0*_p1Points[0] - p[0];
return true;
}
/*rhs vector*/
vector<Vec2> a(N);
vector<Vec2> b(N);
vector<Vec2> c(N);
vector<Vec2> r(N);
/*left most segment*/
a[0].x = 0;
b[0].x = 2;
c[0].x = 1;
r[0].x = p[0].x+2*p[1].x;
a[0].y = 0;
b[0].y = 2;
c[0].y = 1;
r[0].y = p[0].y+2*p[1].y;
/*internal segments*/
for (int i = 1; i < N - 1; i++)
{
a[i].x=1;
b[i].x=4;
c[i].x=1;
r[i].x = 4 * p[i].x + 2 * p[i+1].x;
a[i].y=1;
b[i].y=4;
c[i].y=1;
r[i].y = 4 * p[i].y + 2 * p[i+1].y;
}
/*right segment*/
a[N-1].x = 2;
b[N-1].x = 7;
c[N-1].x = 0;
r[N-1].x = 8*p[N-1].x+p[N].x;
a[N-1].y = 2;
b[N-1].y = 7;
c[N-1].y = 0;
r[N-1].y = 8*p[N-1].y+p[N].y;
/*solves Ax=b with the Thomas algorithm (from Wikipedia)*/
for (int i = 1; i < N; i++)
{
double m;
m = a[i].x/b[i-1].x;
b[i].x = b[i].x - m * c[i - 1].x;
r[i].x = r[i].x - m * r[i-1].x;
m = a[i].y/b[i-1].y;
b[i].y = b[i].y - m * c[i - 1].y;
r[i].y = r[i].y - m * r[i-1].y;
}
_p1Points[N-1].x = r[N-1].x/b[N-1].x;
_p1Points[N-1].y = r[N-1].y/b[N-1].y;
for (int i = N - 2; i >= 0; --i)
{
_p1Points[i].x = (r[i].x - c[i].x * _p1Points[i+1].x) / b[i].x;
_p1Points[i].y = (r[i].y - c[i].y * _p1Points[i+1].y) / b[i].y;
}
/*we have p1, now compute p2*/
for (int i=0;i<N-1;i++)
{
_p2Points[i].x=2*p[i+1].x-_p1Points[i+1].x;
_p2Points[i].y=2*p[i+1].y-_p1Points[i+1].y;
}
_p2Points[N-1].x = 0.5 * (p[N].x+_p1Points[N-1].x);
_p2Points[N-1].y = 0.5 * (p[N].y+_p1Points[N-1].y);
return true;
}
virtual void DumpDerived()
{
cout << " Control Points " << endl;
for(int idx = 0; idx < _p1Points.size(); idx++)
{
cout << "[" << idx << "] ";
cout << "P1: " << _p1Points[idx];
cout << " ";
cout << "P2: " << _p2Points[idx];
cout << endl;
}
}
};
#endif /* defined(__SplineCommon__) */
Some Notes
The classic spline will crash if you give it a vertical set of
points. That is why I created the Bezier...I have lots of vertical
lines/paths to follow.
The base class has an option to remove colinear points as you add
them. This uses a simple slope comparison of two lines to figure out
if they are on the same line. You don't have to do this, but for
long paths that are straight lines, it cuts down on cycles. When you
do a lot of pathfinding on a regular-spaced graph, you tend to get a
lot of continuous segments.
Here is an example of using the Bezier Spline:
/* Smooth the points on the path so that turns look
* more natural. We'll only smooth the first few
* points. Most of the time, the full path will not
* be executed anyway...why waste cycles.
*/
void SmoothPath(vector<Vec2>& path, int32 divisions)
{
const int SMOOTH_POINTS = 6;
BezierSpine spline;
if(path.size() < 2)
return;
// Cache off the first point. If the first point is removed,
// the we occasionally run into problems if the collision detection
// says the first node is occupied but the splined point is too
// close, so the FSM "spins" trying to find a sensor cell that is
// not occupied.
// Vec2 firstPoint = path.back();
// path.pop_back();
// Grab the points.
for(int idx = 0; idx < SMOOTH_POINTS && path.size() > 0; idx++)
{
spline.AddPoint(path.back());
path.pop_back();
}
// Smooth them.
spline.ComputeSpline();
// Push them back in.
for(int idx = spline.GetPoints().size()-2; idx >= 0; --idx)
{
for(int division = divisions-1; division >= 0; --division)
{
double t = division*1.0/divisions;
path.push_back(spline.Eval(idx, t));
}
}
// Push back in the original first point.
// path.push_back(firstPoint);
}
Notes
While the whole path could be smoothed, in this application, since
the path was changing every so often, it was better to just smooth
the first points and then connect it up.
The points are loaded in "reverse" order into the path vector. This
may or may not save cycles (I've slept since then).
This code is part of a much larger code base, but you can download it all on github and see a blog entry about it here.
You can look at this in action in this video.
Was this helpful?

how can i find the coordinates of intersection between 2 line segments C++

I am very new to c++ programming language i just need to know how can i declare a set of line segments given their start and end points? is there anything like that in C++?
I have this code which reads the starting and ending points of the line segments from a text file and divides the input into 4 vectors : X_start, Y_start, X_end, Y_end.
I need to know how to use these vectors to define line segments? any help would be appreciated. Thanks in advance
#include <iostream>
#include <algorithm> // for std::copy#include <iostream>
#include <iterator>
#include <fstream>
#include <math.h>
#include <vector>
#include <algorithm> // for std::copy
using namespace std;
int main()
{
std::ifstream is("D:\\Task1.txt");
std::istream_iterator<double> start(is), end;
std::vector<double> numbers(start, end);
std::vector<double> X_start(start, end);
std::vector<double> Y_start(start, end);
std::vector<double> X_end(start, end);
std::vector<double> Y_end(start, end);
std::vector<double>::iterator i;
std::vector<double>::iterator j;
float left, top, right, bottom; // Bounding Box For Line Segments
left = 12;
top = 12;
right = 0;
bottom = 0;
std::cout << "Read " << numbers.size() << " numbers" << std::endl;
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<double>(std::cout, " "));
std::cout << std::endl;
for (vector<double>::iterator i = numbers.begin();
i != numbers.end();
++i)
{
for(int j = 0; j < numbers.size(); j = j+4)
{
std::cout << "elemnts of X_start " << numbers[j] << " " <<std::endl;
X_start.push_back(numbers[j]);
}
for(int k = 1; k < numbers.size(); k = k+4)
{
std::cout << "elemnts of Y_start " << numbers[k] << " " <<std::endl;
Y_start.push_back(numbers[k]);
}
for(int l = 2; l < numbers.size(); l = l+4)
{
std::cout << "elemnts of X_end " << numbers[l] << " " <<std::endl;
X_end.push_back(numbers[l]);
}
for(int m = 3; m < numbers.size(); m = m+4)
{
std::cout << "elemnts of Y_end " << numbers[m] << " " <<std::endl;
Y_end.push_back(numbers[m]);
}
getchar();
}
}
"I am very new to c++ programming language"
How new to C++? Do you understand the maths involved in what you're trying to do first?
I use the following function. Just modify it to meet your requirements.
class Point
{
public:
float x,y;
};
class LineSegment
{
public:
Point top;
Point bottom;
};
Point* getIntersectionPoint(LineSegment line1,LineSegment line2)
{
float s1_x, s1_y, s2_x, s2_y;
float p1_x = line1.bottom.x,p1_y = line1.bottom.y;
float p0_x = line1.top.x,p0_y = line1.top.y;
float p3_x = line2.bottom.x,p3_y = line2.bottom.y;
float p2_x = line2.top.x,p2_y = line2.top.y;
s1_x = p1_x - p0_x; s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x; s2_y = p3_y - p2_y;
float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
Point *intsPoint = (Point *)malloc(sizeof(Point));
intsPoint->x = p0_x + (t * s1_x);
intsPoint->y = p0_y + (t * s1_y);
return intsPoint;
}
return NULL;
}