2017-05-17 1 views
0

Je dois écrire une fonction qui détecte l'intersection et retourne vrai ou faux. J'ai le fichier Shape.cpp, et les fichiers rectangle.cpp, circle.cpp héritent de celui-ci. J'ai essayé de le calculer, mais j'ai échoué. Il n'y a pas d'erreur, mais quand mon programme démarre, il plante. Ma question est pourquoi il se bloque? est mon chemin? Voici le fichier circle.cpp.Comment écrire une fonction d'intersection pour n'importe quel type de formes

bool Circ::intersects(Shape* pshape) 
{ 
    Rect *p1 = dynamic_cast<Rect*>(pshape); 
    Circ *p2 = dynamic_cast<Circ*>(pshape); 

    if(p1) 
    { 
     float circleDistance_x = abs(p2->getPos().x - p1->getPos().x); 
     float circleDistance_y = abs(p2->getPos().y - p1->getPos().y); 

     if(circleDistance_x > (p1->getSize().x/2 + p2->getRad())) 
      return false; 
     if(circleDistance_y > (p1->getSize().y/2 + p2->getRad())) 
      return false; 
     if(circleDistance_x <= (p1->getSize().x/2)) 
      return true; 
     if(circleDistance_y <= (p1->getSize().y/2)) 
      return true; 
     float cornerDistance_sq = (circleDistance_x - (p1->getSize().x/2)) + (circleDistance_y - (p1->getSize().y/2))*(circleDistance_y - (p1->getSize().y/2)); 

     return (cornerDistance_sq <= p2->getRad()^2); 

    } 

    return false; 
} 

Ce n'est pas le code tout ce que je veux écrire. Mais quand ça échoue, je me suis arrêté pour écrire.

et mon fichier Shapes.h

#ifndef _SHAPES_H 
#define _SHAPES_H 


struct Point2d 
{ 
    float x, y; 

}; 
struct Point3d 
{ 
    float r, g, b; 

}; 

class Shape 
{ 
protected: 
    bool m_bMarked; 
    Point3d m_col; 
    Point2d m_veldir; 
    Point2d m_pos; 
    float m_vel; 
public: 
    Shape(Point2d& pos, Point2d& veldir, float vel, Point3d& col) 
     :m_pos(pos),m_veldir(veldir),m_vel(vel),m_col(col) 
    { 
     m_bMarked = false; 
    } 
    virtual ~Shape() {} 
    virtual void draw() = 0; 
    virtual bool intersects(Shape*) = 0; 
    inline void move() { m_pos.x += m_veldir.x*m_vel; m_pos.y += m_veldir.y*m_vel; } 
    inline void invert_xdir() { m_veldir.x *= -1; } 
    inline void invert_ydir() { m_veldir.y *= -1; } 
    inline void MarkShape() { m_bMarked = true; } 
    inline void UnMarkShape() { m_bMarked = false; } 
    inline bool isMarked() { return m_bMarked; } 
    inline void increase_vel() { m_vel += 0.01f; } 
    inline void decrease_vel() { m_vel -= 0.01f; } 

}; 


#endif 

Et enfin mon fichier ShapesMain.cpp

#include <time.h> 
#include <GL/glut.h> 
#include <cmath> 

#include "Rectangle.h" 
#include "Circle.h" 


// YOU CAN CHANGE THE NUMBER OF SHAPES 
#define SHAPE_COUNT 20 

// YOU CAN MODIFY WINDOW SIZE BY CHANGING THESE 
// YOU MAY ALSO VIEW WINDOW IN FULL SCREEN 
#define WINDOWX 500 
#define WINDOWY 500 

// UNCOMMENT THE LINE BELOW TO STOP MOVING SHAPES 
//#define NO_MOTION 

// CHANGE THESE DIMENSIONS HOWEVER YOU LIKE 
#define MAX_SHAPE_DIM 70 
#define MIN_SHAPE_DIM 10 

float g_windowWidth = WINDOWX; 
float g_windowHeight = WINDOWY; 

