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