diff options
Diffstat (limited to 'Project/Element.cpp')
-rw-r--r-- | Project/Element.cpp | 347 |
1 files changed, 339 insertions, 8 deletions
diff --git a/Project/Element.cpp b/Project/Element.cpp index 7f0e211..8ced79b 100644 --- a/Project/Element.cpp +++ b/Project/Element.cpp @@ -14,9 +14,35 @@ void Element::DrawCircle(wxPoint2DDouble position, double radius, int numSegment { 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); - } + 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::DrawArc(wxPoint2DDouble position, + double radius, + double initAngle, + double finalAngle, + int numSegments, + GLenum mode) const +{ + double initAngRad = wxDegToRad(initAngle); + double finalAngRad = wxDegToRad(finalAngle); + glBegin(mode); + for(int i = 0; i <= numSegments; i++) { + double theta = initAngRad + (finalAngRad - initAngRad) * double(i) / double(numSegments); + glVertex2f(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y); + } + glEnd(); +} + +void Element::DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode) const +{ + glBegin(mode); + for(int i = 0; i < 3; i++) { + glVertex2d(points[i].m_x, points[i].m_y); + } glEnd(); } @@ -44,8 +70,8 @@ void Element::DrawLine(std::vector<wxPoint2DDouble> points, GLenum mode) const { glBegin(mode); for(auto it = points.begin(); it != points.end(); ++it) { - glVertex2d((*it).m_x, (*it).m_y); - } + glVertex2d((*it).m_x, (*it).m_y); + } glEnd(); } @@ -103,8 +129,313 @@ wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble translation, double scale scale; } -wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble position, wxPoint2DDouble translation, double scale, double offsetX, double offsetY) const +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; + 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; +} + +void Element::UpdateSwitches() +{ + // General method, to one switch only. + wxPoint2DDouble swCenter = wxPoint2DDouble((m_pointList[0].m_x + m_pointList[1].m_x) / 2.0, + (m_pointList[0].m_y + m_pointList[1].m_y) / 2.0); + m_switchRect[0] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0, m_switchSize, + m_switchSize); +} + +void Element::DrawSwitches() const +{ + int i = 0; + for(auto it = m_parentList.begin(); it != m_parentList.end(); it++) { + Element* parent = *it; + if(parent) { + if(m_online) { + glColor4d(0.0, 0.4, 0.0, 1.0); // green + } else { + glColor4d(1.0, 0.1, 0.1, 1.0); // red + } + + glPushMatrix(); + glTranslated(m_switchRect[i].GetPosition().m_x + m_switchSize / 2.0, + m_switchRect[i].GetPosition().m_y + m_switchSize / 2.0, 0.0); + glRotated(parent->GetAngle(), 0.0, 0.0, 1.0); + glTranslated(-m_switchRect[i].GetPosition().m_x - m_switchSize / 2.0, + -m_switchRect[i].GetPosition().m_y - m_switchSize / 2.0, 0.0); + + DrawRectangle(m_switchRect[i].GetPosition() + wxPoint2DDouble(m_switchSize / 2.0, m_switchSize / 2.0), + m_switchSize, m_switchSize); + + glPopMatrix(); + } + i++; + } +} + +bool Element::SwitchesContains(wxPoint2DDouble position) const +{ + for(int i = 0; i < (int)m_switchRect.size(); i++) { + if(m_parentList[i]) { + if(m_switchRect[i].Contains(position)) return true; + } + } + return false; +} + +void Element::SetOnline(bool online) +{ + // Check if any parent is null. + for(auto it = m_parentList.begin(); it != m_parentList.end(); it++) { + if(!(*it)) return; + } + m_online = online; +} + +void Element::GeneralMenuItens(wxMenu& menu) +{ + wxMenuItem* clockItem = new wxMenuItem(&menu, ID_ROTATE_CLOCK, _("Rotate clockwise")); + clockItem->SetBitmap(wxImage("data\\images\\menu\\rotateClock16.png")); + menu.Append(clockItem); + + wxMenuItem* counterClockItem = new wxMenuItem(&menu, ID_ROTATE_COUNTERCLOCK, _("Rotate counter-clockwise")); + counterClockItem->SetBitmap(wxImage("data\\images\\menu\\rotateCounterClock16.png")); + menu.Append(counterClockItem); + + wxMenuItem* deleteItem = new wxMenuItem(&menu, ID_DELETE, _("Delete")); + deleteItem->SetBitmap(wxImage("data\\images\\menu\\delete16.png")); + menu.Append(deleteItem); +} + +void Element::CalculateBoundaries(wxPoint2DDouble& leftUp, wxPoint2DDouble& rightBottom) const +{ + // Check rect corners boundaries. + + // Get rectangle corners + wxPoint2DDouble rectCorner[4] = {m_rect.GetLeftTop(), m_rect.GetLeftBottom(), m_rect.GetRightBottom(), + m_rect.GetRightTop()}; + // Rotate corners. + for(int i = 0; i < 4; ++i) { + rectCorner[i] = RotateAtPosition(rectCorner[i], m_angle); + } + leftUp = rectCorner[0]; + rightBottom = rectCorner[0]; + for(int i = 1; i < 4; ++i) { + if(rectCorner[i].m_x < leftUp.m_x) leftUp.m_x = rectCorner[i].m_x; + if(rectCorner[i].m_y < leftUp.m_y) leftUp.m_y = rectCorner[i].m_y; + if(rectCorner[i].m_x > rightBottom.m_x) rightBottom.m_x = rectCorner[i].m_x; + if(rectCorner[i].m_y > rightBottom.m_y) rightBottom.m_y = rectCorner[i].m_y; + } + + // Check points list boundaries. + for(int i = 0; i < (int)m_pointList.size(); i++) { + if(m_pointList[i].m_x < leftUp.m_x) leftUp.m_x = m_pointList[i].m_x; + if(m_pointList[i].m_y < leftUp.m_y) leftUp.m_y = m_pointList[i].m_y; + if(m_pointList[i].m_x > rightBottom.m_x) rightBottom.m_x = m_pointList[i].m_x; + if(m_pointList[i].m_y > rightBottom.m_y) rightBottom.m_y = m_pointList[i].m_y; + } +} + +bool Element::DoubleFromString(wxWindow* parent, wxString strValue, double& value, wxString errorMsg) +{ + double dValue = 0.0; + + if(!strValue.ToDouble(&dValue)) { + wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR); + msgDialog.ShowModal(); + return false; + } + + value = dValue; + return true; +} + +bool Element::IntFromString(wxWindow* parent, wxString strValue, int& value, wxString errorMsg) +{ + long int iValue = 0; + + if(!strValue.ToLong(&iValue)) { + wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR); + msgDialog.ShowModal(); + return false; + } + + value = iValue; + return true; +} + +wxString Element::StringFromDouble(double value, int minDecimal) +{ + wxString str = wxString::FromCDouble(value, 13); + int cutNumber = 0; + int numDecimal = 0; + bool foundCut = false; + for(int i = (int)str.length() - 1; i >= 0; i--) { + if(str[i] != '0' && !foundCut) { + cutNumber = i; + foundCut = true; + } + if(str[i] == '.') { + numDecimal = i; + break; + } + } + + wxString formatedStr = ""; + if(cutNumber - numDecimal > minDecimal) + formatedStr = wxString::FromDouble(value, cutNumber - numDecimal); + else + formatedStr = wxString::FromDouble(value, minDecimal); + + return formatedStr; +} + +void Element::CalculatePowerFlowPts(std::vector<wxPoint2DDouble> edges) +{ + double arrowRate = 100.0; // One arrow to each "arrowRate" distance in pixels. + + if(edges.size() < 2) return; + + // Clear all power flow points + for(int i = 0; i < (int)m_powerFlowArrow.size(); i++) m_powerFlowArrow[i].clear(); + m_powerFlowArrow.clear(); + + for(int i = 1; i < (int)edges.size(); i++) { + wxPoint2DDouble pt1 = edges[i - 1]; + wxPoint2DDouble pt2 = edges[i]; + + double angle = std::atan2(pt2.m_y - pt1.m_y, pt2.m_x - pt1.m_x); + + wxPoint2DDouble rotPt2( + std::cos(-angle) * (pt2.m_x - pt1.m_x) - std::sin(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_x, + std::sin(-angle) * (pt2.m_x - pt1.m_x) + std::cos(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_y); + + int numArrows = std::abs(pt1.m_x - rotPt2.m_x) / arrowRate; + if(numArrows == 0) numArrows = 1; + + for(int i = 0; i < numArrows; i++) { + wxPoint2DDouble arrowCenter(pt1.m_x + ((rotPt2.m_x - pt1.m_x) / double(numArrows + 1)) * double(i + 1), + pt1.m_y + ((rotPt2.m_y - pt1.m_y) / double(numArrows + 1)) * double(i + 1)); + + std::vector<wxPoint2DDouble> triPts; + triPts.push_back(arrowCenter + wxPoint2DDouble(5.0, 0.0)); + triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, 5.0)); + triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, -5.0)); + + // Rotate back. + for(int i = 0; i < 3; i++) { + triPts[i] = wxPoint2DDouble( + std::cos(angle) * (triPts[i].m_x - pt1.m_x) - std::sin(angle) * (triPts[i].m_y - pt1.m_y) + pt1.m_x, + std::sin(angle) * (triPts[i].m_x - pt1.m_x) + std::cos(angle) * (triPts[i].m_y - pt1.m_y) + + pt1.m_y); + } + m_powerFlowArrow.push_back(triPts); + } + } +} + +void Element::DrawPowerFlowPts() const +{ + glColor4d(1.0, 0.51, 0.0, 1.0); + for(int i = 0; i < (int)m_powerFlowArrow.size(); i++) { + DrawTriangle(m_powerFlowArrow[i]); + } } |