20#include "DegreesAndRadians.h"
26 m_busColour.Set(0, 78, 255, 255);
27 m_onlineElementColour.Set(51, 51, 51, 255);
28 m_offlineElementColour.Set(128, 128, 128, 255);
29 m_closedSwitchColour.Set(0, 102, 0, 255);
30 m_openedSwitchColour.Set(255, 26, 26, 255);
31 m_powerFlowArrowColour.Set(255, 130, 0, 255);
32 m_dynamicEventColour.Set(255, 130, 0, 255);
41 double swLineSize = 20.0;
43 double dist = std::sqrt(
44 (secondPoint.m_x - parentPoint.m_x) *
45 (secondPoint.m_x - parentPoint.m_x) +
46 (secondPoint.m_y - parentPoint.m_y) *
47 (secondPoint.m_y - parentPoint.m_y));
49 if (dist > 0.0 && dist < swLineSize) {
50 swLineSize = dist / 2.0;
56 double rad = wxDegToRad(-angle);
57 double c = std::cos(rad);
58 double s = std::sin(rad);
60 double dx = secondPoint.m_x - parentPoint.m_x;
61 double dy = secondPoint.m_y - parentPoint.m_y;
63 double localX = c * dx - s * dy;
64 double localY = s * dx + c * dy;
75 wxPoint2DDouble swPoint(parentPoint.m_x, parentPoint.m_y - swLineSize);
77 double backRad = wxDegToRad(angle);
78 double bc = std::cos(backRad);
79 double bs = std::sin(backRad);
81 wxPoint2DDouble pt(bc * (swPoint.m_x - parentPoint.m_x) - bs * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_x,
82 bs * (swPoint.m_x - parentPoint.m_x) + bc * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_y);
84 if (std::abs(pt.m_x - std::round(pt.m_x)) < 1e-4)
85 pt.m_x = std::round(pt.m_x);
87 if (std::abs(pt.m_y - std::round(pt.m_y)) < 1e-4)
88 pt.m_y = std::round(pt.m_y);
95 for (
int i = 0; i < (int)m_switchRect.size(); i++) {
96 if (m_parentList[i]) {
97 if (m_switchRect[i].
Contains(position))
return true;
106 wxPoint2DDouble swCenter = wxPoint2DDouble((m_pointList[0].m_x + m_pointList[1].m_x) / 2.0,
107 (m_pointList[0].m_y + m_pointList[1].m_y) / 2.0);
108 m_switchRect[0] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0, m_switchSize,
142 gc->SetPen(*wxTRANSPARENT_PEN);
145 for (
auto parent : m_parentList) {
148 gc->SetBrush(wxBrush(guiColour->swClose));
151 gc->SetBrush(wxBrush(guiColour->swOpen));
155 gc->Translate(m_switchRect[i].
GetPosition().m_x + m_switchSize / 2.0,
156 m_switchRect[i].GetPosition().m_y + m_switchSize / 2.0);
157 gc->Rotate(wxDegToRad(parent->GetAngle()));
158 gc->Translate(-m_switchRect[i].
GetPosition().m_x - m_switchSize / 2.0,
159 -m_switchRect[i].GetPosition().m_y - m_switchSize / 2.0);
161 wxPoint2DDouble switchPos = m_switchRect[i].GetPosition();
162 gc->DrawRectangle(switchPos.m_x, switchPos.m_y, m_switchSize, m_switchSize);
172 dc.SetPen(*wxTRANSPARENT_PEN);
175 for (
auto parent : m_parentList) {
178 dc.SetBrush(wxBrush(guiColour->swClose));
181 dc.SetBrush(wxBrush(guiColour->swOpen));
185 m_switchSize, m_switchSize, parent->GetAngle(), dc);
193 double arrowRate = 100.0;
195 if (edges.size() < 2)
return;
198 for (
int i = 0; i < (int)m_powerFlowArrow.size(); i++) m_powerFlowArrow[i].clear();
199 m_powerFlowArrow.clear();
201 for (
int i = 1; i < (int)edges.size(); i++) {
202 wxPoint2DDouble pt1 = edges[i - 1];
203 wxPoint2DDouble pt2 = edges[i];
205 double angle = std::atan2(pt2.m_y - pt1.m_y, pt2.m_x - pt1.m_x);
207 wxPoint2DDouble rotPt2(
208 std::cos(-angle) * (pt2.m_x - pt1.m_x) - std::sin(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_x,
209 std::sin(-angle) * (pt2.m_x - pt1.m_x) + std::cos(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_y);
211 int numArrows = std::abs(pt1.m_x - rotPt2.m_x) / arrowRate;
212 if (numArrows == 0) numArrows = 1;
214 for (
int i = 0; i < numArrows; i++) {
215 wxPoint2DDouble arrowCenter(pt1.m_x + ((rotPt2.m_x - pt1.m_x) /
double(numArrows + 1)) *
double(i + 1),
216 pt1.m_y + ((rotPt2.m_y - pt1.m_y) /
double(numArrows + 1)) *
double(i + 1));
218 std::vector<wxPoint2DDouble> triPts;
219 triPts.push_back(arrowCenter + wxPoint2DDouble(5.0, 0.0));
220 triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, 5.0));
221 triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, -5.0));
224 for (
int i = 0; i < 3; i++) {
225 triPts[i] = wxPoint2DDouble(
226 std::cos(angle) * (triPts[i].m_x - pt1.m_x) - std::sin(angle) * (triPts[i].m_y - pt1.m_y) + pt1.m_x,
227 std::sin(angle) * (triPts[i].m_x - pt1.m_x) + std::cos(angle) * (triPts[i].m_y - pt1.m_y) +
230 m_powerFlowArrow.push_back(triPts);
245 gc->SetPen(*wxTRANSPARENT_PEN);
247 gc->SetBrush(wxBrush(guiColour->pfArrow));
248 for (
auto arrow : m_powerFlowArrow) {
DrawDCTriangle(arrow, gc); }
254 dc.SetPen(*wxTRANSPARENT_PEN);
256 dc.SetBrush(wxBrush(guiColour->pfArrow));
257 for (
auto arrow : m_powerFlowArrow) {
258 std::vector<wxPoint> arrowPts;
259 for (
auto& pt : arrow) {
260 arrowPts.emplace_back(
static_cast<int>(pt.m_x),
static_cast<int>(pt.m_y));
267double PowerElement::GetValueFromUnit(
double value, ElectricalUnit valueUnit)
const
270 case ElectricalUnit::UNIT_kV:
271 case ElectricalUnit::UNIT_kA:
272 case ElectricalUnit::UNIT_kW:
273 case ElectricalUnit::UNIT_kVA:
274 case ElectricalUnit::UNIT_kvar: {
277 case ElectricalUnit::UNIT_MW:
278 case ElectricalUnit::UNIT_MVA:
279 case ElectricalUnit::UNIT_Mvar: {
288bool PowerElement::OpenCADProperties(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
290 auto cadPropNode = elementNode->first_node(
"CADProperties");
291 if (!cadPropNode)
return false;
293 auto position = cadPropNode->first_node(
"Position");
294 double posX = XMLParser::GetNodeValueDouble(position,
"X");
295 double posY = XMLParser::GetNodeValueDouble(position,
"Y");
296 auto size = cadPropNode->first_node(
"Size");
297 m_width = XMLParser::GetNodeValueDouble(size,
"Width");
298 m_height = XMLParser::GetNodeValueDouble(size,
"Height");
299 double angle = XMLParser::GetNodeValueDouble(cadPropNode,
"Angle");
302 auto nodePosition = cadPropNode->first_node(
"NodePosition");
303 double nodePosX = XMLParser::GetNodeValueDouble(nodePosition,
"X");
304 double nodePosY = XMLParser::GetNodeValueDouble(nodePosition,
"Y");
306 int parentID = XMLParser::GetNodeValueInt(cadPropNode,
"ParentID");
309 if (parentID == -1) {
310 m_parentList.push_back(
nullptr);
311 m_pointList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
312 m_pointList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
313 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
314 m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
316 wxRect2DDouble genRect(0, 0, 0, 0);
317 m_switchRect.push_back(genRect);
323 AddParent(parentList[parentID], wxPoint2DDouble(nodePosX, nodePosY),
true);
328 Move(wxPoint2DDouble(posX, posY));
331 int numRot = angle / m_rotationAngle;
332 bool clockwise =
true;
334 numRot = std::abs(numRot);
337 for (
int i = 0; i < numRot; i++)
Rotate(clockwise);
342void PowerElement::SaveCADProperties(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementNode)
344 auto cadProp = XMLParser::AppendNode(doc, elementNode,
"CADProperties");
345 auto position = XMLParser::AppendNode(doc, cadProp,
"Position");
346 auto posX = XMLParser::AppendNode(doc, position,
"X");
347 XMLParser::SetNodeValue(doc, posX, m_position.m_x);
348 auto posY = XMLParser::AppendNode(doc, position,
"Y");
349 XMLParser::SetNodeValue(doc, posY, m_position.m_y);
350 auto size = XMLParser::AppendNode(doc, cadProp,
"Size");
351 auto width = XMLParser::AppendNode(doc, size,
"Width");
352 XMLParser::SetNodeValue(doc, width, m_width);
353 auto height = XMLParser::AppendNode(doc, size,
"Height");
354 XMLParser::SetNodeValue(doc, height, m_height);
355 auto angle = XMLParser::AppendNode(doc, cadProp,
"Angle");
356 XMLParser::SetNodeValue(doc, angle, m_angle);
357 auto nodePos = XMLParser::AppendNode(doc, cadProp,
"NodePosition");
358 auto nodePosX = XMLParser::AppendNode(doc, nodePos,
"X");
359 XMLParser::SetNodeValue(doc, nodePosX, m_pointList[0].m_x);
360 auto nodePosY = XMLParser::AppendNode(doc, nodePos,
"Y");
361 XMLParser::SetNodeValue(doc, nodePosY, m_pointList[0].m_y);
362 auto parentID = XMLParser::AppendNode(doc, cadProp,
"ParentID");
363 Element* parent = m_parentList[0];
364 if (parent) XMLParser::SetNodeValue(doc, parentID, parent->
GetID());
367void PowerElement::SaveSwitchingData(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* electricalNode)
369 auto switchingList = XMLParser::AppendNode(doc, electricalNode,
"SwitchingList");
370 for (
int i = 0; i < static_cast<int>(m_swData.
swType.size()); i++) {
371 auto switching = XMLParser::AppendNode(doc, switchingList,
"Switching");
372 XMLParser::SetNodeAttribute(doc, switching,
"ID", i);
373 auto swType = XMLParser::AppendNode(doc, switching,
"Type");
374 XMLParser::SetNodeValue(doc, swType,
static_cast<int>(m_swData.
swType[i]));
375 auto swTime = XMLParser::AppendNode(doc, switching,
"Time");
376 XMLParser::SetNodeValue(doc, swTime, m_swData.
swTime[i]);
380bool PowerElement::OpenSwitchingData(rapidxml::xml_node<>* electricalNode)
382 auto switchingList = electricalNode->first_node(
"SwitchingList");
383 if (!switchingList)
return false;
384 auto swNode = switchingList->first_node(
"Switching");
387 m_swData.
swTime.push_back(XMLParser::GetNodeValueDouble(swNode,
"Time"));
388 swNode = swNode->next_sibling(
"Switching");
SwitchingType
Type of switching.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
virtual int GetID() const
Get the element ID.
wxPoint2DDouble GetPosition() const
Get the element position.
double GetAngle() const
Get the element angle.
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 DrawDCRectangle(wxPoint2DDouble position, double width, double height, double angle, wxDC &dc) const
Draw a circle.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
virtual void DrawDCTriangle(std::vector< wxPoint2DDouble > points, wxGraphicsContext *gc) const
Draw rectangle.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
virtual bool Contains(wxPoint2DDouble position) const =0
Checks if the element contains a position.
virtual void Rotate(bool clockwise=true)
Rotate the element.
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
PowerElement()
Constructor.
virtual void CalculatePowerFlowPts(std::vector< wxPoint2DDouble > edges)
Calculate the points of the power flow arrows.
virtual bool SwitchesContains(wxPoint2DDouble position) const
Check if switch contains position.
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.
std::vector< double > swTime
std::vector< SwitchingType > swType