I am new to c++ and I get this error “Invalid operands to binary expression (‘const Vector’ and ‘const Vector’)” and I have no idea where to look at in my own code.
The error appears at the line “{return __x < __y;}” in _functional_base:
#if _LIBCPP_STD_VER > 11
template <class _Tp = void>
#else
template <class _Tp>
#endif
struct _LIBCPP_TYPE_VIS_ONLY less : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x < __y;}
};
But my real code looks like this:
//
// MCP.cpp
// Speciale
//
// Created by Zaki G on 21/11/15.
// Copyright © 2015 Zaki G. All rights reserved.
//
#include "mcp.h"
#include <cmath>
#include <string>
#include <iomanip>
#include "Vector.h"
#include "Particle.h"
#include "Detector.h"
#include "Cave.h"
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <map>
MCP::MCP(char* name,Vector& dimension,Vector& QuartzDimension, int NumberSubQuartz, double ElectronicThickness, double Reflective_index, double z_axis_sign): Detector(name, dimension, 0)
{
MCP_Dimension = dimension;
MCP_QuartDimension = QuartzDimension;
MCP_NumberSubQuartz = NumberSubQuartz;
MCP_ElectronicThickness = ElectronicThickness;
MCP_Quartz_Reflective_index = Reflective_index;
MCP_z_axis_sign = z_axis_sign;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
Vector MCP::Quartz_wall_Intersection(Detector& name, Vector &inter_front_quartz, Vector &path_photon, Vector &direction_vector, int reflection_on_off, Vector &Cherenkov_photon) //The direction vector is the vector against the normal vectors of the walls, and the Cherenkov_photon is only called to
//calculate the refelcted photon.
{ // Function for finding the intersection with the quartz walls and it can also calculated the reflected photon vector//
Vector detector_posi = name.fPosition; // The position of the detector
double Quartz_L_corner_x = detector_posi.GetX()-(0.053/2);
double Quartz_L_corner_y = detector_posi.GetY()-(0.053/2);
double Quartz_L_corner_z = detector_posi.GetZ();
Vector loop_Quartz_Lcorner = (Quartz_L_corner_x, Quartz_L_corner_y, Quartz_L_corner_z); //The position of the Quartz down left corner.
//Generating walls and roofs position for every sub MCP quartz.
int number_of_walls =int(sqrt(MCP_NumberSubQuartz)); //4+1 walls in total remember "+1"
int walls_position[number_of_walls+1];
for (int i = 0; i<=number_of_walls; i++)
{
walls_position[i] = loop_Quartz_Lcorner.GetX()+i*(0.053/sqrt(MCP_NumberSubQuartz)); // 0.053 is the length and width of the MCP Quartz
}
int number_of_roof =int(sqrt(MCP_NumberSubQuartz));
int roofs_position[number_of_roof+1];
for (int i = 0; i<=number_of_roof; i++)
{
roofs_position[i] = loop_Quartz_Lcorner.GetY()+i*(0.053/sqrt(MCP_NumberSubQuartz));
}
//loop for which section (Divided quartz) is the generated particle close to.
int en = 0;
int to = 0;
double x_array[2];
double y_array[2];
for (int i = 0; i<=number_of_walls; i++)
{
if ( abs(inter_front_quartz.GetX()) - abs(walls_position[i])<= (0.053/sqrt(MCP_NumberSubQuartz))){
x_array[en] = walls_position[i];
en =+1;
if ( abs(inter_front_quartz.GetY()) - abs(roofs_position[i]) <= (0.053/sqrt(MCP_NumberSubQuartz))){
y_array[to] = roofs_position[i];
to =+1;
}
}
}
// Defining the four point in which the particle is incapsuled within the divided quartz:
Vector position_array_one_zero = Vector(x_array[0], y_array[0], 0);
Vector position_array_one_one = Vector(x_array[0], y_array[1], 0);
Vector position_array_two_zero = Vector(x_array[1], y_array[0], 0);
Vector position_array_two_one = Vector(x_array[1], y_array[1], 0);
//Defining the four normal vectors for the incapsuled walls and roofs:
//Walls normal vector:
//Left:
Vector normal_left = (position_array_one_one-position_array_one_zero).Cross(Vector(position_array_one_zero.GetX(),position_array_one_zero.GetY(),position_array_one_zero.GetZ()-0.020)-position_array_one_zero);
//Right:
Vector normal_right = (position_array_two_one-position_array_two_zero).Cross(Vector(position_array_two_zero.GetX(),position_array_two_zero.GetY(),position_array_two_zero.GetZ()-0.020)-position_array_two_one);
//Roof normal vectors:
//Top:
Vector normal_top = (position_array_two_one-position_array_one_one).Cross(Vector(position_array_one_one.GetX(),position_array_one_one.GetY(),position_array_one_one.GetZ()-0.020)-position_array_one_one);
//Bottom:
Vector normal_bottom = (position_array_one_zero-position_array_two_zero).Cross(Vector(position_array_two_zero.GetX(),position_array_two_zero.GetY(),position_array_two_zero.GetZ()-0.020)-position_array_two_zero);
// Putting the normal vectors in a array
Vector normal_walls_roof[4]={normal_left,normal_right,normal_top,normal_bottom};
//point on the surface for every normal vector which coresponds to the each surface
map<Vector, Vector> quartz_surface_position;
quartz_surface_position[normal_walls_roof[1]] =Vector(position_array_one_zero) + Vector(0, (0.053/8), (0.020/2)*MCP_z_axis_sign ) ; //Left
quartz_surface_position[normal_walls_roof[2]] =Vector(position_array_two_zero) + Vector(0, (0.053/8), (0.020/2)*MCP_z_axis_sign ); //Right
quartz_surface_position[normal_walls_roof[3]] =Vector(position_array_one_one) + Vector((0.053/8), 0, (0.020/2)*MCP_z_axis_sign ); //Top
quartz_surface_position[normal_walls_roof[4]] =Vector(position_array_two_one) + Vector(-(0.053/8), 0, (0.020/2)*MCP_z_axis_sign );//Bottom
Vector Quartz_wall_Intersection; //The intersection point on one of the walls
Vector return_intersection_vector;
//Looping over which wall it hits
for (int i=0; i<=3; i++){
double dot_normal = direction_vector.Dot(normal_walls_roof[i]);
if (dot_normal < 10e-18)
{ //the dot product should be less than zero so the angle is stump (over 90 degree)
//The intersection point on one of the walls
Vector Quartz_wall_Intersection = path_photon-(((path_photon-quartz_surface_position[i]).Dot(normal_walls_roof[i])/dot_normal)*direction_vector);
Vector w_quartz = Quartz_wall_Intersection - quartz_surface_position[i];
// If the intersection of the plane falls outside window, return a
// NAN vector.
if (w_quartz.GetY() > name.GetHeight() || w_quartz.GetZ() > name.GetWidth())
{
return_intersection_vector = Vector(NAN,NAN,NAN);
}
else
{
if (reflection_on_off==1) //If the reflected momentum is needed:
{
// Refelction vector with in the quartz walls for the Cherenkov photons
Vector Reflection_vector_quartz = Cherenkov_photon -2.0*(Cherenkov_photon.Dot(normal_walls_roof[i]))*normal_walls_roof[i];
return_intersection_vector = Reflection_vector_quartz;
}
else
{
return_intersection_vector = Quartz_wall_Intersection;
}
}
}
}
return return_intersection_vector;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
void MCP::Cherenkov_Photon_Generation(const Particle& pname, Vector &first_intersection, Vector &second_intersection, Vector pathPhoton_array[], Vector CherenkovPhoton_array[])
{
// Now we generates cherenkov photons along the particle path.//
Vector particle_momentum = pname.GetMomentum();
// The end_value is a constant, which describes the position where the particle is at the end of the quart plan.
double end_value =(second_intersection.GetX()-first_intersection.GetX())/particle_momentum.GetX();
// Generating the path for the particles where the photon should emits as Cherenkov light.
for (int n=0; n<=1000; n++) //1000 Cherenkov photons per particle
{
srand( (unsigned int) time(0) );
double random_number_d = ( double(rand()) / double(RAND_MAX))*end_value; // generate numbers between 0 and end_value.
double path_photon_x =first_intersection.GetX() + random_number_d*particle_momentum.GetX();
double path_photon_y =first_intersection.GetY() + random_number_d*particle_momentum.GetY();;
double path_photon_z =first_intersection.GetZ() + random_number_d*particle_momentum.GetZ();
Vector path_photon(path_photon_x,path_photon_y,path_photon_z);
double random_angle = (rand()/RAND_MAX)* (2*M_PI); //Generate number between 0 and 2*Pi
Vector velocity_vector = pname.GetVelocity();
double v = velocity_vector.Length();
double Cherenkov_Angle = acos((1.0)/(MCP_Quartz_Reflective_index*v));
double x = (pname.GetMomentum()).Length()*sin(Cherenkov_Angle)*cos(random_angle); //random angle is from 0-2pi
double y = (pname.GetMomentum()).Length()*sin(Cherenkov_Angle)*sin(random_angle);
double z = (pname.GetMomentum()).Length()*cos(Cherenkov_Angle);
Vector Cherenkov_photon(x,y,z);
//pathPhoton_Cherenkov_array[path_photon] = Cherenkov_photon;
pathPhoton_array[n] = path_photon;
CherenkovPhoton_array[n] = Cherenkov_photon;
}
return;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
Vector MCP::MCP_end_Intersection_for_particle(const Particle& pname, Vector &particle_pos, Detector& name)
{
// Intersection with the end surface of the quartz//
// end_position is the position of the end plan of the quartz.
Vector front_quartz_position = name.fPosition;
Vector end_position(front_quartz_position.GetX(),front_quartz_position.GetY(),front_quartz_position.GetZ()+(0.020*MCP_z_axis_sign));
Vector particle_momentum = pname.GetMomentum();
Vector normal_end_quartz(0, 0, MCP_QuartDimension.GetX()*MCP_QuartDimension.GetY()*MCP_z_axis_sign);
double dot_end_quartz = particle_momentum.Dot(normal_end_quartz);
if (dot_end_quartz > 10e-18)
{
return Vector(NAN,NAN,NAN);
}
// inter_end_quartz is the intersection point on the end surface of the quartz
Vector inter_end_quartz = particle_pos-(((particle_pos-end_position).Dot(normal_end_quartz)/dot_end_quartz)*particle_momentum);
Vector w_end_quartz = inter_end_quartz - end_position;
// If the intersection of the plane falls outside window, return a
// Zero vector.
if (w_end_quartz.GetX() > MCP_QuartDimension.GetX() || w_end_quartz.GetY() > MCP_QuartDimension.GetY())
{
return Vector(NAN,NAN,NAN);
}
return inter_end_quartz;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
Vector MCP::MCP_end_Intersection_for_Photon(Vector &Photon_momentum, Vector &particle_pos, Detector& name)
{
// Intersection with the end surface of the quartz//
// end_position is the position of the end plan of the quartz.
Vector front_quartz_position = name.fPosition;
Vector end_position(front_quartz_position.GetX(),front_quartz_position.GetY(),front_quartz_position.GetZ()+(0.020*MCP_z_axis_sign));
Vector normal_end_quartz(0, 0, MCP_QuartDimension.GetX()*MCP_QuartDimension.GetY()*MCP_z_axis_sign);
double dot_end_quartz = Photon_momentum.Dot(normal_end_quartz);
if (dot_end_quartz > 10e-18)
{
return Vector(NAN,NAN,NAN);
}
// inter_end_quartz is the intersection point on the end surface of the quartz
Vector inter_end_quartz = particle_pos-(((particle_pos-end_position).Dot(normal_end_quartz)/dot_end_quartz)*Photon_momentum);
Vector w_end_quartz = inter_end_quartz - end_position;
// If the intersection of the plane falls outside window, return a
// Zero vector.
if (w_end_quartz.GetX() > MCP_QuartDimension.GetX() || w_end_quartz.GetY() > MCP_QuartDimension.GetY())
{
return Vector(NAN,NAN,NAN);
}
return inter_end_quartz;
}
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
void MCP::MCP_Intersection(const Particle& pname, Vector &particle_pos, Detector& name, Vector intersection_array[], int array_size)
{
//Intersection with the front surface of the MCP which is the quartz.//
Vector particle_momentum = pname.GetMomentum(); //Momentum of the particle
Vector front_quartz_position = name.fPosition; // position of the MCP on the FIT (Husk nedeunder MCP flad position)
Vector normal_front_quartz(0,0,MCP_QuartDimension.GetY()*MCP_QuartDimension.GetX());
double dot_front_quartz = particle_momentum.Dot(normal_front_quartz);
if (dot_front_quartz > 10e-18)
{
//return Vector(NAN, NAN, NAN);
}
// inter_front_quartz is the intersection point on the quartz
Vector inter_front_quartz = particle_pos-(((particle_pos-front_quartz_position).Dot(normal_front_quartz)/dot_front_quartz)*particle_momentum);
Vector w = inter_front_quartz - front_quartz_position;
// If the intersection of the plane falls outside window, return a
// Zero vector.
if (w.GetX() > name.GetHeight() || w.GetY() > name.GetWidth())
{
//return Vector(NAN,NAN,NAN);
}
//---------------------------------------------------------------------
// Intersection with the end surface of the quartz//
// end_position is the position of the end plan of the quartz. ---------.men hvad med protonen flyver den videre igennem MCP?!!!
Vector end_position(front_quartz_position.GetX(),front_quartz_position.GetY(),front_quartz_position.GetZ()+(0.020*MCP_z_axis_sign));
Vector normal_end_quartz(0, 0, MCP_QuartDimension.GetX()*MCP_QuartDimension.GetY()*MCP_z_axis_sign);
double dot_end_quartz = particle_momentum.Dot(normal_end_quartz);
if (dot_end_quartz > 10e-18) // If it does not intersect with the end panel, then it must intersect with the walls of the MCP.
{
//Here I find the wall intersection
Vector zero_vector(NAN,NAN,NAN);
Vector particle_intersection_with_wall = Quartz_wall_Intersection(name, inter_front_quartz, particle_pos , particle_momentum, 0 , zero_vector);
//Defining the two arrays for path of the photons and the cherenkov photon vector:
Vector pathPhoton_array[1000];
Vector CherenkovPhoton_array[1000];
Cherenkov_Photon_Generation(pname, inter_front_quartz, particle_intersection_with_wall, pathPhoton_array, CherenkovPhoton_array);
//slette Vector array_path_cherenkov_photon = Cherenkov_Photon_Generation(pname, inter_front_quartz, particle_intersection_with_wall);
static Vector intersection_array[1000];
//Here it finds out that the photon intersect with the walls or not.
for (int i = 0; i <= sizeof(pathPhoton_array); i++)
{
Vector photon_intersection_with_wall = Quartz_wall_Intersection(name, inter_front_quartz, pathPhoton_array[i] , CherenkovPhoton_array[i], 0, zero_vector);
if (photon_intersection_with_wall.GetX() != zero_vector.GetX()) //If the photon interc. with the wall:
{
// Here the reflected photon is found:
Vector reflected_photon = Quartz_wall_Intersection(name, inter_front_quartz, pathPhoton_array[i] , CherenkovPhoton_array[i], 1, CherenkovPhoton_array[i]);
//The reflected photon is intersected with MCP
Vector intersection_with_end_MCP = MCP_end_Intersection_for_Photon(reflected_photon, photon_intersection_with_wall, name);
intersection_array[i] = intersection_with_end_MCP;
//return Intersection; // tænk lige over det
}
else // If the photon do not intersect with the wall then:
{
Vector intersection_with_end_MCP = MCP_end_Intersection_for_Photon(CherenkovPhoton_array[i], pathPhoton_array[i], name);
//Intersection[] = intersection_with_end_MCP;
intersection_array[i] = intersection_with_end_MCP;
//return Intersection; // tænk lige over det
}
}
}
//The particle intersection with the MCP directly
Vector intersection_with_end_MCP = MCP_end_Intersection_for_particle(pname, particle_pos, name);
//Intersection[] = intersection_with_end_MCP;
//Generate Cherenkov photon in 2D array
Vector pathPhoton_array[1000] = {};
Vector CherenkovPhoton_array[1000] = {};
Cherenkov_Photon_Generation(pname, inter_front_quartz, intersection_with_end_MCP, pathPhoton_array, CherenkovPhoton_array);
Vector zero_vector(NAN,NAN,NAN);
for (int i = 0; i <= sizeof(CherenkovPhoton_array); i++)
{
Vector photon_intersection_with_wall = Quartz_wall_Intersection(name, inter_front_quartz, pathPhoton_array[i], CherenkovPhoton_array[i], 0, zero_vector);
if (photon_intersection_with_wall.GetX()!= NAN) //If the photon interc. with the wall:
{
// Here the reflected photon is found:
Vector reflected_photon = Quartz_wall_Intersection(name, inter_front_quartz, pathPhoton_array[i] , CherenkovPhoton_array[i], 1, CherenkovPhoton_array[i]);
//The reflected photon is intersected with MCP
Vector intersection_with_end_MCP = MCP_end_Intersection_for_Photon(reflected_photon, photon_intersection_with_wall, name);
intersection_array[i] = intersection_with_end_MCP;
}
else
{
Vector intersection_with_end_MCP = MCP_end_Intersection_for_Photon(CherenkovPhoton_array[i], pathPhoton_array[i], name);
intersection_array[i] = intersection_with_end_MCP;
}
}
}
Hope someone can figure this out.
#ifndef _VECTOR_H
#define _VECTOR_H
//class ostream;
using namespace std;
class Vector
{
private:
double fX;
double fY;
double fZ;
public:
Vector(double x=0, double y=0, double z=0);
double Length(void) const;
void SetX(double x) { fX= x; }
void SetY(double y) { fY= y; }
void SetZ(double z) { fZ= z; }
double GetX(void) const { return fX; }
double GetY(void) const { return fY; }
double GetZ(void) const { return fZ; }
Vector Cross(const Vector& v) const;
double Dot(const Vector& v) const;
Vector operator+(const Vector& v);
Vector operator-(const Vector& v);
Vector operator=(const Vector& v);
bool operator() (const Vector& lhs, const Vector& rhs) const
{
return (lhs.GetX(),lhs.GetY(),lhs.GetZ()) < (rhs.GetX(),rhs.GetY(),rhs.GetZ());
}
}
;
// Global functions
Vector operator*(const double a, const Vector& v);
Vector operator*(const Vector& v, const Vector& u);
std::ostream& operator<<(std::ostream& o, const Vector& v);
#endif
The problem, as pointed out in the last comment, is map<Vector, Vector>. This is a sorted associative container. Its Key is a Vector, and the default order is std::less<Vector>. The compiler duly instantiates std::less<Vector>, finds no specializations, and fails on <. You'll need to provide one, but it can be simple: return std::tie(r.x, r.y, r.z) < std::tie(l.x, l.y, l.z).
PS. normal_walls_roof[] runs from [0] to [3], not [1] to [4].
Related
I am developing a 2D physics engine in c++, and one of the main structures I am using is name RigidBody. In order to easily iterate through all of the RigidBody objects in each time step, I attempted to create a global vector of RigidBody object pointers.
vector<RigidBody*> RigidBodies
As suggested in other StackOverflow answers, I declared the global variable in a header file, and defined it in one of the other project .cpp files. However, when I attempt to access member functions or variables, I get bogus values. Below are my source and header files. Could someone please let me know if there is an error with this or if I am doing something fundamentally wrong, as I have been trying to find an error for a few days, and have not been able to figure it out yet.
main.cpp:
#include <iostream>
#include <vector>
#include "polygon.h"
#include "rendering.h"
int test;
std::vector<RigidBody*> RigidBodies;
RigidBody * rigPtr;
void CreateBody() {
Material m1; // Settings for ROCK.
m1.density = 0.6;
m1.restitution = 0.1;
float volume = 1;
Vector p0 = {0,1};
Vector p1 = {1,1};
Vector p2 = {1,0};
Vector p3 = {0,0};
std::vector<Vector*> Points;
Points.push_back(&p0);
Points.push_back(&p1);
Points.push_back(&p2);
Points.push_back(&p3);
//std::cout << Points.at(0)->y << '\n';
Polygon pol1(Points, m1, volume);
Polygon * polPtr = &pol1;
//std::cout << pol1.Points.at(0)->y << '\n';
std::cout << "polygon created" << '\n';
Vector pos1;
pos1.x = 10;
pos1.y = 10;
RigidBody r1(pos1, polPtr);
rigPtr = &r1;
std::cout << "rigid body created" << '\n';
// std::cout << RigidBodies.at(0)->dt << '\n';
}
// MAIN
int main() {
test = 3;
//std::cout << test << '\n';
test = 6;
CreateBody();
RigidBodies.push_back(rigPtr);
//std::cout << test << '\n';
unsigned int lastTime = SDL_GetTicks();
unsigned int currentTime;
SDL_Renderer* renderer = InitializeRender();
while(1) {
currentTime = SDL_GetTicks();
if (currentTime - lastTime > 33) {
//RigidBodies.at(0)->Step();
Render(renderer, RigidBodies);
lastTime = SDL_GetTicks();
}
}
return(0);
}
rendering.cpp:
#include <iostream>
#include "polygon.h"
#include "rendering.h"
SDL_Renderer* InitializeRender() {
SDL_Window * window = NULL;
window = SDL_CreateWindow
(
"RIGID BODIES SIM", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN
);
// Setup renderer
SDL_Renderer * renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
return(renderer);
}
void Render(SDL_Renderer * renderer, std::vector<RigidBody*> RigidBodies) {
float scale = 10; // METERS to PIXELS.
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // Clear screen.
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); // Set polygon drawing color (GREEN)
std::cout << RigidBodies.at(0)->dt << '\n';
for (int j = 0; j < RigidBodies.size(); j++) {
RigidBody * rPtr = RigidBodies.at(j); // Not recognizing rigid body pointer correctly
//std::cout << rPtr->dt << '\n';
Polygon * polyPtr = rPtr->p;
std::cout << "hey1" << '\n';
int size = polyPtr->Points.size(); // ERROR HERE //
std::cout << "hey2" << '\n';
// std::cout << polyPtr->Points.at(0)->y << '\n';
for (int i = 0; i < size; i++) {
std::cout << "hey3" << '\n';
auto pointPtr1 = polyPtr->Points.at(i);
int lastIndex = size - 1;
//std::cout << i+1 << '\n';
auto pointPtr2 = polyPtr->Points.at((i + 1) % (lastIndex)); // Modulo so last point links back up to first one.
SDL_RenderDrawLine(renderer, (rPtr->position.x + pointPtr1->x) * scale, SCREEN_HEIGHT
- (rPtr->position.y + pointPtr1->y) * scale, (rPtr->position.x + pointPtr2->x) * scale,
SCREEN_WIDTH - (rPtr->position.y + pointPtr2->y * scale));
}
}
SDL_RenderPresent(renderer);
}
rendering.h:
#include <vector>
#include <SDL2/SDL.h>
#ifndef RENDERING_H
#define RENDERING_H
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//SDL_Renderer * renderer;
SDL_Renderer* InitializeRender();
void Render(SDL_Renderer*, std::vector<RigidBody*>);
#endif
rigid_bodies.cpp
// Joaquin Matias Giorgi jmgiorgi#bu.edu Impulse-Based Physics Engine 2D //
#include <iostream>
#include <math.h>
#include <SDL2/SDL.h>
#include <vector>
#include "polygon.h"
using namespace std;
vector<RigidBody*> RigidBodies;
// VECTOR STUFF //
// Multiplication by scalar quantity.
Vector Vector::operator*(const float scalar) {
Vector vout;
vout.x = this->x * scalar;
vout.y = this->y * scalar;
return(vout);
}
// Addition overload.
Vector Vector::operator+=(const Vector vec) {
Vector vout;
vout.x = this->x + vec.x;
vout.y = this->y + vec.y;
return(vout);
}
float dot (Vector vec1, Vector vec2) {
float out = (vec1.x * vec2.x) + (vec1.y * vec2.y);
return(out);
}
float cross2d (Vector vec1, Vector vec2) {
// magnitude of perpendicular vector in 3d case.
float out = (vec1.x * vec2.y) - (vec1.y * vec2.x);
return(out);
}
// POLYGON Struct Methods //
Polygon::Polygon(vector< Vector* > Points1, Material m1, float volume1) {
Points = Points1;
m = m1;
volume = volume1;
}
float Polygon::ComputeMass() {
float mass = m.density * this->volume;
return(mass);
}
// RIGID BODY Struct Methods //
RigidBody::RigidBody(Vector position1, Polygon * p1) {
std::cout << test << '\n';
position = position1;
p = p1;
mass = p1->ComputeMass();
orientation = 0;
angularVelocity = 0;
dt = .033;
gravity.x = 0;
gravity.y = -9.8;
velocity.x = 0;
velocity.y = 0;
//RigidBodies.push_back(this); // Push to global vector of all RigidBodies.
}
// UPDATE at each iteration.
void RigidBody::Step() {
this->velocity += this->gravity * this->dt;
this->position += this->velocity * this->dt;
this->orientation += this->angularVelocity * this->dt;
}
polygon.h:
#include <vector>
#ifndef POLYGON_H
#define POLYGON_H
struct Vector {
float x;
float y;
// Multiplication by scalar quantity.
Vector operator*(const float);
// Addition overload.
Vector operator+=(const Vector);
};
struct Material {
float density;
float restitution;
};
struct Polygon {
std::vector< Vector* > Points;
float volume;
Material m;
Polygon(std::vector< Vector* >, Material, float);
float ComputeMass();
};
struct RigidBody {
float mass;
float volume;
float dt;
// Linear
Vector position;
Vector gravity;
Vector velocity;
float acceleration;
// Angular
float orientation;
float angularVelocity;
float torque;
Polygon * p;
// Constructor
RigidBody(Vector, Polygon*);
// UPDATE at each iteration.
void Step();
};
// DECLARATION
extern std::vector<RigidBody*> RigidBodies; // Global Vector of RigidBody Pointers.
#endif
Makefile:
sim:
g++ -std=c++11 main.cpp rigid_bodies.cpp rendering.cpp -I include -L lib -l SDL2-2.0.0
In your function CreateBody, RigidBody r1 is created on the stack and ceases to exist when the function returns. Your pointer rigPtr (and the pointers in Points and polPtr) is no longer valid after the end of the function. If you call the CreateBody in a loop you will probably see that you get the same pointers for every call.
The simplest solution is to not use pointers at all, your objects are fairly small and shouldn't be too expensive to copy (or even cheaper to move).
If you really want to use pointers you need to allocate your objects on the heap rather than the stack using new. Note that these objects will then need to the deallocated using delete. A safer solution would be to wrap your pointers in std::shared_ptr or std::unique_ptr which takes care of deleting the objects automatically.
I'm trying to move the user mouse using mouse_event function in WinAPI. This is my code:
while (LeftMouseDown)
{
POINT cursorPos;
GetCursorPos(&cursorPos);
//X Axis And Y Axis is DWORD Array
mouse_event(MOUSEEVENTF_MOVE, xaxis[iCount], yaxis[iCount], 0, 0);
iCount++;
Sleep(200);
}
It's working good but the problem is that I want the code smooth movement, because the function teleports the cursor instantly and I don't want that, I want it to be smooth transition or something like that.
From what it looks like, you are trying to move across a path of points in a smooth manner.
If so, then you are going to have to interpolate along that path via time.
Essentially, the idea is that you first obtain the total length of the path. Then as you are updating time you obtain a total distance via the total duration and the elapsed amount of time. Finally, you find the two points where the obtained distance is somewhere in the middle. Then you simply interpolate along those two points to get a relatively accurate point.
With this class you can pass the points for the path and a a duration to specify how long you would like to be moving along the path for. Then you would simply update it via time intervals.
Mover.h
#include <chrono>
#include <vector>
#ifndef MOVER_H
#define MOVER_H
struct Point {
int x, y;
Point(int x_, int y_)
: x(x_), y(y_) {
}
Point() : Point(0, 0) {
}
};
class Mover {
public:
struct PointData {
float total;
float distance;
Point p1;
Point p2;
PointData()
: total(0.f),
distance(0.f) {
}
PointData(float total, float distance, Point p1, Point p2)
: total(total),
distance(distance),
p1(p1),
p2(p2) {
}
};
using TimePoint = std::chrono::microseconds;
private:
std::vector<Point> m_points;
std::vector<PointData> m_distances;
TimePoint m_duration;
TimePoint m_elapsed;
float m_length;
public:
Mover(std::initializer_list<Point> points, TimePoint duration = std::chrono::microseconds(2000000));
template<typename iter_t>
Mover(iter_t begin, iter_t end, TimePoint duration = std::chrono::microseconds(2000000))
: m_points(begin, end),
m_duration(duration),
m_elapsed(std::chrono::milliseconds(0)) {
updateLength();
}
Mover(const Mover&) = default;
Mover& operator=(const Mover&) = default;
Point update(TimePoint delta);
bool isComplete() const;
void setDuration(TimePoint duration);
TimePoint getDuration() const;
TimePoint getElapsed() const;
private:
void updateLength();
};
#endif // MOVER_H
Mover.cpp
#include "Mover.h"
#include <algorithm>
#include <cmath>
Mover::Mover(std::initializer_list<Point> points, TimePoint duration)
: Mover(points.begin(), points.end(), duration)
{
}
Point Mover::update(TimePoint delta)
{
const auto comparison = [](float left, const PointData& right) {
return left < right.total;
};
m_elapsed = std::min(m_elapsed + delta, m_duration);
const float length = (static_cast<float>(m_elapsed.count()) / static_cast<float>(m_duration.count())) * m_length;
auto& data = *std::prev(std::upper_bound(m_distances.begin(), m_distances.end(), length, comparison));
const float percent = (length - data.total) / data.distance;
Point point(data.p1.x + percent * (data.p2.x - data.p1.x), data.p1.y + percent * (data.p2.y - data.p1.y));
return point;
}
bool Mover::isComplete() const
{
return m_duration == m_elapsed;
}
void Mover::setDuration(TimePoint duration)
{
m_duration = duration;
}
Mover::TimePoint Mover::getDuration() const
{
return m_duration;
}
Mover::TimePoint Mover::getElapsed() const
{
return m_elapsed;
}
void Mover::updateLength()
{
auto distance = [](float x1, float y1, float x2, float y2) -> float{
return std::sqrt(((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
};
float length = 0.f;
for (std::size_t index = 0; (index + 1) < m_points.size(); ++index) {
const float dist = distance(m_points[index].x, m_points[index].y, m_points[index + 1].x, m_points[index + 1].y);
m_distances.emplace_back(length, dist, m_points[index], m_points[index + 1]);
length += dist;
}
m_length = length;
}
Example
#include <iostream>
#include "Mover.h"
int main() {
std::vector<Point> points{ { 0, 0 }, { 100, 100 } };
Mover move(points.begin(), points.end());
auto t1 = std::chrono::steady_clock::now();
while (!move.isComplete()) {
auto t2 = std::chrono::steady_clock::now();
auto point = move.update(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1));
std::cout << point.x << ' ' << point.y;
t1 = t2;
}
}
It's worth mentioning that in order to use this you are going to have to keep track of the time in order to update the mover. So it's probably worth implementing a Clock class or something to keep track of the time for you.
Also, if you want to move along the path relative to the current cursor position, then you would have to simply add the cursor position to the active path point.
I know this is very late but I might as well answer it.
while doing golang I used this library called robot.go and over there they have a function that does the smooth input. So if you want you can use that as a reference.
https://github.com/go-vgo/robotgo/blob/master/mouse/mouse_c.h
looking at your code your mouse will jump pixels every 200 ms.
while (LeftMouseDown)
{
POINT cursorPos;
GetCursorPos(&cursorPos);
//X Axis And Y Axis is DWORD Array
int i;
for (i = 0; i < 20; i++)
{
mouse_event(MOUSEEVENTF_MOVE, (xaxis[icount]-cursorPos.x)/20, (yaxis[icount]-cursorPos.y)/20, 0, 0);
iCount++;
Sleep(10);
}
}
I am using OpenCV 2.4.10 with Visual Studio 2013 for my code. But I am getting the following linking error:
1>Pathfinding.obj : error LNK2019: unresolved external symbol "public:
class cv::Vec & __cdecl cv::Mat::at >(int,int)"
(??$at#V?$Vec#E$02#cv###Mat#cv##QEAAAEAV?$Vec#E$02#1#HH#Z) referenced
in function "private: struct Pathfinding::Point2A * __cdecl
Pathfinding::GetNeighbors(struct Pathfinding::Point2A,int &)"
(?GetNeighbors#Pathfinding##AEAAPEAUPoint2A#1#U21#AEAH#Z)
1>C:\Users\ysingh\Documents\DstarLite\OpenCV\Astar\x64\Debug\Astar.exe
: fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Here is the header file (please see struct Point2A in class definition) where the above error is referring to:
#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<string>
class Pathfinding
{
private :
//Two dimensional , integer -based point structure , contains additional variables for pathfinding calculation
**struct Point2A**
{
// x, y the coordinates of the point
//dir is the direction from the previous point . see directions coding below
int x, y, dir;
//level: the cost of route from start to this point
//fscore: the essence of the A* algorithm, value is : [level] + [in air distance from destination] * astar_weight
float fScore, level;
//Constructors
Point2A() : x(0), y(0), fScore(0), dir(0){};
Point2A(int _x, int _y, float _level = 0.f, int _dir = 0) :x(_x), y(_y), level(_level), fScore(0), dir(_dir) {};
//== operator overload
bool operator == (const Point2A other);
};
//CompByPos : struct used in the stl map<Point2A, Point2A> during the pathfinding
//it only contains a comparator function
//we need this, because every point is unique by position, but not by fscore
struct CompByPos
{
bool operator()(const Point2A a, const Point2A b) const;
};
//CompByFScore : contains a comparating function, which works by fscore
//it gives priority for the smaller fScore
//used in stl priority_queue<Point2A>
struct CompByFScore
{
bool operator()(const Point2A a, const Point2A b);
};
//mapimg is the map got, pathmap is the same, but the pixels of the path are colored
//pathmap is only valid after calculate path
//blurmap is matimg blurred with opencv function, its used in keeping away from walls
cv::Mat mapimg, pathmap, blurmap;
//astar_weight is the multiplier of A* coefficient
//wall_weight is used in keeping away from walls features
float astar_weight, wall_weight;
//no comment
Point2A start, dest;
//daigonal decides if a pixel (which is a node) has 4 or 8 neighbours
//see direction coding below
//calculated decides if the Pathfinding object has valid path for current map and settings
bool diagonal, calculated;
//mrows and mcols refers to the size of mapimg
//blursize is used in avaoiding wall avoidance feature
int mrows, mcols, blur_size;
//stores the list of directions for the path
std::string dir;
//calculated Eucledian Distance between two points a and b
float Distance(Point2A a, Point2A b);
//returns an array of the points surrounding point p
//the length of the array is not constant, because the function performs
//OnMap checks too. use arraySize ref variable to get the size of the array returned
Point2A* GetNeighbors(Point2A p, int& arraySize);
// Function sets default values
void InitValues();
//Checks if point p is wall
//Class support black and white maps, where black pixels are wall
bool IsWall(Point2A p);
//Function decides if coordinates of this point are on map or not
bool OnMap(int x, int y);
public:
enum ErrorCodes
{
NoError = 0,
NoMap,
StartIsWall,
DestIsWall,
NoPath,
AlreadyCalculated
};
static const int diagonalDirX[];
static const int diagonalDirY[];
static const int nonDiagonalDirX[];
static const int nonDiagonalDirY[];
//constructor :sets default values diagonal = true, astar coefficient 0.3
Pathfinding();
//constructor, argument map is the map on which algorithm is implemented
Pathfinding(cv::Mat map, bool _diagonal = true);
//Set OpenCV Mat image as the map
void SetMap(cv::Mat map);
////sets the A* pathfinding coefficient. 0.f means Dijkstra's algorithm, anything else is A* (positive values recommended).
//The bigger the value, the more the algorithm steers towards the destination
//but setting it too high can result in suboptimal path
//after changing that, have to call CalculatePath again
void SetAWeight(float weight);
//if set to true, each pixel has 8 connected neighbor, else only 4 - see GetDirections() comment
//after changing that, have to call CalculatePath again
void SetDiagonal(bool _diagonal);
//sets the value of how much the algorithm tries to avoid going near walls.
//weight: the amount the walls push away the route. default 10.f
//0.f disables the feature
//avoidZoneLevel: the size of the zone surrounding the walls, in which the upper effect works. default: 5
void SetWallWeight(float weight, int avoidZoneLevel);
//sets the start point. the coordinate system is the OpenCV/image default, the origin is the upper left corner of the image.
//start and destination points have to be set after the map image!
void SetStart(int x, int y);
void SetDestination(int x, int y);
//returns the map, on which the calculated path is marked red
//call this after CalculatePath(), otherwise returns empty map
cv::Mat GetPathMap();
// returns a std::string of numbers, which represent the directions along the path.Direction coding(relative to p) :
//call after CalculatePath()
//if diagonal is set to true if diagonal == false
// [0] [1] [2] [3]
// [3] [p] [4] [2] [p] [0]
// [5] [6] [7] [1]
std::string GetDirections();
//evaluates the algorithm. It's a separate function because it takes some time
//check out the ErrorCodes enum to decode the returned values
ErrorCodes CalculatePath();
};
I am also attaching the .cpp for this class
#include "Pathfinding.h"
bool Pathfinding::Point2A::operator==(const Point2A other) {
return x == other.x && y == other.y;
}
bool Pathfinding::CompByPos::operator()(const Point2A a, const Point2A b) const
{
if (a.x == b.x)
return a.y > b.y;
else
return a.x > b.x;
}
bool Pathfinding::CompByFScore::operator()(const Point2A a, const Point2A b)
{
return a.fScore > b.fScore;
}
float Pathfinding::Distance(Point2A a, Point2A b)
{
float x = static_cast<float>(a.x - b.x);
float y = static_cast<float>(a.y - b.y);
return sqrtf(x*x + y*y);
}
Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)
{
arraySize = 0;
uchar size;
if (diagonal)
size = 8;
else
size = 4;
Point2A* ret = new Point2A[size];
for (int i = 0; i < size; i++) {
int x, y;
if (diagonal)
{
x = p.x + diagonalDirX[i];
y = p.y + diagonalDirY[i];
}
else
{
x = p.x + nonDiagonalDirX[i];
y = p.y + nonDiagonalDirY[i];
}
if (!OnMap(x, y))
continue;
float level = p.level + 1.f + (255 - blurmap.at<cv::Vec3b>(y, x)[2]) / 255.f * wall_weight;
Point2A n = Point2A(x, y, level, i);
if (diagonal && (i == 0 || i == 2 || i == 5 || i == 7))
n.level += 0.414213f;
ret[arraySize] = n;
arraySize++;
}
return ret;
}
void Pathfinding::InitValues()
{
astar_weight = 0.3f;
wall_weight = 10.f;
blur_size = 11;
diagonal = true;
calculated = false;
}
bool Pathfinding::IsWall(Point2A p)
{
if (mapimg.at<cv::Vec3b>(p.y, p.x) == cv::Vec3b(0, 0, 0))
return true;
return false;
}
bool Pathfinding::OnMap(int x, int y)
{
if (x >= 0 && y >= 0 && x < mcols && y < mrows)
return true;
return false;
}
const int Pathfinding::diagonalDirX[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
const int Pathfinding::diagonalDirY[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int Pathfinding::nonDiagonalDirX[] = { 1, 0, -1, 0 };
const int Pathfinding::nonDiagonalDirY[] = { 0, 1, 0, -1 };
Pathfinding::Pathfinding()
{
InitValues();
}
Pathfinding::Pathfinding(cv::Mat map, bool _diagonal)
{
InitValues();
SetMap(map);
diagonal = _diagonal;
}
void Pathfinding::SetMap(cv::Mat map)
{
if (!map.empty())
{
mapimg = map;
calculated = false;
mrows = map.rows;
mcols = map.cols;
GaussianBlur(mapimg, blurmap, cv::Size(blur_size, blur_size), 0);
}
}
void Pathfinding::SetAWeight(float weight)
{
if (astar_weight != weight)
{
astar_weight = weight;
calculated = false;
}
}
void Pathfinding::SetDiagonal(bool _diagonal)
{
if (diagonal != _diagonal)
{
diagonal = _diagonal;
calculated = false;
}
}
void Pathfinding::SetWallWeight(float weight, int avoidZoneLevel)
{
if (wall_weight == weight && blur_size == 2 * avoidZoneLevel + 1)
return;
wall_weight = weight;
if (avoidZoneLevel >= 0)
blur_size = 2 * avoidZoneLevel + 1;
calculated = false;
}
void Pathfinding::SetStart(int x, int y)
{
if (!mapimg.empty())
{
if (OnMap(x, y))
{
start = Point2A(x, y);
calculated = false;
}
}
}
void Pathfinding::SetDestination(int x, int y)
{
if (!mapimg.empty())
{
if (OnMap(x, y))
{
dest = Point2A(x, y);
calculated = false;
}
}
}
cv::Mat Pathfinding::GetPathMap()
{
if (calculated) return pathmap;
else return cv::Mat();
}
std::string Pathfinding::GetDirections()
{
if (calculated) return dir;
else return std::string();
}
Pathfinding::ErrorCodes Pathfinding::CalculatePath()
{
if (calculated)
return AlreadyCalculated;
if (mapimg.empty())
return NoMap;
if (IsWall(start))
return StartIsWall;
if (IsWall(dest))
return DestIsWall;
dir = std::string();
mapimg.copyTo(pathmap);
int **closedSet = new int*[mrows];
float **openSet = new float*[mrows];
for (int i = 0; i < mrows; i++) {
closedSet[i] = new int[mcols];
openSet[i] = new float[mcols];
for (int j = 0; j < mcols; j++) {
closedSet[i][j] = 0;
openSet[i][j] = -1.0f;
}
}
std::priority_queue<Pathfinding::Point2A, std::vector<Point2A>, CompByFScore> openSetQue[2];
int osq = 0;
std::map <Pathfinding::Point2A, Pathfinding::Point2A, CompByPos> cameFrom;
start.fScore = Distance(start, dest);
openSetQue[osq].push(start);
openSet[start.y][start.x] = 0.0f;
while (openSetQue[osq].size() != 0) {
Point2A current = openSetQue[osq].top();
if (current == dest) {
while (cameFrom.size() != 0) {
pathmap.at<cv::Vec3b>(current.y, current.x) = cv::Vec3b(0, 0, 255);
dir = std::to_string(current.dir) + dir;
auto it = cameFrom.find(current);
Point2A keytmp = current;
if (it == cameFrom.end()) {
for (int i = 0; i < mrows; i++) {
delete openSet[i];
delete closedSet[i];
}
delete openSet;
delete closedSet;
calculated = true;
dir = dir.substr(1, dir.length() - 1);
return NoError;
}
current = cameFrom[current];
cameFrom.erase(keytmp);
}
}
openSetQue[osq].pop();
closedSet[current.y][current.x] = 1;
int arraySize;
Point2A *neighbors = GetNeighbors(current, arraySize);
for (int i = 0; i < arraySize; i++) {
Point2A neighbor = neighbors[i];
if (closedSet[neighbor.y][neighbor.x] == 1)
continue;
if (IsWall(neighbor)) {
closedSet[neighbor.y][neighbor.x] = 1;
continue;
}
float ngScore = neighbor.level;
if (openSet[neighbor.y][neighbor.x] == -1.0f || ngScore < openSet[neighbor.y][neighbor.x]) {
cameFrom[neighbor] = current;
neighbor.fScore = ngScore + Distance(neighbor, dest) * astar_weight;
if (openSet[neighbor.y][neighbor.x] == -1.0f) {
openSet[neighbor.y][neighbor.x] = ngScore;
openSetQue[osq].push(neighbor);
}
else {
openSet[neighbor.y][neighbor.x] = ngScore;
while (!(neighbor == openSetQue[osq].top())) {
openSetQue[1 - osq].push(openSetQue[osq].top());
openSetQue[osq].pop();
}
openSetQue[osq].pop();
if (openSetQue[osq].size() >= openSetQue[1 - osq].size()) {
osq = 1 - osq;
}
while (!openSetQue[osq].empty()) {
openSetQue[1 - osq].push(openSetQue[osq].top());
openSetQue[osq].pop();
}
osq = 1 - osq;
openSetQue[osq].push(neighbor);
}
}
}
delete neighbors;
}
return NoPath;
}
Here is my main file .cpp too :
#include"Pathfinding.h"
#include<opencv2\highgui\highgui.hpp>
#include<iostream>
Pathfinding pathfinding;
cv::Mat mapimg;
void DisplayMap()
{
cv::Mat tmp;
cv::imshow("Path", tmp);
}
int main()
{
//Open and load the map
mapimg = cv::imread("test.png");
pathfinding.SetMap(mapimg);
pathfinding.SetWallWeight(0.f, 0);
pathfinding.SetStart(1, 1);
pathfinding.SetDestination(39, 53);
pathfinding.SetDiagonal(false);
DisplayMap();
}
I think I am using Pathfinding class twice in the definition of the functions in .cpp ( i.e. Line 29 in .cpp file > Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)
My intention is not to throw a bunch of codes at the people but to give them an complete picture for the problem so that people can provide me some useful suggestions. My apologies for this.
My deadlines are near and I am constrained with time. Can someone suggest me some solutions.
I assume your project settings are the problem for this (your write you did a working minimalistic example, so you indeed use right libs and includes).
Please check what the include and lib paths evaluate to (check this inside the configuration site). Maybe you see they are relative paths or a makro was set wrong.
Usually, an "UNRESOLVED EXTERNAL" error means you did not link the right lib (32/64 debug/release these are 4 different combinations!) or the path to the lib is wrong.
See this answer,
If you DID explicitly set up linking with all the necessary libraries,
but linking errors still show, you might be mixing up 64/32 bit
libraries and application.
BUILD -> Configration Manager. check 'platform' is 'x64'
Check that your Project -> Properties -> VC++ Directories -> Library Directories, includes the path where the OpenCV libraries are
And Linker -> General -> Aditional Library Directories
C:\opencv\build\x64\vc11\lib
(on a 64-bit machine running VS2012, it will vary on other setups).
I'm trying to implement collision detection in sfml using the separating axis theorem but my function to get the min translation vector (getMtv()) is always returning that there is a collision (MTV::IsValid()). I was following a tutorial here
but I can't see where I went wrong.
#include <iostream>
#include <math.h>
#include <SFML/Graphics.hpp>
#include <gtest/gtest.h>
typedef sf::Vector2f Vector2;
typedef sf::Vector2f Axis;
typedef sf::Vector2f Projection;
typedef std::vector<Axis> AxesVec;
class MTV
{
private:
bool _valid;
Axis _axis;
float _overlap;
public:
MTV(Axis axis, float overlap, bool valid)
{
_valid = valid;
_overlap = overlap;
_axis = axis;
}
bool IsValid() const
{
return _valid;
}
};
Vector2 perpendicular(Vector2 v)
{
return Vector2(v.y, -v.x);
}
float dot(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.x) + (vec1.y * vec2.y);
}
float magnitude(Vector2 v)
{
return std::sqrt(dot(v,v));
}
class Polygon : public sf::ConvexShape
{
public:
const AxesVec& GetAxes() const
{
return axes;
}
AxesVec axes;
void generateAxes()
{
for (int i = 0; i < getPointCount(); i++)
{
// get the current vertex
Vector2 p1 = getPoint(i); //shape.vertices[i];
// get the next vertex
Vector2 p2 = getPoint(i + 1 == getPointCount() ? 0 : i + 1);
// subtract the two to get the edge vector
Vector2 edge = p1 - p2;
// get either perpendicular vector
Vector2 normal = perpendicular(edge);
// the perp method is just (x, y) => (-y, x) or (y, -x)
axes.push_back(normal / magnitude(normal));
}
};
float cross(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.y) - (vec1.y * vec2.x);
}
Vector2 project(Polygon p, Axis axis)
{
float min = dot(axis, p.getPoint(0)); //axis.dot(shape.vertices[0]);
float max = min;
for (int i = 1; i < p.getPointCount(); i++)
{
// NOTE: the axis must be normalized to get accurate projections
float prj = dot(axis, p.getPoint(i));//axis.dot(shape.vertices[i]);
if (prj < min)
{
min = prj;
}
else if (prj > max)
{
max = prj;
}
}
//Projection proj = new Projection(min, max);
return Projection(min, max);
}
class Collison
{
private:
Vector2 mtv;
Polygon a;
Polygon b;
};
bool overlap(Projection a, Projection b)
{
// x = min & y = max
return !(a.x > b.y || a.x > b.y);
}
float getOverlap(Projection a, Projection b)
{
// x = min & y = max
return (a.y < b.y) ? a.y - b.x : b.y - a.x;
}
MTV getMtv(Polygon a, Polygon b)
{
float overlapMax = std::numeric_limits<float>::infinity();// really large value;
float Overlap;
Axis smallest;// = null;
AxesVec axesA = a.GetAxes();
AxesVec axesB = b.GetAxes();
// loop over the axes1
for (auto&& axis : axesA) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
float o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
for (auto&& axis : axesB) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
double o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
//MTV mtv = new MTV(smallest, overlap);
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return MTV(smallest, Overlap, true);
}
int main(int argc, char **argv)
{
Polygon polygon;
polygon.setPointCount(3);
polygon.setPoint(0, sf::Vector2f(500, 100));
polygon.setPoint(1, sf::Vector2f(250, 500));
polygon.setPoint(2, sf::Vector2f(750, 500));
polygon.setFillColor(sf::Color::Red);
polygon.generateAxes();
Polygon polygon2;
polygon2.setPointCount(3);
polygon2.setPoint(0, sf::Vector2f(100, 0));
polygon2.setPoint(1, sf::Vector2f(50, 150));
polygon2.setPoint(2, sf::Vector2f(150, 150));
polygon2.generateAxes();
//polygon2.setPoint(0, sf::Vector2f(100, 0));
//polygon2.setPoint(1, sf::Vector2f(500, 150));
//polygon2.setPoint(2, sf::Vector2f(250, 150));
polygon2.setFillColor(sf::Color::Green);
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
window.draw(polygon);
window.draw(polygon2);
std::cout << getMtv(polygon, polygon2).IsValid() << std::endl;
// end the current frame
window.display();
}
return 0;
}
This is my implementation of Sutherland-Hodgman Polygon Clipping Algorithm.
I am trying to clip a Positively Oriented and Convex polygon with a rectangular clipping area.
I am using BGI library from colorado university. I am using OS=Win7. Visual C++ 2008 Express.
This program isn't working correctly.
//Sutherland-Holdgman Line Clipping
#include "Line2d.h"
#include "Rectangle2d.h"
#include "Coordinates2d.h"
#include "Bits.h"
#include "Polygon2d.h"
#include <list>
typedef enum PointPosition
{
Left, Right
} PointPosition;
typedef enum LinePosition
{
CompletelyOut, CompletelyIn, ClippingCandidate, ClippingCandidateExtended
} LinePosition;
class ClippingPolygon2d
{
private:
Rectangle2d rectangle;
Polygon2d polygon;
public:
ClippingPolygon2d(){}
//ClippingPolygon2d(Rectangle2d & rectangle, Polygon2d & polygon): rectangle(rectangle), polygon(polygon){}
void SetCandidatePolygon(Polygon2d & pol)
{
polygon = pol;
}
void SetClippingPolygon(Rectangle2d & rect)
{
rectangle = rect;
}
public:
std::vector<Point2d> GetClippedPoints()
{
std::vector<Point2d> vertexList = polygon.GetVertices();
std::vector<Point2d> clipping = rectangle.GetVertices();
for (size_t i = 0; i < clipping.size(); i++)
{
//obtaining one vertex and the next one from the clipping region.
//Then, constructing a line from them.
Line2d clippingEdge(clipping[i], clipping[(i + 1) % clipping.size()]);
std::vector<Point2d> temp;
for (size_t j = 0; j < vertexList.size(); j++)
{
Point2d polygonEdgeStart = vertexList[j];
Point2d polygonEdgeEnd = vertexList[(j + 1) % vertexList.size()];
if (clippingEdge.onLeft(polygonEdgeStart))
{
if (clippingEdge.onLeft(polygonEdgeEnd))
{
// point on the left, just add to vertexList
temp.push_back(polygonEdgeEnd);
}
else //Right
{
// calculate intersection I and add it to vertexList
temp.push_back(clippingEdge.GetIntersection(Line2d(polygonEdgeStart, polygonEdgeEnd)));
}
}
else //Right
{
if (clippingEdge.onLeft(polygonEdgeEnd))
{
//calculate intersection I and add I and polygonEdgeEnd to vertexList
temp.push_back(clippingEdge.GetIntersection(Line2d(polygonEdgeStart, polygonEdgeEnd)));
temp.push_back(polygonEdgeEnd);
}
else //Right
{
// nothing to do: outside of the window
}
}
}
vertexList = temp;
}
return vertexList;
}
};
int main()
{
//////////////////////// Initialize ///////////////////////
Coordinates2d::ShowWindow("Sutherland-Hodgeman Line Clipping");
///////////////////////////////////////////////////////////////
Rectangle2d rectangle(Point2d(20, 20), Point2d(200, 140));
Polygon2d polygon;
polygon.Add(Point2d(30, 40));
polygon.Add(Point2d(110,40));
polygon.Add(Point2d(130,110));
polygon.Add(Point2d(70,150));
polygon.Add(Point2d(10,110));
ClippingPolygon2d clip;
clip.SetClippingPolygon(rectangle);
clip.SetCandidatePolygon(polygon);
std::vector<Point2d> clippedVerticesList = clip.GetClippedPoints();
Coordinates2d::Draw(polygon, Red);
Coordinates2d::Draw(rectangle, Magenta);
Coordinates2d::Draw(clippedVerticesList, Thick, Yellow);
//////////////////////// Draw /////////////////////////
Coordinates2d::Wait(); return 0;
///////////////////////////////////////////////////////////////
}
double Line2d :: orientationOf(Point2d & point)
{
return (end.x - start.x) * (point.y - start.y) - (end.y - start.y) * (point.x - start.x);
}
bool Line2d :: onRight(Point2d & point)
{
return orientationOf(point) < -E; //for precision reason
}
bool Line2d :: onLeft(Point2d & point)
{
return orientationOf(point) > E;//for precision reason
}
I found at least 2 problems in GetClippedPoints function:
you use if(i) - it's not right because i iterates on windows edges. I think that you suppose to use if(j).
supposed that for(size_t i=0 ; i<clippingRegionLines.size() ; i++) should transform (generate new) vertexList (initially vertexList==allPolygonVertexes) and use it in next step. (so after all iterations of this loop you will get clipped polygon). So my advice here: represent input polygon as list of vertexes instead of list of edges.
Also you need to be sure that std::vector<Line2d> clippingRegionLines = rectangle.GetLines(); returns segments oriented counter-clockwise.