20#include "../controlElement/ControlElementContainer.h"
21#include "../controlElement/ControlElementSolver.h"
27 m_parentList.push_back(parent);
33 parentPt.m_x = std::round(parentPt.m_x / 20.0) * 20.0;
35 double halfLength = parent->
GetWidth() / 2.0;
36 double minX = parent->
GetPosition().m_x - halfLength;
37 double maxX = parent->
GetPosition().m_x + halfLength;
39 if (parentPt.m_x < minX)
42 if (parentPt.m_x > maxX)
53 bool busHorizontal = (std::abs(parent->
GetAngle() - 0.0) < 1.0 || std::abs(parent->
GetAngle() - 180.0) < 1.0);
58 m_position = parentPt + wxPoint2DDouble(0.0, -80.0);
63 m_position = parentPt + wxPoint2DDouble(0.0, 80.0);
70 m_position = parentPt + wxPoint2DDouble(-80.0, 0.0);
75 m_position = parentPt + wxPoint2DDouble(80.0, 0.0);
83 m_width = m_height = 50.0;
84 m_rect = wxRect2DDouble(m_position.m_x - 25.0, m_position.m_y - 25.0, m_width, m_height);
89 m_pointList.push_back(parentPt);
92 wxPoint2DDouble term1 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
93 wxPoint2DDouble term2 = m_position + RotateLocal(wxPoint2DDouble(20.0, 0.0), m_angle);
95 term1.m_x = std::round(term1.m_x);
96 term1.m_y = std::round(term1.m_y);
98 term2.m_x = std::round(term2.m_x);
99 term2.m_y = std::round(term2.m_y);
105 m_pointList.push_back(term1);
106 m_pointList.push_back(term2);
110 wxRect2DDouble genRect(0, 0, 0, 0);
111 m_switchRect.push_back(genRect);
114 UpdatePowerFlowArrowsPosition();
124 wxColour elementColour;
129 elementColour = guiColour->enabled;
132 elementColour = guiColour->disable;
137 gc->SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
138 gc->SetBrush(*wxTRANSPARENT_BRUSH);
139 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
141 gc->SetPen(*wxTRANSPARENT_PEN);
142 gc->SetBrush(wxBrush(guiColour->selection));
143 DrawDCCircle(m_position, 25.0 + (m_borderSize + 1.5) / scale, 20, gc);
146 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc);
151 gc->SetPen(*wxTRANSPARENT_PEN);
152 gc->SetBrush(wxBrush(elementColour));
155 gc->SetPen(wxPen(wxColour(elementColour), 2));
156 gc->SetBrush(*wxTRANSPARENT_BRUSH);
157 gc->StrokeLines(m_pointList.size(), &m_pointList[0]);
163 gc->SetPen(*wxTRANSPARENT_PEN);
164 gc->SetBrush(wxBrush(guiColour->background));
167 gc->SetPen(wxPen(elementColour, 2));
168 gc->SetBrush(*wxTRANSPARENT_BRUSH);
175 DrawStabilityEventGC(gc, translation, scale, guiColour);
182 wxColour elementColour;
185 elementColour = guiColour->eventElement;
187 elementColour = guiColour->enabled;
190 elementColour = guiColour->disable;
192 std::vector<wxPoint> pointListInt;
193 for (
auto& pt : m_pointList) {
194 pointListInt.emplace_back(
static_cast<int>(pt.m_x),
static_cast<int>(pt.m_y));
200 dc.SetPen(wxPen(guiColour->selection, 2 + m_borderSize * 2.0));
201 dc.SetBrush(*wxTRANSPARENT_BRUSH);
202 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
204 dc.SetPen(*wxTRANSPARENT_PEN);
205 dc.SetBrush(wxBrush(guiColour->selection));
206 DrawDCCircle(m_position, 20.0 + (m_borderSize + 1.5) / scale, dc);
209 DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, dc);
214 dc.SetPen(*wxTRANSPARENT_PEN);
215 dc.SetBrush(wxBrush(elementColour));
218 dc.SetPen(wxPen(wxColour(elementColour), 2));
219 dc.SetBrush(*wxTRANSPARENT_BRUSH);
220 dc.DrawLines(pointListInt.size(), &pointListInt[0]);
226 dc.SetPen(*wxTRANSPARENT_PEN);
227 dc.SetBrush(wxBrush(guiColour->background));
230 dc.SetPen(wxPen(elementColour, 2));
231 dc.SetBrush(*wxTRANSPARENT_BRUSH);
239void Machines::UpdateSwitchesPosition()
241 if (m_parentList[0]) {
242 m_pointList[1] =
GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
245 m_pointList[1] = m_pointList[0];
253 if (m_pointList.size() >= 4) {
254 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
255 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(20.0, 0.0), m_angle);
256 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
257 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
259 if (!m_parentList[0]) {
260 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
262 UpdateSwitchesPosition();
263 UpdatePowerFlowArrowsPosition();
269 if (element == m_parentList[0]) {
270 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
274 if (m_activeNodeID == 1) {
275 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
276 if (m_parentList[0]) {
277 m_parentList[0]->RemoveChild(
this);
278 m_parentList[0] =
nullptr;
285 UpdateSwitchesPosition();
286 UpdatePowerFlowArrowsPosition();
291 m_moveStartPt = position;
292 m_movePts = m_pointList;
293 m_movePos = m_position;
298 double rotAngle = m_rotationAngle;
299 if (!clockwise) rotAngle = -m_rotationAngle;
301 if (parent == m_parentList[0]) {
303 UpdateSwitchesPosition();
304 UpdatePowerFlowArrowsPosition();
310 if (parent == m_parentList[0]) {
311 m_parentList[0] =
nullptr;
313 UpdateSwitchesPosition();
314 UpdatePowerFlowArrowsPosition();
320 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
321 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
323 if (nodeRect.Contains(position)) {
334 if (parent && m_activeNodeID != 0) {
335 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
336 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
339 m_parentList[0] = parent;
342 wxPoint2DDouble parentPt =
346 m_pointList[0] = parentPt;
348 UpdateSwitchesPosition();
349 UpdatePowerFlowArrowsPosition();
353 m_parentList[0] =
nullptr;
362 if (m_parentList[0]) {
363 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
364 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
367 m_parentList[0]->RemoveChild(
this);
368 m_parentList[0] =
nullptr;
370 UpdateSwitchesPosition();
371 UpdatePowerFlowArrowsPosition();
378 double rotAngle = m_rotationAngle;
379 if (!clockwise) rotAngle = -m_rotationAngle;
382 while (m_angle >= 360.0) m_angle -= 360.0;
383 while (m_angle < 0.0) m_angle += 360.0;
385 if (std::abs(m_angle - 90.0) < 1e-4) m_angle = 90.0;
386 else if (std::abs(m_angle - 180.0) < 1e-4) m_angle = 180.0;
387 else if (std::abs(m_angle - 270.0) < 1e-4) m_angle = 270.0;
388 else if (std::abs(m_angle - 0.0) < 1e-4 || std::abs(m_angle - 360.0) < 1e-4) m_angle = 0.0;
390 if (m_pointList.size() >= 4) {
391 wxPoint2DDouble t1 = m_position + RotateLocal(wxPoint2DDouble(40.0, 0.0), m_angle);
392 wxPoint2DDouble t2 = m_position + RotateLocal(wxPoint2DDouble(20.0, 0.0), m_angle);
393 m_pointList[2] = wxPoint2DDouble(std::round(t1.m_x), std::round(t1.m_y));
394 m_pointList[3] = wxPoint2DDouble(std::round(t2.m_x), std::round(t2.m_y));
396 UpdateSwitchesPosition();
397 UpdatePowerFlowArrowsPosition();
400void Machines::AlignToGrid(
double gridSize)
408 wxPoint2DDouble oldPosition = m_position;
410 wxPoint2DDouble newPosition(
411 std::round(oldPosition.m_x / gridSize) * gridSize,
412 std::round(oldPosition.m_y / gridSize) * gridSize);
414 wxPoint2DDouble delta = newPosition - oldPosition;
416 m_position = newPosition;
433 for (
size_t i = 2; i < m_pointList.size(); ++i) {
434 m_pointList[i] += delta;
441 if (m_pointList.size() >= 4) {
445 wxPoint2DDouble(40.0, 0.0),
451 wxPoint2DDouble(20.0, 0.0),
454 m_pointList[2] = wxPoint2DDouble(
458 m_pointList[3] = wxPoint2DDouble(
471 if (!m_parentList.empty() &&
473 m_pointList.size() >= 3) {
475 Element* bus = m_parentList[0];
477 wxPoint2DDouble p2 = m_pointList[2];
480 wxPoint2DDouble p2Delta(
484 wxPoint2DDouble p2Local =
492 wxPoint2DDouble candidateLocal(
500 if (std::abs(candidateLocal.m_x) <= halfWidth) {
503 wxPoint2DDouble candidate =
509 m_pointList[0] = candidate;
512 else if (!m_pointList.empty()) {
517 m_pointList[0].m_x / gridSize) * gridSize;
521 m_pointList[0].m_y / gridSize) * gridSize;
527 UpdateSwitchesPosition();
528 UpdatePowerFlowArrowsPosition();
531void Machines::UpdatePowerFlowArrowsPosition()
533 std::vector<wxPoint2DDouble> edges;
534 switch (m_pfDirection) {
536 m_powerFlowArrow.clear();
539 edges.push_back(m_pointList[2]);
540 edges.push_back(m_pointList[1]);
543 edges.push_back(m_pointList[1]);
544 edges.push_back(m_pointList[2]);
555 m_pfDirection = pfDirection;
556 UpdatePowerFlowArrowsPosition();
PowerFlowDirection
Direction of power flow arrows.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element's rect intersects other rect.
double GetWidth() const
Get the element width.
wxPoint2DDouble GetPosition() const
Get the element position.
double GetAngle() const
Get the element angle.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
virtual void AddChild(Element *child)
Add a child to the child list.
virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext *gc) const
Draw a circle using device context.
virtual void RemoveParent(Element *parent)
Remove a parent.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement.
virtual void DrawDC(GUIColour *guiColour, wxPoint2DDouble translation, double scale, wxGraphicsContext *gc) const
Draw the element using GDI+.
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
virtual bool AddParent(Element *parent, wxPoint2DDouble position, bool isOpening=false)
Add a parent to the element. This method must be used on power elements that connect to a bus,...
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void Rotate(bool clockwise=true)
Rotate the element.
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Abstract class of power elements.
virtual void CalculatePowerFlowPts(std::vector< wxPoint2DDouble > edges)
Calculate the points of the power flow arrows.
virtual void DrawDCPowerFlowPts(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw power flow arrows.
virtual void UpdateSwitches()
Update the switch position.
virtual void DrawDCSwitches(GUIColour *guiColour, wxGraphicsContext *gc) const
Draw switch.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.