Shape* g_shapeList[SHAPE_COUNT]; 
int  g_numShapes = 0; 
bool g_bShowIntersection = true; 



//------------------------------------ 

void Initialize() 
{ 
    srand (time(NULL)); 

    // delete previous shapes, if there is any 
    if (g_numShapes > 0) 
    { 
     for (int i = 0; i < g_numShapes; i++) 
      delete g_shapeList[i]; 
    } 

    // create a new shape repository 
    do { 
     g_numShapes = rand() % SHAPE_COUNT; // number of shapes are randomly determined  
    } while (g_numShapes < 5); // we dont want to have less than 5 shapes 


    int rect_count = g_numShapes * (rand() % 10/10.0f); 
    int circle_count = g_numShapes - rect_count; 

    int half_wind_x = 3* g_windowWidth/4; 
    int half_wind_y = 3* g_windowHeight/4; 
    int max_dim = MAX_SHAPE_DIM; // max dim. of any shape 
    int min_dim = MIN_SHAPE_DIM; // min dim. of any shape 
    int quad_wind = g_windowWidth/4; 

    for (int i= 0; i<g_numShapes; i++) 
    { 

     float x, y; 
     float v1, v2; 

     // set positions 
     do { 
      x = rand() % half_wind_x; 
     } while (x <= quad_wind); 

     do { 
      y = rand() % half_wind_y; 
     } while (y <= quad_wind); 
     Point2d pos = { x,y }; 

     // set velocity directions 
     do{ 
      v1 = rand() % 10/10.0f; 
      v2 = rand() % 10/10.0f;   
     } while (v1 == 0 || v2 == 0); 

     v1 *= (rand() % 2) ? -1 : 1; 
     v2 *= (rand() % 2) ? -1 : 1; 
     float vnorm = sqrt(v1*v1 + v2*v2); 
     Point2d veldir = { v1/vnorm, v2/vnorm }; 

     // set velocity 
     float vel; 
     do { 
      vel = rand() % 2/10.0f; 
     } while (vel == 0); 

#ifdef NO_MOTION 
     vel = 0.0f; 
#endif 
     //set color 
     float R = rand()%100/100.0f; 
     float G = rand()%100/100.0f; 
     float B = rand()%100/100.0f; 
     Point3d color = { R,G,B }; 

     // construct objects 
     if (i < rect_count) 
     { 
      float wx; 
      float wy; 
      do { 
       wx = rand() % quad_wind; 
      } while (wx < min_dim || wx>max_dim); 

      do { 
       wy = rand() % quad_wind; 
      } while (wy < min_dim || wy>max_dim); 

      Point2d size = { wx, wy };   

      Rect* pRect = new Rect(pos, size, veldir, vel, color); 
      g_shapeList[i] = pRect; 
     } 
     else 
     { 
      float rad; 
      do { 
       rad = rand() % quad_wind; 
      } while (rad < min_dim || rad>max_dim); 


      Circ* pCirc = new Circ(pos, rad, veldir, vel, color); 
      g_shapeList[i] = pCirc; 
     } 
    } 

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 

} 
//------------------------------------- 
// This function handles the intersections of shapes. 
// if the user is not interested in marking intersections 
// s/he can set bMarkIntersections to false..in this case 
// no intersection test is performed 
void MarkObjects(bool bMarkIntersections) 
{ 
    if (bMarkIntersections == false) 
    { 
     for (int i = 0; i < g_numShapes; i++) 
      g_shapeList[i]->UnMarkShape(); 
    } 
    else 
    { 
     // reset the states of all shapes as unmarked 
     for (int i = 0; i < g_numShapes; i++) 
      g_shapeList[i]->UnMarkShape(); 

     for (int i = 0; i < g_numShapes; i++) 
     {   
      for (int j = i+1; j < g_numShapes; j++) 
      { 

       if (g_shapeList[i]->intersects(g_shapeList[j])) 
       { 
        g_shapeList[i]->MarkShape(); 
        g_shapeList[j]->MarkShape(); 

       } 
      } 
     } 
    } 

} 
//------------------------------------ 
void UpdateData() 
{ 
    // create viewport bounding rectangles to keep the shapes within the viewport 
    Point2d Winpos = { -1.0,0.0 }; 
    Point2d Winsize = { 1.0 , g_windowHeight }; 
    Point2d Winveldir = { 0,0 }; // dummy veldir 
    float Winvel = 0.0f; //not moving 
    Point3d Wincol = { 0,0,0 }; // dummy color 
    Rect WindowRectLeft(Winpos, Winsize, Winveldir, Winvel, Wincol); 
    Winpos.x = 0.0; Winpos.y = -1.0; 
    Winsize.x = g_windowWidth; Winsize.y = 1.0; 
    Rect WindowRectBottom(Winpos, Winsize, Winveldir, Winvel, Wincol); 
    Winpos.x = g_windowWidth; Winpos.y = 0.0; 
    Winsize.x = 1; Winsize.y = g_windowHeight; 
    Rect WindowRectRight(Winpos, Winsize, Winveldir, Winvel, Wincol); 
    Winpos.x = 0.0; Winpos.y = g_windowHeight; 
    Winsize.x = g_windowWidth; Winsize.y = 1.0f; 
    Rect WindowRectUp(Winpos, Winsize, Winveldir, Winvel, Wincol); 

    for (int i = 0; i < g_numShapes; i++) 
    { 
     // move the shape 
     g_shapeList[i]->move(); 

     // if it bounces to the window walls, invert its veldir 
     if (g_shapeList[i]->intersects(&WindowRectLeft) || 
      g_shapeList[i]->intersects(&WindowRectRight)) 
      g_shapeList[i]->invert_xdir(); 

     if (g_shapeList[i]->intersects(&WindowRectBottom) || 
      g_shapeList[i]->intersects(&WindowRectUp)) 
      g_shapeList[i]->invert_ydir(); 
    } 
} 
//------------------------------------ 
void ChangeSize(GLsizei w, GLsizei h) 
{ 
    if(h == 0) 
     h = 1; 

    glViewport(0, 0, w, h); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 

    g_windowHeight = h; 
    g_windowWidth = w; 

    glOrtho(0, g_windowWidth, 0, g_windowHeight , 1.0f, -1.0f); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
} 
//------------------------------------ 
void processNormalKeys(unsigned char key, int x, int y) 
{ 

    if (key == 'q') // PRESS 'q' to terminate the application 
     exit(0); 
    if(key=='r') // PRESS 'r' ket to reset the shapes 
     Initialize(); 
    if (key == 's') // toggle between showing the intersections or not 
     g_bShowIntersection = g_bShowIntersection ? false: true; 


} 
//------------------------------------ 
void processSpecialKeys(int key, int x, int y) 
{ 

    switch(key) { 
     case GLUT_KEY_LEFT :     
      break; 
     case GLUT_KEY_RIGHT :  
      break; 
     case GLUT_KEY_UP: 
      // PRESSING UP ARROW KEY INCREASES THE SHAPE VELOCITIES 
      for (int i = 0; i < g_numShapes; i++) 
       g_shapeList[i]->increase_vel(); 
      break; 
     case GLUT_KEY_DOWN: 
      // PRESSING DOWN ARROW KEY DECREASES THE SHAPE VELOCITIES 
      for (int i = 0; i < g_numShapes; i++) 
       g_shapeList[i]->decrease_vel(); 

      break; 
    } 

} 

