如何为任何形状编写交叉函数

时间:2017-05-17 18:42:16

标签: c++ freeglut

我必须编写一个函数,它检测交集并返回true或false。

我有Shape.cpp文件,而rectangle.cpp,circle.cpp文件继承了它。我试着计算它,但我失败了。没有错误,但是当我的程序启动时,它会崩溃。我的问题是它崩溃的原因?我的方式是错的吗?这是circle.cpp文件。

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;
}

这不是我想写的代码。但是当它失败时,我就停下来写了。

和我的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

最后是我的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;
}

1 个答案:

答案 0 :(得分:0)

你的问题在于以下几点:

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

除非你从Circ继承了Rect,反之亦然,这是导致程序崩溃的原因,如果它是一个Rect,你就不能将你的pShape转换为Circ,所以当你将一个Rect对象传递给你的函数时,它将会正确转换为Rect *但它将失败并且Circ *返回nullptr,所以当你尝试从p2访问方法时它会崩溃因为你正在访问无效内存(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);

        }

所以,你可以简单地抛出第一个p1指针,因为该方法来自圆圈,很明显它是从Circ对象调用的,所以不需要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);

        }

同样在线:

return (cornerDistance_sq <= getRad()^2)

我认为你正试图获得半径方形,但这不会做,它实际上在做什么

(cornerDistance_sq <= getRad()) ^ 2 

becouse&lt; =具有更高的^优先级,加上^不是方运算符,它是一个按位运算符。所以你真正想要的是:

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