Power System Platform  2026w34a-beta
Loading...
Searching...
No Matches
Shunt.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 "Shunt.h"
19
20Shunt::Shunt() : PowerElement() {}
21Shunt::~Shunt() {}
22void Shunt::UpdateSwitchesPosition()
23{
24 if (m_parentList[0]) {
25 m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
26 }
27 else {
28 m_pointList[1] = m_pointList[0];
29 }
31}
32
33void Shunt::Move(wxPoint2DDouble position)
34{
35 SetPosition(m_movePos + position - m_moveStartPt);
36 for (int i = 2; i < (int)m_pointList.size(); i++) {
37 m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
38 }
39 if (!m_parentList[0]) {
40 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
41 }
42 UpdateSwitchesPosition();
43 UpdatePowerFlowArrowsPosition();
44}
45
46void Shunt::AlignToGrid(double gridSize)
47{
48 if (gridSize <= 0.0)
49 gridSize = 20.0;
50
51 // 1. Align m_position to the grid.
52 wxPoint2DDouble oldPosition = m_position;
53
54 wxPoint2DDouble newPosition(
55 std::round(oldPosition.m_x / gridSize) * gridSize,
56 std::round(oldPosition.m_y / gridSize) * gridSize);
57
58 wxPoint2DDouble delta = newPosition - oldPosition;
59
60 m_position = newPosition;
61 SetPosition(m_position);
62
63 // 2. Move the shunt geometry together with m_position.
64 // Point 0 = bus connection.
65 // Point 1 = switch.
66 // Point 2+ = shunt geometry.
67 //
68 // Point 0 is not moved here because it must be aligned with the bus in the next step.
69 for (size_t i = 2; i < m_pointList.size(); ++i) {
70 m_pointList[i] += delta;
71 }
72
73 // 3. Align the bus connection point (m_pointList[0]) with the reference point (m_pointList[2]).
74 //
75 // The alignment is completely independent of m_angle.
76 // m_pointList[2] determines the position along the bus.
77 if (!m_parentList.empty() &&
78 m_parentList[0] &&
79 m_pointList.size() >= 3) {
80
81 Element* bus = m_parentList[0];
82 wxPoint2DDouble p2 = m_pointList[2];
83
84 // Transform p2 to the local coordinate system of the bus.
85 wxPoint2DDouble p2Delta(p2.m_x - bus->GetPosition().m_x, p2.m_y - bus->GetPosition().m_y);
86 wxPoint2DDouble p2Local = bus->RotateLocal(p2Delta, -bus->GetAngle());
87
88 // The new connection point is located at the same longitudinal position as p2 and exactly on the center line of the bus.
89 wxPoint2DDouble candidateLocal(p2Local.m_x, 0.0);
90
91 // The candidate must remain within the length of the bus.
92 double halfWidth = bus->GetWidth() / 2.0 + 2.0;
93
94 if (std::abs(candidateLocal.m_x) <= halfWidth) {
95
96 // Transform the candidate back to global coordinates.
97 wxPoint2DDouble candidate = bus->GetPosition() + bus->RotateLocal(candidateLocal, bus->GetAngle());
98 m_pointList[0] = candidate;
99 }
100 }
101 else if (!m_pointList.empty()) {
102
103 // No parent: simply snap the connection point to the grid.
104 m_pointList[0].m_x = std::round(m_pointList[0].m_x / gridSize) * gridSize;
105 m_pointList[0].m_y = std::round(m_pointList[0].m_y / gridSize) * gridSize;
106 }
107
108 // 4. Update dependent geometry.
109 UpdateSwitchesPosition();
110 UpdatePowerFlowArrowsPosition();
111}
112
113void Shunt::MoveNode(Element* element, wxPoint2DDouble position)
114{
115 if (element) {
116 if (element == m_parentList[0]) {
117 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
118 }
119 }
120 else {
121 if (m_activeNodeID == 1) {
122 m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
123 if (m_parentList[0]) {
124 m_parentList[0]->RemoveChild(this);
125 m_parentList[0] = nullptr;
126 m_online = false;
127 }
128 }
129 }
130
131 // Recalculate switches positions
132 UpdateSwitchesPosition();
133 UpdatePowerFlowArrowsPosition();
134}
135
136void Shunt::StartMove(wxPoint2DDouble position)
137{
138 m_moveStartPt = position;
139 m_movePts = m_pointList;
140 m_movePos = m_position;
141}
142
144{
145 if (parent == m_parentList[0]) {
146 m_parentList[0] = nullptr;
147 m_online = false;
148 UpdateSwitchesPosition();
149 UpdatePowerFlowArrowsPosition();
150 }
151}
152
153bool Shunt::NodeContains(wxPoint2DDouble position)
154{
155 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
156 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
157
158 if (nodeRect.Contains(position)) {
159 m_activeNodeID = 1;
160 return true;
161 }
162
163 m_activeNodeID = 0;
164 return false;
165}
166
168{
169 if (parent && m_activeNodeID != 0) {
170 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
171 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
172
173 if (parent->Intersects(nodeRect)) {
174 m_parentList[0] = parent;
175
176 // Centralize the node on bus.
177 wxPoint2DDouble parentPt =
178 parent->RotateAtPosition(m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
179 parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
180 parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
181 m_pointList[0] = parentPt;
182
183 UpdateSwitchesPosition();
184 UpdatePowerFlowArrowsPosition();
185 return true;
186 }
187 else {
188 m_parentList[0] = nullptr;
189 m_online = false;
190 }
191 }
192 return false;
193}
194
196{
197 if (m_parentList[0]) {
198 wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
199 10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
200
201 if (!m_parentList[0]->Intersects(nodeRect)) {
202 m_parentList[0]->RemoveChild(this);
203 m_parentList[0] = nullptr;
204 m_online = false;
205 UpdateSwitchesPosition();
206 UpdatePowerFlowArrowsPosition();
207 }
208 }
209}
210
211void Shunt::RotateNode(Element* parent, bool clockwise)
212{
213 double rotAngle = m_rotationAngle;
214 if (!clockwise) rotAngle = -m_rotationAngle;
215
216 if (parent == m_parentList[0]) {
217 m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
218 UpdateSwitchesPosition();
219 UpdatePowerFlowArrowsPosition();
220 }
221}
222
223//void Shunt::DrawGround(wxPoint2DDouble position) const
224//{
225// std::vector<wxPoint2DDouble> groundPts;
226// groundPts.push_back(position);
227// groundPts.push_back(position + wxPoint2DDouble(0, 10));
228// groundPts.push_back(position + wxPoint2DDouble(-10, 10));
229// groundPts.push_back(position + wxPoint2DDouble(10, 10));
230// groundPts.push_back(position + wxPoint2DDouble(-6, 15));
231// groundPts.push_back(position + wxPoint2DDouble(6, 15));
232// groundPts.push_back(position + wxPoint2DDouble(-3, 20));
233// groundPts.push_back(position + wxPoint2DDouble(3, 20));
234//
235// DrawLine(groundPts, GL_LINES);
236//}
237
238void Shunt::DrawDCGround(wxPoint2DDouble position, wxGraphicsContext* gc) const
239{
240 std::vector<wxPoint2DDouble> groundPts;
241 groundPts.push_back(position);
242 groundPts.push_back(position + wxPoint2DDouble(0, 10));
243 groundPts.push_back(position + wxPoint2DDouble(-10, 10));
244 groundPts.push_back(position + wxPoint2DDouble(10, 10));
245 groundPts.push_back(position + wxPoint2DDouble(-6, 15));
246 groundPts.push_back(position + wxPoint2DDouble(6, 15));
247 groundPts.push_back(position + wxPoint2DDouble(-3, 20));
248 groundPts.push_back(position + wxPoint2DDouble(3, 20));
249
250 gc->StrokeLines(2, &groundPts[0]);
251 gc->StrokeLines(2, &groundPts[2]);
252 gc->StrokeLines(2, &groundPts[4]);
253 gc->StrokeLines(2, &groundPts[6]);
254}
255
256void Shunt::DrawDCGround(wxPoint2DDouble position, wxDC& dc) const
257{
258 wxPoint groundPts[8];
259 wxPoint2DDouble p;
260
261 p = position;
262 groundPts[0] = RotateAround(p, m_position, m_angle);
263 p = position + wxPoint2DDouble(0, 10);
264 groundPts[1] = RotateAround(p, m_position, m_angle);
265 p = position + wxPoint2DDouble(-10, 10);
266 groundPts[2] = RotateAround(p, m_position, m_angle);
267 p = position + wxPoint2DDouble(10, 10);
268 groundPts[3] = RotateAround(p, m_position, m_angle);
269 p = position + wxPoint2DDouble(-6, 15);
270 groundPts[4] = RotateAround(p, m_position, m_angle);
271 p = position + wxPoint2DDouble(6, 15);
272 groundPts[5] = RotateAround(p, m_position, m_angle);
273 p = position + wxPoint2DDouble(-3, 20);
274 groundPts[6] = RotateAround(p, m_position, m_angle);
275 p = position + wxPoint2DDouble(3, 20);
276 groundPts[7] = RotateAround(p, m_position, m_angle);
277
278 dc.DrawLines(2, &groundPts[0]);
279 dc.DrawLines(2, &groundPts[2]);
280 dc.DrawLines(2, &groundPts[4]);
281 dc.DrawLines(2, &groundPts[6]);
282}
283
284void Shunt::UpdatePowerFlowArrowsPosition()
285{
286 std::vector<wxPoint2DDouble> edges;
287 switch (m_pfDirection) {
289 m_powerFlowArrow.clear();
290 } break;
292 edges.push_back(m_pointList[2]);
293 edges.push_back(m_pointList[1]);
294 } break;
296 edges.push_back(m_pointList[1]);
297 edges.push_back(m_pointList[2]);
298 } break;
299 default:
300 break;
301 }
303}
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:115
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element's rect intersects other rect.
double GetWidth() const
Get the element width.
Definition Element.h:209
wxPoint2DDouble GetPosition() const
Get the element position.
Definition Element.h:189
double GetAngle() const
Get the element angle.
Definition Element.h:214
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition Element.cpp:33
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition Element.cpp:298
Abstract class of power elements.
virtual void CalculatePowerFlowPts(std::vector< wxPoint2DDouble > edges)
Calculate the points of the power flow arrows.
virtual void UpdateSwitches()
Update the switch position.
virtual wxPoint2DDouble GetSwitchPoint(Element *parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const
Get the correct switch position.
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition Shunt.cpp:113
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition Shunt.cpp:136
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition Shunt.cpp:143
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition Shunt.cpp:211
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition Shunt.cpp:33
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...
Definition Shunt.cpp:167
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition Shunt.cpp:195
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement.
Definition Shunt.cpp:153
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element's rect intersects other rect.
Definition Shunt.h:38