Power System Platform  2026w23a-beta
Loading...
Searching...
No Matches
Element.cpp
1/*
2 * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "Element.h"
19#ifdef USING_WX_3_0_X
20#include "../utils/DegreesAndRadians.h"
21#endif
22#include "../utils/Path.h"
23#include "../utils/PropertiesData.h"
24
25#include <wx/pen.h>
26#include <wx/brush.h>
27
29{
30 //m_selectionColour.Set(0, 128, 255, 128);
31}
32
33void Element::SetPosition(const wxPoint2DDouble position)
34{
35 m_position = position;
36 m_rect =
37 wxRect2DDouble(m_position.m_x - m_width / 2.0 - m_borderSize, m_position.m_y - m_height / 2.0 - m_borderSize,
38 m_width + 2.0 * m_borderSize, m_height + 2.0 * m_borderSize);
39}
40
41void Element::DrawDCRectangle(wxPoint2DDouble position, double width, double height, double angle, wxDC& dc) const
42{
43 if (angle == 0.0) {
44 wxPoint poly[4] = {
45 wxPoint((int)(position.m_x - width / 2.0), (int)(position.m_y - height / 2.0)),
46 wxPoint((int)(position.m_x + width / 2.0), (int)(position.m_y - height / 2.0)),
47 wxPoint((int)(position.m_x + width / 2.0), (int)(position.m_y + height / 2.0)),
48 wxPoint((int)(position.m_x - width / 2.0), (int)(position.m_y + height / 2.0))
49 };
50 dc.DrawPolygon(4, poly);
51 return;
52 }
53
54 double hw = width / 2.0;
55 double hh = height / 2.0;
56 double angleRad = wxDegToRad(angle);
57
58 // Retângulo centrado na origem
59 wxPoint2DDouble pts[4] = {
60 {-hw, -hh},
61 { hw, -hh},
62 { hw, hh},
63 {-hw, hh}
64 };
65
66 wxPoint poly[4];
67
68 for (int i = 0; i < 4; ++i)
69 {
70 double x = pts[i].m_x;
71 double y = pts[i].m_y;
72
73 // Rotação
74 double xr = x * cos(angleRad) - y * sin(angleRad);
75 double yr = x * sin(angleRad) + y * cos(angleRad);
76
77 // Translação para centro
78 poly[i].x = (int)(xr + position.m_x);
79 poly[i].y = (int)(yr + position.m_y);
80 }
81
82 dc.DrawPolygon(4, poly);
83
84}
85
86void Element::DrawDCRoundedRectRotated(wxDC& dc, const wxPoint2DDouble& center, double width, double height, double radius, double angleDeg, int arcSegments) const
87{
88 radius = std::min(radius, std::min(width, height) / 2.0);
89
90 double hw = width / 2.0;
91 double hh = height / 2.0;
92
93 double rad = wxDegToRad(angleDeg);
94 double c = std::cos(rad);
95 double s = std::sin(rad);
96
97 auto rotate = [&](double x, double y)
98 {
99 double xr = c * x - s * y + center.m_x;
100 double yr = s * x + c * y + center.m_y;
101 return wxPoint2DDouble(xr, yr);
102 };
103
104 auto drawArc = [&](double cx, double cy,
105 double startDeg)
106 {
107 wxPoint2DDouble arcCenterLocal(cx, cy);
108 wxPoint2DDouble arcCenter = rotate(arcCenterLocal.m_x,
109 arcCenterLocal.m_y);
110
111 double start = startDeg + angleDeg;
112 double end = start + 90.0;
113
114 dc.DrawEllipticArc(
115 wxRound(arcCenter.m_x - radius),
116 wxRound(arcCenter.m_y - radius),
117 wxRound(radius * 2),
118 wxRound(radius * 2),
119 start,
120 end
121 );
122 };
123
124 auto line = [&](double x1, double y1,
125 double x2, double y2,
126 wxPoint& p1, wxPoint& p2)
127 {
128 wxPoint2DDouble p1d = rotate(x1, y1);
129 wxPoint2DDouble p2d = rotate(x2, y2);
130 p1 = wxPoint(wxRound(p1d.m_x), wxRound(p1d.m_y));
131 p2 = wxPoint(wxRound(p2d.m_x), wxRound(p2d.m_y));
132
133 //dc.DrawLine(p1.x, p1.y, p2.x, p2.y);
134 };
135
136 wxPen pen = dc.GetPen();
137
138 wxPoint pts[4];
139 line(-hw + radius, -hh,
140 hw - radius, -hh,
141 pts[0], pts[1]);
142
143 line(hw - radius, hh,
144 -hw + radius, hh,
145 pts[2], pts[3]);
146
147 dc.SetPen(*wxTRANSPARENT_PEN);
148 dc.DrawPolygon(4, pts);
149 dc.SetPen(pen);
150 dc.DrawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
151 dc.DrawLine(pts[2].x, pts[2].y, pts[3].x, pts[3].y);
152
153 line(hw, -hh + radius,
154 hw, hh - radius,
155 pts[0], pts[1]);
156
157 line(-hw, hh - radius,
158 -hw, -hh + radius,
159 pts[2], pts[3]);
160
161 dc.SetPen(*wxTRANSPARENT_PEN);
162 dc.DrawPolygon(4, pts);
163 dc.SetPen(pen);
164 dc.DrawLine(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
165 dc.DrawLine(pts[2].x, pts[2].y, pts[3].x, pts[3].y);
166
167 drawArc(hw - radius, -hh + radius, 0 - angleDeg * 2);
168 drawArc(hw - radius, hh - radius, 270 - angleDeg * 2);
169 drawArc(-hw + radius, hh - radius, 180 - angleDeg * 2);
170 drawArc(-hw + radius, -hh + radius, 90 - angleDeg * 2);
171}
172
173void Element::DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext* gc) const
174{
175 wxPoint2DDouble* pts = new wxPoint2DDouble[numSegments + 1];
176 for (int i = 0; i < numSegments; i++) {
177 double theta = 2.0 * 3.1415926 * double(i) / double(numSegments);
178 pts[i] = wxPoint2DDouble(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y);
179 }
180 pts[numSegments] = pts[0];
181 gc->DrawLines(numSegments + 1, pts);
182 delete[] pts;
183}
184
185void Element::DrawDCCircle(wxPoint2DDouble position, double radius, wxDC& dc) const
186{
187 dc.DrawCircle(wxRound(position.m_x), wxRound(position.m_y), wxRound(radius));
188}
189
190void Element::DrawDCArc(wxPoint2DDouble position, double radius, double initAngle, double finalAngle, int numSegments, wxGraphicsContext* gc) const
191{
192 double initAngRad = wxDegToRad(initAngle);
193 double finalAngRad = wxDegToRad(finalAngle);
194 wxPoint2DDouble* points = new wxPoint2DDouble[numSegments + 2];
195 for (int i = 0; i <= numSegments; i++) {
196 double theta = initAngRad + (finalAngRad - initAngRad) * double(i) / double(numSegments);
197 points[i] = wxPoint2DDouble(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y);
198 }
199
200 gc->StrokeLines(numSegments + 1, points);
201 delete[] points;
202}
203
204void Element::DrawDCArc(wxPoint2DDouble position, double radius, double initAngle, double finalAngle, wxDC& dc) const
205{
206 dc.DrawEllipticArc(wxRound(position.m_x - radius), wxRound(position.m_y - radius), wxRound(2 * radius), wxRound(2 * radius), initAngle, finalAngle);
207}
208
209void Element::DrawDCTriangle(std::vector<wxPoint2DDouble> points, wxGraphicsContext* gc) const
210{
211 points.emplace_back(points[0]);
212 gc->DrawLines(4, &points[0]);
213}
214
215void Element::DrawDCTriangle(std::vector<wxPoint> points, wxDC& dc) const
216{
217 points.emplace_back(points[0]);
218 dc.DrawPolygon(4, &points[0]);
219}
220
221void Element::DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext* gc) const
222{
223 gc->SetPen(wxPen(wxColour(0, 0, 0, 255)));
224 gc->SetBrush(wxBrush(wxColour(255, 255, 255, 204)));
225 gc->DrawRectangle(position.m_x, position.m_y, 8, 8);
226}
227
228wxPoint2DDouble Element::RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees) const
229{
230 double radAngle = angle;
231 if (degrees) radAngle = wxDegToRad(angle);
232 return wxPoint2DDouble(std::cos(radAngle) * (pointToRotate.m_x - m_position.m_x) -
233 std::sin(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_x,
234 std::sin(radAngle) * (pointToRotate.m_x - m_position.m_x) +
235 std::cos(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_y);
236}
237
238wxPoint2DDouble Element::RotateLocal(wxPoint2DDouble local, double angleDeg) const
239{
240 double rad = wxDegToRad(angleDeg);
241 double c = std::cos(rad);
242 double s = std::sin(rad);
243
244 return wxPoint2DDouble(
245 c * local.m_x - s * local.m_y,
246 s * local.m_x + c * local.m_y
247 );
248}
249
250wxPoint Element::RotateAround(const wxPoint2DDouble& p, const wxPoint2DDouble& center, double angleDeg) const
251{
252 double rad = wxDegToRad(angleDeg);
253 double c = std::cos(rad);
254 double s = std::sin(rad);
255
256 double dx = p.m_x - center.m_x;
257 double dy = p.m_y - center.m_y;
258
259 double xr = c * dx - s * dy + center.m_x;
260 double yr = s * dx + c * dy + center.m_y;
261
262 return wxPoint(wxRound(xr), wxRound(yr));
263}
264
265void Element::StartMove(wxPoint2DDouble position)
266{
267 this->m_moveStartPt = position;
268 this->m_movePos = m_position;
269}
270
271void Element::Move(wxPoint2DDouble position) { SetPosition(m_movePos + position - m_moveStartPt); }
272wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX, double offsetY) const
273{
274 return wxPoint2DDouble(m_position.m_x + offsetX + translation.m_x, m_position.m_y + offsetY + translation.m_y) *
275 scale;
276}
277
278wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble position,
279 wxPoint2DDouble translation,
280 double scale,
281 double offsetX,
282 double offsetY) const
283{
284 return wxPoint2DDouble(position.m_x + offsetX + translation.m_x, position.m_y + offsetY + translation.m_y) * scale;
285}
286
287//void Element::DrawPoint(wxPoint2DDouble position, double size) const
288//{
289// glPointSize(size);
290// glBegin(GL_POINTS);
291// glVertex2d(position.m_x, position.m_y);
292// glEnd();
293//}
294
295bool Element::RotatedRectanglesIntersects(wxRect2DDouble rect1,
296 wxRect2DDouble rect2,
297 double angle1,
298 double angle2) const
299{
300 wxPoint2DDouble rect1Corners[4] = { rect1.GetLeftTop(), rect1.GetLeftBottom(), rect1.GetRightBottom(),
301 rect1.GetRightTop() };
302 wxPoint2DDouble rect2Corners[4] = { rect2.GetLeftTop(), rect2.GetLeftBottom(), rect2.GetRightBottom(),
303 rect2.GetRightTop() };
304 wxPoint2DDouble rect1Center(rect1.m_x + rect1.m_width / 2.0, rect1.m_y + rect1.m_height / 2.0);
305 wxPoint2DDouble rect2Center(rect2.m_x + rect2.m_width / 2.0, rect2.m_y + rect2.m_height / 2.0);
306
307 // Rotate the corners.
308 double radAngle1 = wxDegToRad(angle1);
309 double radAngle2 = wxDegToRad(angle2);
310
311 for (int i = 0; i < 4; i++) {
312 rect1Corners[i] =
313 wxPoint2DDouble(std::cos(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) -
314 std::sin(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_x,
315 std::sin(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) +
316 std::cos(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_y);
317
318 rect2Corners[i] =
319 wxPoint2DDouble(std::cos(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) -
320 std::sin(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_x,
321 std::sin(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) +
322 std::cos(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_y);
323 }
324
325 //[Ref] http://www.gamedev.net/page/resources/_/technical/game-programming/2d-rotated-rectangle-collision-r2604
326
327 // Find the rectangles axis to project
328 wxPoint2DDouble axis[4] = { rect1Corners[3] - rect1Corners[0], rect1Corners[3] - rect1Corners[2],
329 rect2Corners[3] - rect2Corners[0], rect2Corners[3] - rect2Corners[2] };
330
331 // Calculate the projected points to each axis
332 wxPoint2DDouble rect1ProjPts[4][4]; // [axis][corner]
333 wxPoint2DDouble rect2ProjPts[4][4]; // [axis][corner]
334 for (int i = 0; i < 4; i++) {
335 double den = axis[i].m_x * axis[i].m_x + axis[i].m_y * axis[i].m_y;
336 for (int j = 0; j < 4; j++) {
337 double m_rectProj = (rect1Corners[j].m_x * axis[i].m_x + rect1Corners[j].m_y * axis[i].m_y) / den;
338 double rectProj = (rect2Corners[j].m_x * axis[i].m_x + rect2Corners[j].m_y * axis[i].m_y) / den;
339
340 rect1ProjPts[i][j] = wxPoint2DDouble(m_rectProj * axis[i].m_x, m_rectProj * axis[i].m_y);
341 rect2ProjPts[i][j] = wxPoint2DDouble(rectProj * axis[i].m_x, rectProj * axis[i].m_y);
342 }
343 }
344
345 // Calculate the scalar value to identify the max and min values on projections
346 double rect1Scalar[4][4]; //[axis][corner]
347 double rect2Scalar[4][4]; //[axis][corner]
348 for (int i = 0; i < 4; i++) {
349 for (int j = 0; j < 4; j++) {
350 rect1Scalar[i][j] = rect1ProjPts[i][j].m_x * axis[i].m_x + rect1ProjPts[i][j].m_y * axis[i].m_y;
351 rect2Scalar[i][j] = rect2ProjPts[i][j].m_x * axis[i].m_x + rect2ProjPts[i][j].m_y * axis[i].m_y;
352 }
353 }
354 // Identify the max and min scalar values
355 double rect1Min[4];
356 double rect1Max[4];
357 double rect2Min[4];
358 double rect2Max[4];
359
360 for (int i = 0; i < 4; i++) {
361 rect1Max[i] = rect1Scalar[i][0];
362 rect2Max[i] = rect2Scalar[i][0];
363 rect1Min[i] = rect1Scalar[i][0];
364 rect2Min[i] = rect2Scalar[i][0];
365
366 for (int j = 1; j < 4; j++) {
367 if (rect1Max[i] < rect1Scalar[i][j]) rect1Max[i] = rect1Scalar[i][j];
368 if (rect2Max[i] < rect2Scalar[i][j]) rect2Max[i] = rect2Scalar[i][j];
369
370 if (rect1Min[i] > rect1Scalar[i][j]) rect1Min[i] = rect1Scalar[i][j];
371 if (rect2Min[i] > rect2Scalar[i][j]) rect2Min[i] = rect2Scalar[i][j];
372 }
373 }
374
375 // Check if any segment don't overlap
376 for (int i = 0; i < 4; i++) {
377 if (!(rect2Min[i] <= rect1Max[i] && rect2Max[i] >= rect1Min[i])) return false;
378 }
379
380 return true;
381}
382
383bool Element::SetOnline(bool online)
384{
385 // Check if any parent is null.
386 for (auto it = m_parentList.begin(); it != m_parentList.end(); it++) {
387 if (!(*it)) return false;
388 }
389 m_online = online;
390 return true;
391}
392
394{
395 wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
396 //wxString exePath = exeFileName.GetPath();
397
398 wxMenuItem* clockItem = new wxMenuItem(&menu, ID_ROTATE_CLOCK, _("Rotate clockwise"));
399 clockItem->SetBitmap(wxImage(Paths::GetDataPath() + "/images/menu/rotateClock16.png"));
400 menu.Append(clockItem);
401
402 wxMenuItem* counterClockItem = new wxMenuItem(&menu, ID_ROTATE_COUNTERCLOCK, _("Rotate counter-clockwise"));
403 counterClockItem->SetBitmap(wxImage(Paths::GetDataPath() + "/images/menu/rotateCounterClock16.png"));
404 menu.Append(counterClockItem);
405
406 wxMenuItem* deleteItem = new wxMenuItem(&menu, ID_DELETE, _("Delete"));
407 deleteItem->SetBitmap(wxImage(Paths::GetDataPath() + "/images/menu/delete16.png"));
408 menu.Append(deleteItem);
409}
410
411void Element::CalculateBoundaries(wxPoint2DDouble& leftUp, wxPoint2DDouble& rightBottom) const
412{
413 // Check rect corners boundaries.
414
415 // Get rectangle corners
416 wxPoint2DDouble rectCorner[4] = { m_rect.GetLeftTop(), m_rect.GetLeftBottom(), m_rect.GetRightBottom(),
417 m_rect.GetRightTop() };
418 // Rotate corners.
419 for (int i = 0; i < 4; ++i) { rectCorner[i] = RotateAtPosition(rectCorner[i], m_angle); }
420 leftUp = rectCorner[0];
421 rightBottom = rectCorner[0];
422 for (int i = 1; i < 4; ++i) {
423 if (rectCorner[i].m_x < leftUp.m_x) leftUp.m_x = rectCorner[i].m_x;
424 if (rectCorner[i].m_y < leftUp.m_y) leftUp.m_y = rectCorner[i].m_y;
425 if (rectCorner[i].m_x > rightBottom.m_x) rightBottom.m_x = rectCorner[i].m_x;
426 if (rectCorner[i].m_y > rightBottom.m_y) rightBottom.m_y = rectCorner[i].m_y;
427 }
428
429 // Check points list boundaries.
430 for (int i = 0; i < (int)m_pointList.size(); i++) {
431 if (m_pointList[i].m_x < leftUp.m_x) leftUp.m_x = m_pointList[i].m_x;
432 if (m_pointList[i].m_y < leftUp.m_y) leftUp.m_y = m_pointList[i].m_y;
433 if (m_pointList[i].m_x > rightBottom.m_x) rightBottom.m_x = m_pointList[i].m_x;
434 if (m_pointList[i].m_y > rightBottom.m_y) rightBottom.m_y = m_pointList[i].m_y;
435 }
436}
437
438bool Element::DoubleFromString(wxWindow* parent, wxString strValue, double& value, wxString errorMsg)
439{
440 double dValue = 0.0;
441
442 if (!strValue.ToDouble(&dValue)) {
443 wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
444 msgDialog.ShowModal();
445 return false;
446 }
447
448 value = dValue;
449 return true;
450}
451
452bool Element::IntFromString(wxWindow* parent, wxString strValue, int& value, wxString errorMsg)
453{
454 long int iValue = 0;
455
456 if (!strValue.ToLong(&iValue)) {
457 wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
458 msgDialog.ShowModal();
459 return false;
460 }
461
462 value = iValue;
463 return true;
464}
465
466wxString Element::StringFromDouble(double value, int minDecimal, int maxDecimals)
467{
468 wxString str = wxString::FromCDouble(value, maxDecimals);
469 int cutNumber = 0;
470 int numDecimal = 0;
471 bool foundCut = false;
472 for (int i = (int)str.length() - 1; i >= 0; i--) {
473 if (str[i] != '0' && !foundCut) {
474 cutNumber = i;
475 foundCut = true;
476 }
477 if (str[i] == '.') {
478 numDecimal = i;
479 break;
480 }
481 }
482
483 wxString formatedStr = "";
484 if (cutNumber - numDecimal > minDecimal)
485 formatedStr = wxString::FromDouble(value, cutNumber - numDecimal);
486 else
487 formatedStr = wxString::FromDouble(value, minDecimal);
488
489 return formatedStr;
490}
491
492void Element::ReplaceParent(Element* oldParent, Element* newParent)
493{
494 for (int i = 0; i < (int)m_parentList.size(); i++) {
495 if (m_parentList[i] == oldParent) m_parentList[i] = newParent;
496 }
497}
498
499void Element::AddChild(Element* child) { m_childList.push_back(child); }
501{
502 for (auto it = m_childList.begin(); it != m_childList.end();) {
503 if (*it == child) it = m_childList.erase(it);
504 else ++it;
505 }
506}
507
508void Element::ReplaceChild(Element* oldChild, Element* newChild)
509{
510 for (int i = 0; i < (int)m_childList.size(); i++) {
511 if (m_childList[i] == oldChild) m_childList[i] = newChild;
512 }
513}
514
515//void OpenGLColour::SetRGBA(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
516//{
517// rgba[0] = red;
518// rgba[1] = green;
519// rgba[2] = blue;
520// rgba[3] = alpha;
521//}
522//
523//wxColour OpenGLColour::GetDcRGBA() const
524//{
525// return wxColour(rgba[0] * 255, rgba[1] * 255, rgba[2] * 255, rgba[3] * 255);
526//}
527//
528//OpenGLColour::OpenGLColour() { SetRGBA(1.0, 1.0, 1.0, 1.0); }
529//OpenGLColour::OpenGLColour(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
530//{
531// SetRGBA(red, green, blue, alpha);
532//}
533
534double Element::PointToLineDistance(wxPoint2DDouble point, int* segmentNumber) const
535{
536 //[Ref] http://geomalgorithms.com/a02-_lines.html
537 double distance = 100.0; // Big initial distance.
538 wxPoint2DDouble p0 = point;
539
540 for (int i = 1; i < (int)m_pointList.size() - 2; i++) {
541 double d = 0.0;
542
543 wxPoint2DDouble p1 = m_pointList[i];
544 wxPoint2DDouble p2 = m_pointList[i + 1];
545
546 wxPoint2DDouble v = p2 - p1;
547 wxPoint2DDouble w = p0 - p1;
548
549 double c1 = w.m_x * v.m_x + w.m_y * v.m_y;
550 double c2 = v.m_x * v.m_x + v.m_y * v.m_y;
551
552 if (c1 <= 0.0) {
553 d = std::sqrt(std::pow(p0.m_y - p1.m_y, 2) + std::pow(p0.m_x - p1.m_x, 2));
554 }
555 else if (c2 <= c1) {
556 d = std::sqrt(std::pow(p0.m_y - p2.m_y, 2) + std::pow(p0.m_x - p2.m_x, 2));
557 }
558 else {
559 d = std::abs((p2.m_y - p1.m_y) * p0.m_x - (p2.m_x - p1.m_x) * p0.m_y + p2.m_x * p1.m_y - p2.m_y * p1.m_x) /
560 std::sqrt(std::pow(p2.m_y - p1.m_y, 2) + std::pow(p2.m_x - p1.m_x, 2));
561 }
562 if (d < distance) {
563 distance = d;
564 if (segmentNumber) *segmentNumber = i;
565 }
566 }
567
568 return distance;
569}
570
571void Element::SaveCADProperties(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementNode)
572{
573 auto cadProp = XMLParser::AppendNode(doc, elementNode, "CADProperties");
574 auto position = XMLParser::AppendNode(doc, cadProp, "Position");
575 auto posX = XMLParser::AppendNode(doc, position, "X");
576 XMLParser::SetNodeValue(doc, posX, m_position.m_x);
577 auto posY = XMLParser::AppendNode(doc, position, "Y");
578 XMLParser::SetNodeValue(doc, posY, m_position.m_y);
579 auto size = XMLParser::AppendNode(doc, cadProp, "Size");
580 auto width = XMLParser::AppendNode(doc, size, "Width");
581 XMLParser::SetNodeValue(doc, width, m_width);
582 auto height = XMLParser::AppendNode(doc, size, "Height");
583 XMLParser::SetNodeValue(doc, height, m_height);
584 auto angle = XMLParser::AppendNode(doc, cadProp, "Angle");
585 XMLParser::SetNodeValue(doc, angle, m_angle);
586}
587
588bool Element::OpenCADProperties(rapidxml::xml_node<>* elementNode)
589{
590 auto cadPropNode = elementNode->first_node("CADProperties");
591 if (!cadPropNode) return false;
592
593 auto position = cadPropNode->first_node("Position");
594 double posX = XMLParser::GetNodeValueDouble(position, "X");
595 double posY = XMLParser::GetNodeValueDouble(position, "Y");
596 auto size = cadPropNode->first_node("Size");
597 m_width = XMLParser::GetNodeValueDouble(size, "Width");
598 m_height = XMLParser::GetNodeValueDouble(size, "Height");
599 m_angle = XMLParser::GetNodeValueDouble(cadPropNode, "Angle");
600 SetPosition(wxPoint2DDouble(posX, posY));
601 return true;
602}
@ ID_DELETE
Definition Element.h:82
@ ID_ROTATE_CLOCK
Definition Element.h:80
@ ID_ROTATE_COUNTERCLOCK
Definition Element.h:81
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:114
virtual bool RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
Check if two roteted rectangles intersect.
Definition Element.cpp:295
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:393
static bool IntFromString(wxWindow *parent, wxString strValue, int &value, wxString errorMsg)
Convert a string to int. Show a error message if the conversion fail.
Definition Element.cpp:452
virtual double PointToLineDistance(wxPoint2DDouble point, int *segmentNumber=nullptr) const
Calculate the distance between a line (formed by point list) and a point.
Definition Element.cpp:534
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
Definition Element.cpp:411
virtual void RemoveChild(Element *child)
Remove a child from the list.
Definition Element.cpp:500
virtual void ReplaceParent(Element *oldParent, Element *newParent)
Replace a parent.
Definition Element.cpp:492
virtual void DrawDCRectangle(wxPoint2DDouble position, double width, double height, double angle, wxDC &dc) const
Draw a circle.
Definition Element.cpp:41
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition Element.cpp:265
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:33
virtual void DrawDCTriangle(std::vector< wxPoint2DDouble > points, wxGraphicsContext *gc) const
Draw rectangle.
Definition Element.cpp:209
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition Element.cpp:228
virtual void DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext *gc) const
Draw a point.
Definition Element.cpp:221
Element()
Constructor.
Definition Element.cpp:28
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition Element.cpp:271
virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
Convert the element position to screen position.
Definition Element.cpp:272
virtual void AddChild(Element *child)
Add a child to the child list.
Definition Element.cpp:499
static bool DoubleFromString(wxWindow *parent, wxString strValue, double &value, wxString errorMsg)
Get a double value from a string. Show a error message if the conversion fail.
Definition Element.cpp:438
static wxString StringFromDouble(double value, int minDecimal=1, int maxDecimals=13)
Convert a double value to string.
Definition Element.cpp:466
virtual void ReplaceChild(Element *oldChild, Element *newChild)
Replace a child from the list.
Definition Element.cpp:508
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:383
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
Definition Element.cpp:173