//------------------------------------- 
void display() { 


    glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer 

    glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

    UpdateData(); 
    MarkObjects(g_bShowIntersection); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    for (int i= 0; i<g_numShapes; i++) 
     g_shapeList[i]->draw(); 


    glutSwapBuffers(); 
} 
//------------------------------------ 
int main(int argc, char* argv[]) 
{ 

    glutInit(&argc, argv);   // Initialize GLUT 
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); 
    glutInitWindowPosition(100,100); 
    glutInitWindowSize(WINDOWX, WINDOWY); 



    glutCreateWindow("COM102B - PA4"); 


    // Register callback handler for window re-paint 
    glutDisplayFunc(display);  
    glutReshapeFunc(ChangeSize); 
    glutIdleFunc(display); 
    glutKeyboardFunc(processNormalKeys); 
    glutSpecialFunc(processSpecialKeys); 

    Initialize(); 


    glutMainLoop();     // Enter infinitely event-processing loop 

    return 0; 
} 
+0

Les formes se déplacent dans la fenêtre et vous voulez savoir quand elles se chevauchent? Si c'est le cas, vous devez suivre la zone dans laquelle se trouve la forme, puis comparer si cette zone est occupée par une autre forme. Vous pouvez définir une "grille" dans la fenêtre et calculer où est chaque forme si deux ou plusieurs formes occupent la même coordonnée de grille, eh bien, elles se croisent. Eh bien, c'est comme ça que j'attaquerais le problème ... –

