#include "Element.h" Element::Element() {} Element::~Element() {} void Element::SetPosition(const wxPoint2DDouble position) { m_position = position; m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0 - m_borderSize, m_position.m_y - m_height / 2.0 - m_borderSize, m_width + 2.0 * m_borderSize, m_height + 2.0 * m_borderSize); } void Element::DrawCircle(wxPoint2DDouble position, double radius, int numSegments, GLenum mode) const { glBegin(mode); for(int i = 0; i < numSegments; i++) { double theta = 2.0 * 3.1415926 * double(i) / double(numSegments); glVertex2f(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y); } glEnd(); } void Element::DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode) const { glBegin(mode); // TODO: GL_QUADS é obsoleto (OpenGL 3.0+), encontrar outra solução. glVertex2d(position.m_x - width / 2.0, position.m_y - height / 2.0); glVertex2d(position.m_x - width / 2.0, position.m_y + height / 2.0); glVertex2d(position.m_x + width / 2.0, position.m_y + height / 2.0); glVertex2d(position.m_x + width / 2.0, position.m_y - height / 2.0); glEnd(); } void Element::DrawRectangle(wxPoint2DDouble* points, GLenum mode) const { glBegin(mode); // TODO: GL_QUADS é obsoleto (OpenGL 3.0+), encontrar outra solução. glVertex2d(points[0].m_x, points[0].m_y); glVertex2d(points[1].m_x, points[1].m_y); glVertex2d(points[2].m_x, points[2].m_y); glVertex2d(points[3].m_x, points[3].m_y); glEnd(); } void Element::DrawLine(std::vector points, GLenum mode) const { glBegin(mode); for(auto it = points.begin(); it != points.end(); ++it) { glVertex2d((*it).m_x, (*it).m_y); } glEnd(); } void Element::DrawPickbox(wxPoint2DDouble position) const { glLineWidth(1.0); glColor4d(1.0, 1.0, 1.0, 0.8); DrawRectangle(position, 8.0, 8.0); glColor4d(0.0, 0.0, 0.0, 1.0); DrawRectangle(position, 8.0, 8.0, GL_LINE_LOOP); } wxPoint2DDouble Element::RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees) const { double radAngle = angle; if(degrees) radAngle = wxDegToRad(angle); return wxPoint2DDouble(std::cos(radAngle) * (pointToRotate.m_x - m_position.m_x) - std::sin(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_x, std::sin(radAngle) * (pointToRotate.m_x - m_position.m_x) + std::cos(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_y); } void Element::StartMove(wxPoint2DDouble position) { this->m_moveStartPt = position; this->m_movePos = m_position; } void Element::Move(wxPoint2DDouble position) { SetPosition(m_movePos + position - m_moveStartPt); } wxPoint2DDouble Element::GetSwitchPoint(Element* parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const { double swLineSize = 25.0; wxPoint2DDouble swPoint = wxPoint2DDouble(parentPoint.m_x, parentPoint.m_y - swLineSize); // Rotate the second point (to compare). double angle = parent->GetAngle(); secondPoint = wxPoint2DDouble(std::cos(wxDegToRad(-angle)) * (secondPoint.m_x - parentPoint.m_x) - std::sin(wxDegToRad(-angle)) * (secondPoint.m_y - parentPoint.m_y) + parentPoint.m_x, std::sin(wxDegToRad(-angle)) * (secondPoint.m_x - parentPoint.m_x) + std::cos(wxDegToRad(-angle)) * (secondPoint.m_y - parentPoint.m_y) + parentPoint.m_y); // Rotate if(secondPoint.m_y > parentPoint.m_y) angle -= 180.0; return wxPoint2DDouble(std::cos(wxDegToRad(angle)) * (swPoint.m_x - parentPoint.m_x) - std::sin(wxDegToRad(angle)) * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_x, std::sin(wxDegToRad(angle)) * (swPoint.m_x - parentPoint.m_x) + std::cos(wxDegToRad(angle)) * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_y); } wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX, double offsetY) const { return wxPoint2DDouble(m_position.m_x + offsetX + translation.m_x, m_position.m_y + offsetY + translation.m_y) * scale; } wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble position, wxPoint2DDouble translation, double scale, double offsetX, double offsetY) const { return wxPoint2DDouble(position.m_x + offsetX + translation.m_x, position.m_y + offsetY + translation.m_y) * scale; } void Element::DrawPoint(wxPoint2DDouble position, double size) const { glPointSize(size); glBegin(GL_POINTS); glVertex2d(position.m_x, position.m_y); glEnd(); } bool Element::RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const { wxPoint2DDouble rect1Corners[4] = {rect1.GetLeftTop(), rect1.GetLeftBottom(), rect1.GetRightBottom(), rect1.GetRightTop()}; wxPoint2DDouble rect2Corners[4] = {rect2.GetLeftTop(), rect2.GetLeftBottom(), rect2.GetRightBottom(), rect2.GetRightTop()}; wxPoint2DDouble rect1Center(rect1.m_x + rect1.m_width / 2.0, rect1.m_y + rect1.m_height / 2.0); wxPoint2DDouble rect2Center(rect2.m_x + rect2.m_width / 2.0, rect2.m_y + rect2.m_height / 2.0); // Rotate the corners. double radAngle1 = wxDegToRad(angle1); double radAngle2 = wxDegToRad(angle2); for(int i = 0; i < 4; i++) { rect1Corners[i] = wxPoint2DDouble(std::cos(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) - std::sin(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_x, std::sin(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) + std::cos(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_y); rect2Corners[i] = wxPoint2DDouble(std::cos(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) - std::sin(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_x, std::sin(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) + std::cos(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_y); } //[Ref] http://www.gamedev.net/page/resources/_/technical/game-programming/2d-rotated-rectangle-collision-r2604 // Find the rectangles axis to project wxPoint2DDouble axis[4] = {rect1Corners[3] - rect1Corners[0], rect1Corners[3] - rect1Corners[2], rect2Corners[3] - rect2Corners[0], rect2Corners[3] - rect2Corners[2]}; // Calculate the projected points to each axis wxPoint2DDouble rect1ProjPts[4][4]; // [axis][corner] wxPoint2DDouble rect2ProjPts[4][4]; // [axis][corner] for(int i = 0; i < 4; i++) { double den = axis[i].m_x * axis[i].m_x + axis[i].m_y * axis[i].m_y; for(int j = 0; j < 4; j++) { double m_rectProj = (rect1Corners[j].m_x * axis[i].m_x + rect1Corners[j].m_y * axis[i].m_y) / den; double rectProj = (rect2Corners[j].m_x * axis[i].m_x + rect2Corners[j].m_y * axis[i].m_y) / den; rect1ProjPts[i][j] = wxPoint2DDouble(m_rectProj * axis[i].m_x, m_rectProj * axis[i].m_y); rect2ProjPts[i][j] = wxPoint2DDouble(rectProj * axis[i].m_x, rectProj * axis[i].m_y); } } // Calculate the scalar value to identify the max and min values on projections double rect1Scalar[4][4]; //[axis][corner] double rect2Scalar[4][4]; //[axis][corner] for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { rect1Scalar[i][j] = rect1ProjPts[i][j].m_x * axis[i].m_x + rect1ProjPts[i][j].m_y * axis[i].m_y; rect2Scalar[i][j] = rect2ProjPts[i][j].m_x * axis[i].m_x + rect2ProjPts[i][j].m_y * axis[i].m_y; } } // Identify the max and min scalar values double rect1Min[4]; double rect1Max[4]; double rect2Min[4]; double rect2Max[4]; for(int i = 0; i < 4; i++) { rect1Max[i] = rect1Scalar[i][0]; rect2Max[i] = rect2Scalar[i][0]; rect1Min[i] = rect1Scalar[i][0]; rect2Min[i] = rect2Scalar[i][0]; for(int j = 1; j < 4; j++) { if(rect1Max[i] < rect1Scalar[i][j]) rect1Max[i] = rect1Scalar[i][j]; if(rect2Max[i] < rect2Scalar[i][j]) rect2Max[i] = rect2Scalar[i][j]; if(rect1Min[i] > rect1Scalar[i][j]) rect1Min[i] = rect1Scalar[i][j]; if(rect2Min[i] > rect2Scalar[i][j]) rect2Min[i] = rect2Scalar[i][j]; } } // Check if any segment don't overlap for(int i = 0; i < 4; i++) { if(!(rect2Min[i] <= rect1Max[i] && rect2Max[i] >= rect1Min[i])) return false; } return true; }