Répondre

0

Votre problème est dans ces lignes:

Rect *p1 = dynamic_cast<Rect*>(pshape); 
Circ *p2 = dynamic_cast<Circ*>(pshape); 

Sauf si vous aviez hérité Rect de Circ ou vice versa c'est ce qui fait planter votre programme, vous ne pouvez pas lancer votre pShape à Circ si c'est un Re ct, donc quand vous passez un objet Rect à votre fonction, il sera correctement converti en Rect * mais il échouera avec Circ * retournant nullptr, alors quand vous essayez d'accéder aux méthodes de p2, il tombera parce que vous accédez à une mémoire invalide (0x00000000):

if(p1) 
     { 
      float circleDistance_x = abs(p2->getPos().x - p1->getPos().x); 
      float circleDistance_y = abs(p2->getPos().y - p1->getPos().y); 

      if(circleDistance_x > (p1->getSize().x/2 + p2->getRad())) 
       return false; 
      if(circleDistance_y > (p1->getSize().y/2 + p2->getRad())) 
       return false; 
      if(circleDistance_x <= (p1->getSize().x/2)) 
       return true; 
      if(circleDistance_y <= (p1->getSize().y/2)) 
       return true; 
      float cornerDistance_sq = (circleDistance_x - (p1->getSize().x/2)) + (circleDistance_y - (p1->getSize().y/2))*(circleDistance_y - (p1->getSize().y/2)); 

      return (cornerDistance_sq <= p2->getRad()^2); 

     } 

Ainsi, vous pourriez tout simplement jeté le premier pointeur p1 car la méthode est de cercle, il est évident qu'il a été appelé à partir d'un objet Circ donc il n'y a pas besoin de pointer p2.

Rect *p1 = dynamic_cast<Rect*>(pshape); 
    if(p1) 
     { 
      float circleDistance_x = abs(getPos().x - p1->getPos().x); 
      float circleDistance_y = abs(getPos().y - p1->getPos().y); 

      if(circleDistance_x > (p1->getSize().x/2 + getRad())) 
       return false; 
      if(circleDistance_y > (p1->getSize().y/2 + getRad())) 
       return false; 
      if(circleDistance_x <= (p1->getSize().x/2)) 
       return true; 
      if(circleDistance_y <= (p1->getSize().y/2)) 
       return true; 
      float cornerDistance_sq = (circleDistance_x - (p1->getSize().x/2)) + (circleDistance_y - (p1->getSize().y/2))*(circleDistance_y - (p1->getSize().y/2)); 

      return (cornerDistance_sq <= getRad()^2); 

     } 

également sur la ligne:

return (cornerDistance_sq <= getRad()^2) 

je pense que vous essayez d'obtenir ce qu'il est en train de faire est

(cornerDistance_sq <= getRad())^2 

becouse < la place du rayon mais coutume de le faire, = a une plus grande priorité à ^, plus^n'est pas un opérateur carré, c'est un opérateur au niveau du bit. Donc, ce que vous voulez réellement est:

return cornerDistance_sq <= getRad() * getRad();