diff options
82 files changed, 1284 insertions, 320 deletions
diff --git a/Project/Bus.cpp b/Project/Bus.cpp index 5c8c190..d3465cc 100644 --- a/Project/Bus.cpp +++ b/Project/Bus.cpp @@ -101,6 +101,73 @@ void Bus::Draw(wxPoint2DDouble translation, double scale) const } } +void Bus::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + wxPoint2DDouble gcPosition = m_position - wxPoint2DDouble(m_width / 2.0, m_height / 2.0); + wxGraphicsMatrix identityMatrix = gc->GetTransform(); + identityMatrix.Set(); // Set to identity + + gc->SetPen(*wxTRANSPARENT_PEN); + + // Draw selection (layer 1) + if (m_selected) { + // If the object is selected, the matrix is reset to remove scale effects applied to it, thus keeping the + // edges with fixed sizes for all zoom levels. + gc->PushState(); + gc->SetTransform(identityMatrix); + // The matrix was reset, so we must use screen coordinates (WorldToScreen). + wxPoint2DDouble screenPt = WorldToScreen(translation, scale); + gc->Translate(screenPt.m_x, screenPt.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-screenPt.m_x, -screenPt.m_y); + + gc->SetBrush(wxBrush(m_selectionColour.GetDcRGBA())); + + wxPoint2DDouble pts[4] = { WorldToScreen(translation, scale, -(m_width / 2.0), -(m_height / 2.0)) - + wxPoint2DDouble(m_borderSize, m_borderSize), + WorldToScreen(translation, scale, -(m_width / 2.0), (m_height / 2.0)) - + wxPoint2DDouble(m_borderSize, -m_borderSize), + WorldToScreen(translation, scale, (m_width / 2.0), (m_height / 2.0)) - + wxPoint2DDouble(-m_borderSize, -m_borderSize), + WorldToScreen(translation, scale, (m_width / 2.0), -(m_height / 2.0)) - + wxPoint2DDouble(-m_borderSize, m_borderSize) }; + gc->DrawLines(4, pts); + gc->PopState(); + } + + gc->PushState(); + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + if (m_dynEvent) + gc->SetBrush(wxBrush(m_dynamicEventColour.GetDcRGBA())); + else + gc->SetBrush(wxBrush(m_busColour.GetDcRGBA())); + + gc->DrawRectangle(gcPosition.m_x, gcPosition.m_y, m_width, m_height); + + gc->PopState(); + + // Draw pickbox (layer 3) + if (m_showPickbox) { + gc->PushState(); + gc->SetTransform(identityMatrix); + + wxPoint2DDouble screenPt = WorldToScreen(translation, scale); + gc->Translate(screenPt.m_x, screenPt.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-screenPt.m_x, -screenPt.m_y); + + wxPoint2DDouble pbPosition[2] = { WorldToScreen(translation, scale, m_width / 2.0) - wxPoint2DDouble(4, 4), + WorldToScreen(translation, scale, -m_width / 2.0) - wxPoint2DDouble(4, 4)}; + DrawDCPickbox(pbPosition[0], gc); + DrawDCPickbox(pbPosition[1], gc); + + gc->PopState(); + } +} + bool Bus::Contains(wxPoint2DDouble position) const { wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle); diff --git a/Project/Bus.h b/Project/Bus.h index b01a315..0b4bb53 100644 --- a/Project/Bus.h +++ b/Project/Bus.h @@ -86,6 +86,7 @@ class Bus : public PowerElement virtual bool Contains(wxPoint2DDouble position) const; virtual bool Intersects(wxRect2DDouble rect) const; virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual void Rotate(bool clockwise = true); virtual wxCursor GetBestPickboxCursor() const; virtual void MovePickbox(wxPoint2DDouble position); @@ -93,7 +94,7 @@ class Bus : public PowerElement virtual bool GetContextMenu(wxMenu& menu); virtual wxString GetTipText() const; virtual BusElectricalData GetElectricalData() const { return m_electricalData; } - virtual void SetElectricalData(BusElectricalData electricalData) { m_electricalData = electricalData; } + virtual void SetElectricalData(const BusElectricalData& electricalData) { m_electricalData = electricalData; } virtual bool ShowForm(wxWindow* parent, Element* element); virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY); diff --git a/Project/BusForm.cpp b/Project/BusForm.cpp index 9f942f3..d97c235 100644 --- a/Project/BusForm.cpp +++ b/Project/BusForm.cpp @@ -33,7 +33,7 @@ BusForm::BusForm(wxWindow* parent, Bus* bus) : BusFormBase(parent) m_textCtrlName->SetValue(bus->GetElectricalData().name); m_textCtrlNomVoltage->SetValue(bus->StringFromDouble(bus->GetElectricalData().nominalVoltage)); - if(bus->GetElectricalData().nominalVoltageUnit == UNIT_V) + if(bus->GetElectricalData().nominalVoltageUnit == ElectricalUnit::UNIT_V) m_choiceNomVoltage->SetSelection(0); else m_choiceNomVoltage->SetSelection(1); @@ -45,29 +45,29 @@ BusForm::BusForm(wxWindow* parent, Bus* bus) : BusFormBase(parent) m_checkBoxFault->SetValue(bus->GetElectricalData().hasFault); switch(bus->GetElectricalData().faultType) { - case FAULT_THREEPHASE: { + case FaultData::FAULT_THREEPHASE: { m_choiceFaultType->SetSelection(0); } break; - case FAULT_2LINE: { + case FaultData::FAULT_2LINE: { m_choiceFaultType->SetSelection(1); } break; - case FAULT_2LINE_GROUND: { + case FaultData::FAULT_2LINE_GROUND: { m_choiceFaultType->SetSelection(2); } break; - case FAULT_LINE_GROUND: { + case FaultData::FAULT_LINE_GROUND: { m_choiceFaultType->SetSelection(3); } break; default: break; } switch(bus->GetElectricalData().faultLocation) { - case FAULT_LINE_A: { + case FaultData::FAULT_LINE_A: { m_choiceFaultPlace->SetSelection(0); } break; - case FAULT_LINE_B: { + case FaultData::FAULT_LINE_B: { m_choiceFaultPlace->SetSelection(1); } break; - case FAULT_LINE_C: { + case FaultData::FAULT_LINE_C: { m_choiceFaultPlace->SetSelection(2); } break; default: @@ -99,7 +99,7 @@ void BusForm::OnButtonOKClick(wxCommandEvent& event) if(!m_bus->DoubleFromString(m_parent, m_textCtrlNomVoltage->GetValue(), data.nominalVoltage, _("Value entered incorrectly in the field \"Rated voltage\"."))) return; - data.nominalVoltageUnit = m_choiceNomVoltage->GetSelection() == 0 ? UNIT_V : UNIT_kV; + data.nominalVoltageUnit = m_choiceNomVoltage->GetSelection() == 0 ? ElectricalUnit::UNIT_V : ElectricalUnit::UNIT_kV; data.isVoltageControlled = m_checkBoxCtrlVoltage->GetValue(); if(data.isVoltageControlled) { if(!m_bus->DoubleFromString(m_parent, m_textCtrlCtrlVoltage->GetValue(), data.controlledVoltage, @@ -112,28 +112,28 @@ void BusForm::OnButtonOKClick(wxCommandEvent& event) data.hasFault = m_checkBoxFault->GetValue(); switch(m_choiceFaultType->GetSelection()) { case 0: { - data.faultType = FAULT_THREEPHASE; + data.faultType = FaultData::FAULT_THREEPHASE; } break; case 1: { - data.faultType = FAULT_2LINE; + data.faultType = FaultData::FAULT_2LINE; } break; case 2: { - data.faultType = FAULT_2LINE_GROUND; + data.faultType = FaultData::FAULT_2LINE_GROUND; } break; case 3: { - data.faultType = FAULT_LINE_GROUND; + data.faultType = FaultData::FAULT_LINE_GROUND; } break; } switch(m_choiceFaultPlace->GetSelection()) { case 0: { - data.faultLocation = FAULT_LINE_A; + data.faultLocation = FaultData::FAULT_LINE_A; } break; case 1: { - data.faultLocation = FAULT_LINE_B; + data.faultLocation = FaultData::FAULT_LINE_B; } break; case 2: { - data.faultLocation = FAULT_LINE_C; + data.faultLocation = FaultData::FAULT_LINE_C; } break; } diff --git a/Project/Capacitor.cpp b/Project/Capacitor.cpp index 76dc3fd..f7ae32a 100644 --- a/Project/Capacitor.cpp +++ b/Project/Capacitor.cpp @@ -112,6 +112,80 @@ void Capacitor::Draw(wxPoint2DDouble translation, double scale) const } } +void Capacitor::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + } + else + elementColour = m_offlineElementColour; + + if (m_inserted) { + std::vector<wxPoint2DDouble> capPts; + capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0)); + capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0)); + capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0)); + capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0)); + + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + gc->DrawLines(2, &capPts[0]); + gc->DrawLines(2, &capPts[2]); + + DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), gc); + + gc->PopState(); + + // Draw node selection. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc); + } + // Draw Capacitor (layer 2). + // Draw node. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0, 10, gc); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + DrawDCSwitches(gc); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(2, &capPts[0]); + gc->DrawLines(2, &capPts[2]); + + DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), gc); + + gc->PopState(); + } +} + void Capacitor::Rotate(bool clockwise) { double rotAngle = m_rotationAngle; diff --git a/Project/Capacitor.h b/Project/Capacitor.h index 8cf1c64..c98070d 100644 --- a/Project/Capacitor.h +++ b/Project/Capacitor.h @@ -25,7 +25,7 @@ class ReactiveShuntElementForm; struct CapacitorElectricalData { wxString name; double reactivePower = 100.0; - ElectricalUnit reactivePowerUnit = UNIT_MVAr; + ElectricalUnit reactivePowerUnit = ElectricalUnit::UNIT_MVAr; }; /** @@ -45,6 +45,7 @@ class Capacitor : public Shunt virtual Element* GetCopy(); virtual bool AddParent(Element* parent, wxPoint2DDouble position); virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual bool Contains(wxPoint2DDouble position) const; virtual bool Intersects(wxRect2DDouble rect) const; virtual void Rotate(bool clockwise = true); diff --git a/Project/ConnectionLine.cpp b/Project/ConnectionLine.cpp index 80752da..1a858a4 100644 --- a/Project/ConnectionLine.cpp +++ b/Project/ConnectionLine.cpp @@ -166,7 +166,7 @@ void ConnectionLine::StartMove(wxPoint2DDouble position) wxPoint2DDouble ConnectionLine::GetMidPoint() const { return ((m_pointList[2] + m_pointList[3]) / 2.0); } bool ConnectionLine::SetParentLine(ConnectionLine* parent) { - if(m_nodeList[0]->GetNodeType() != Node::NODE_IN) return false; + if(m_nodeList[0]->GetNodeType() != Node::NodeType::NODE_IN) return false; if(!parent) return false; m_type = ELEMENT_LINE; diff --git a/Project/Constant.cpp b/Project/Constant.cpp index c81a0cf..40d6c2d 100644 --- a/Project/Constant.cpp +++ b/Project/Constant.cpp @@ -22,7 +22,7 @@ Constant::Constant(int id) : ControlElement(id) { SetValue(m_value); m_angle = 180.0; - Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeOut); diff --git a/Project/ControlEditor.cpp b/Project/ControlEditor.cpp index cdd172e..709fb25 100644 --- a/Project/ControlEditor.cpp +++ b/Project/ControlEditor.cpp @@ -131,10 +131,10 @@ void ControlElementButton::OnLeftClickUp(wxMouseEvent& event) event.Skip(); } -ControlEditor::ControlEditor(wxWindow* parent, int ioflags) : ControlEditorBase(parent) +ControlEditor::ControlEditor(wxWindow* parent, wxGLContext* sharedGLContext, int ioflags) : ControlEditorBase(parent) { BuildControlElementPanel(); - m_glContext = new wxGLContext(m_glCanvas); + m_glContext = new wxGLContext(m_glCanvas, sharedGLContext); m_glContext->SetCurrent(*m_glCanvas); m_camera = new Camera(); m_selectionRect = wxRect2DDouble(0, 0, 0, 0); diff --git a/Project/ControlEditor.h b/Project/ControlEditor.h index f77f350..2aed0e9 100644 --- a/Project/ControlEditor.h +++ b/Project/ControlEditor.h @@ -23,6 +23,7 @@ #include <wx/dcclient.h> #include <wx/dcscreen.h> #include <wx/graphics.h> +#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> @@ -119,7 +120,7 @@ class ControlEditor : public ControlEditorBase MODE_DRAG_PASTE }; - ControlEditor(wxWindow* parent, + ControlEditor(wxWindow* parent, wxGLContext* sharedGLContext, int ioflags = IOControl::IN_TERMINAL_VOLTAGE | IOControl::IN_VELOCITY | IOControl::OUT_FIELD_VOLTAGE | IOControl::OUT_MEC_POWER); virtual ~ControlEditor(); diff --git a/Project/ControlElement.cpp b/Project/ControlElement.cpp index 5e8a80d..2af9a6f 100644 --- a/Project/ControlElement.cpp +++ b/Project/ControlElement.cpp @@ -108,7 +108,7 @@ void ControlElement::DrawNodes() const for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) { Node* node = *it; DrawCircle(node->GetPosition(), node->GetRadius(), 10, GL_POLYGON); - if(node->GetNodeType() == Node::NODE_IN) { DrawTriangle(node->GetInTrianglePts()); } + if(node->GetNodeType() == Node::NodeType::NODE_IN) { DrawTriangle(node->GetInTrianglePts()); } } } @@ -167,7 +167,7 @@ void ControlElement::SaveControlNodes(rapidxml::xml_document<>& doc, rapidxml::x auto angle = XMLParser::AppendNode(doc, nodeN, "Angle"); XMLParser::SetNodeValue(doc, angle, node->GetAngle()); auto nodeType = XMLParser::AppendNode(doc, nodeN, "Type"); - XMLParser::SetNodeValue(doc, nodeType, node->GetNodeType()); + XMLParser::SetNodeValue(doc, nodeType, static_cast<int>(node->GetNodeType())); id++; } } diff --git a/Project/ControlElement.h b/Project/ControlElement.h index 51f8df3..30e7d90 100644 --- a/Project/ControlElement.h +++ b/Project/ControlElement.h @@ -30,9 +30,9 @@ class Node { public: - enum NodeType { NODE_IN = 0, NODE_OUT }; + enum class NodeType { NODE_IN = 0, NODE_OUT }; - Node(wxPoint2DDouble position = wxPoint2DDouble(0, 0), NodeType nodeType = NODE_IN, double borderSize = 0.0); + Node(wxPoint2DDouble position = wxPoint2DDouble(0, 0), NodeType nodeType = NodeType::NODE_IN, double borderSize = 0.0); ~Node(); wxRect2DDouble GetRect() const { return m_rect; } diff --git a/Project/ControlElementSolver.cpp b/Project/ControlElementSolver.cpp index 7849313..037da84 100644 --- a/Project/ControlElementSolver.cpp +++ b/Project/ControlElementSolver.cpp @@ -62,10 +62,10 @@ void ControlElementSolver::Initialize(wxWindow* parent, double timeStep, double haveInput = haveOutput = false; for(auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) { IOControl* io = *it; - if(io->GetType() == Node::NODE_OUT && !haveInput) { + if(io->GetType() == Node::NodeType::NODE_OUT && !haveInput) { m_inputControl = io; haveInput = true; - } else if(io->GetType() == Node::NODE_IN) { + } else if(io->GetType() == Node::NodeType::NODE_IN) { m_outputControl = io; haveOutput = true; } @@ -329,7 +329,7 @@ ConnectionLine* ControlElementSolver::SolveNextElement(ConnectionLine* currentLi auto nodeList = element->GetNodeList(); for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) { Node* node = *itN; - if(node->GetNodeType() == Node::NODE_OUT) outNode = node; + if(node->GetNodeType() == Node::NodeType::NODE_OUT) outNode = node; } if(!outNode) return NULL; diff --git a/Project/DataReport.cpp b/Project/DataReport.cpp index 1511079..49572b7 100644 --- a/Project/DataReport.cpp +++ b/Project/DataReport.cpp @@ -335,10 +335,10 @@ void DataReport::FillValues(GridSelection gridToFill) double basePower = m_workspace->GetProperties()->GetSimulationPropertiesData().basePower; switch(m_workspace->GetProperties()->GetSimulationPropertiesData().basePowerUnit) { - case UNIT_kVA: { + case ElectricalUnit::UNIT_kVA: { basePower *= 1e3; } break; - case UNIT_MVA: { + case ElectricalUnit::UNIT_MVA: { basePower *= 1e6; } break; default: @@ -485,7 +485,7 @@ void DataReport::FillValues(GridSelection gridToFill) auto data = bus->GetElectricalData(); double vb = std::abs(data.nominalVoltage); - if(data.nominalVoltageUnit == UNIT_kV) vb *= 1e3; + if(data.nominalVoltageUnit == ElectricalUnit::UNIT_kV) vb *= 1e3; double kVoltage = 1.0; if(m_gridPFBuses->GetCellValue(0, 2) == m_voltageChoices[1]) kVoltage = vb; @@ -523,7 +523,7 @@ void DataReport::FillValues(GridSelection gridToFill) auto data = line->GetPUElectricalData(basePower); double vb = data.nominalVoltage; - if(data.nominalVoltageUnit == UNIT_kV) vb *= 1e3; + if(data.nominalVoltageUnit == ElectricalUnit::UNIT_kV) vb *= 1e3; double zb = (vb * vb) / basePower; wxString busName1 = "-"; @@ -567,10 +567,10 @@ void DataReport::FillValues(GridSelection gridToFill) double vb = 0.0; if(data.baseVoltage == 0) { vb = data.primaryNominalVoltage; - if(data.primaryNominalVoltageUnit == UNIT_kV) vb *= 1e3; + if(data.primaryNominalVoltageUnit == ElectricalUnit::UNIT_kV) vb *= 1e3; } else { vb = data.secondaryNominalVoltage; - if(data.secondaryNominalVoltageUnit == UNIT_kV) vb *= 1e3; + if(data.secondaryNominalVoltageUnit == ElectricalUnit::UNIT_kV) vb *= 1e3; } double zb = (vb * vb) / basePower; diff --git a/Project/Divider.cpp b/Project/Divider.cpp index e723de3..1becac4 100644 --- a/Project/Divider.cpp +++ b/Project/Divider.cpp @@ -39,7 +39,7 @@ bool Divider::Solve(double* input, double timeStep) std::vector<double> inputVector; for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) { Node* node = *itN; - if(node->GetNodeType() != Node::NODE_OUT) { + if(node->GetNodeType() != Node::NodeType::NODE_OUT) { if(!node->IsConnected()) { inputVector.push_back(0.0); } else { diff --git a/Project/ElectricCalculation.cpp b/Project/ElectricCalculation.cpp index a2db413..24c92ba 100644 --- a/Project/ElectricCalculation.cpp +++ b/Project/ElectricCalculation.cpp @@ -352,9 +352,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl data.powerFlow[1] = v2 * std::conj(data.current[1]); if(data.powerFlow[0].real() > data.powerFlow[1].real()) - line->SetPowerFlowDirection(PF_BUS1_TO_BUS2); + line->SetPowerFlowDirection(PowerFlowDirection::PF_BUS1_TO_BUS2); else - line->SetPowerFlowDirection(PF_BUS2_TO_BUS1); + line->SetPowerFlowDirection(PowerFlowDirection::PF_BUS2_TO_BUS1); line->SetElectricalData(data); } @@ -389,9 +389,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl data.powerFlow[1] = v2 * std::conj(data.current[1]); if(data.powerFlow[0].real() > data.powerFlow[1].real()) - transformer->SetPowerFlowDirection(PF_BUS1_TO_BUS2); + transformer->SetPowerFlowDirection(PowerFlowDirection::PF_BUS1_TO_BUS2); else - transformer->SetPowerFlowDirection(PF_BUS2_TO_BUS1); + transformer->SetPowerFlowDirection(PowerFlowDirection::PF_BUS2_TO_BUS1); transformer->SetElectricaData(data); } @@ -405,13 +405,13 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl double reactivePower = data.qValue * systemPowerBase; switch(data.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { reactivePower /= systemPowerBase; } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { reactivePower /= 1e3; } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { reactivePower /= 1e6; } break; default: @@ -455,9 +455,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl loadPower += std::complex<double>(childData.activePower, childData.reactivePower); if(childData.activePower >= 0.0) - load->SetPowerFlowDirection(PF_TO_ELEMENT); + load->SetPowerFlowDirection(PowerFlowDirection::PF_TO_ELEMENT); else - load->SetPowerFlowDirection(PF_TO_BUS); + load->SetPowerFlowDirection(PowerFlowDirection::PF_TO_BUS); } } for(auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) { @@ -467,9 +467,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl loadPower += std::complex<double>(childData.activePower, childData.reactivePower); if(childData.activePower >= 0.0) - indMotor->SetPowerFlowDirection(PF_TO_ELEMENT); + indMotor->SetPowerFlowDirection(PowerFlowDirection::PF_TO_ELEMENT); else - indMotor->SetPowerFlowDirection(PF_TO_BUS); + indMotor->SetPowerFlowDirection(PowerFlowDirection::PF_TO_BUS); } } @@ -484,13 +484,13 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl (power[i].real() + loadPower.real()) * systemPowerBase / (double)(syncGeneratorsOnBus.size()); switch(childData.activePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { activePower /= systemPowerBase; } break; - case UNIT_kW: { + case ElectricalUnit::UNIT_kW: { activePower /= 1e3; } break; - case UNIT_MW: { + case ElectricalUnit::UNIT_MW: { activePower /= 1e6; } break; default: @@ -516,13 +516,13 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl reactivePower /= (double)(syncGeneratorsOnBus.size() + syncMotorsOnBus.size()); switch(childData.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { reactivePower /= systemPowerBase; } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { reactivePower /= 1e3; } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { reactivePower /= 1e6; } break; default: @@ -532,9 +532,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl } if(childData.activePower >= 0.0) - generator->SetPowerFlowDirection(PF_TO_BUS); + generator->SetPowerFlowDirection(PowerFlowDirection::PF_TO_BUS); else - generator->SetPowerFlowDirection(PF_TO_ELEMENT); + generator->SetPowerFlowDirection(PowerFlowDirection::PF_TO_ELEMENT); generator->SetElectricalData(childData); } @@ -585,13 +585,13 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl reactivePower *= systemPowerBase; switch(childData.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { reactivePower /= systemPowerBase; } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { reactivePower /= 1e3; } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { reactivePower /= 1e6; } break; default: @@ -601,9 +601,9 @@ void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<doubl } if(childData.activePower > 0.0) - syncMotor->SetPowerFlowDirection(PF_TO_ELEMENT); + syncMotor->SetPowerFlowDirection(PowerFlowDirection::PF_TO_ELEMENT); else - syncMotor->SetPowerFlowDirection(PF_TO_BUS); + syncMotor->SetPowerFlowDirection(PowerFlowDirection::PF_TO_BUS); syncMotor->SetElectricalData(childData); diff --git a/Project/Electromechanical.cpp b/Project/Electromechanical.cpp index 8d97d5b..307b2da 100644 --- a/Project/Electromechanical.cpp +++ b/Project/Electromechanical.cpp @@ -207,14 +207,14 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove machine (only connected machines) - if(swData.swType[i] == SW_REMOVE && generator->IsOnline()) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && generator->IsOnline()) { generator->SetOnline(false); int n = static_cast<Bus*>(generator->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] -= GetSyncMachineAdmittance(generator); } // Insert machine (only disconnected machines) - if(swData.swType[i] == SW_INSERT && !generator->IsOnline() && generator->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !generator->IsOnline() && generator->GetParentList().size() == 1) { if(generator->SetOnline(true)) { int n = static_cast<Bus*>(generator->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] += GetSyncMachineAdmittance(generator); @@ -231,7 +231,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove machine (only connected machines) - if(swData.swType[i] == SW_REMOVE && motor->IsOnline() && motor->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && motor->IsOnline() && motor->GetParentList().size() == 1) { auto data = motor->GetElectricalData(); motor->SetOnline(false); int n = static_cast<Bus*>(motor->GetParentList()[0])->GetElectricalData().number; @@ -239,7 +239,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert machine (only disconnected machines) - if(swData.swType[i] == SW_INSERT && !motor->IsOnline() && motor->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !motor->IsOnline() && motor->GetParentList().size() == 1) { auto data = motor->GetElectricalData(); if(motor->SetOnline(true)) { int n = static_cast<Bus*>(motor->GetParentList()[0])->GetElectricalData().number; @@ -257,7 +257,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove load (only connected loads) - if(swData.swType[i] == SW_REMOVE && load->IsOnline() && load->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && load->IsOnline() && load->GetParentList().size() == 1) { load->SetOnline(false); auto data = load->GetPUElectricalData(m_powerSystemBase); Bus* parentBus = static_cast<Bus*>(load->GetParentList()[0]); @@ -268,7 +268,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert load (only disconnected load) - if(swData.swType[i] == SW_INSERT && !load->IsOnline() && load->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !load->IsOnline() && load->GetParentList().size() == 1) { if(load->SetOnline(true)) { auto data = load->GetPUElectricalData(m_powerSystemBase); Bus* parentBus = static_cast<Bus*>(load->GetParentList()[0]); @@ -289,7 +289,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove line (only connected lines) - if(swData.swType[i] == SW_REMOVE && line->IsOnline()) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && line->IsOnline()) { line->SetOnline(false); auto data = line->GetElectricalData(); @@ -307,7 +307,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert line (only disconnected lines) - if(swData.swType[i] == SW_INSERT && !line->IsOnline() && line->GetParentList().size() == 2) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !line->IsOnline() && line->GetParentList().size() == 2) { if(line->SetOnline(true)) { auto data = line->GetElectricalData(); @@ -335,7 +335,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove transformer (only connected transformers) - if(swData.swType[i] == SW_REMOVE && transformer->IsOnline()) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && transformer->IsOnline()) { transformer->SetOnline(false); auto data = transformer->GetElectricalData(); @@ -364,7 +364,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert transformer (only disconnected transformers) - if(swData.swType[i] == SW_INSERT && !transformer->IsOnline() && + if(swData.swType[i] == SwitchingType::SW_INSERT && !transformer->IsOnline() && transformer->GetParentList().size() == 2) { if(transformer->SetOnline(true)) { auto data = transformer->GetElectricalData(); @@ -404,7 +404,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove capacitor (only connected capacitors) - if(swData.swType[i] == SW_REMOVE && capacitor->IsOnline()) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && capacitor->IsOnline()) { capacitor->SetOnline(false); auto data = capacitor->GetPUElectricalData(m_powerSystemBase); int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number; @@ -412,7 +412,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert capacitor (only disconnected capacitors) - if(swData.swType[i] == SW_INSERT && !capacitor->IsOnline() && capacitor->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !capacitor->IsOnline() && capacitor->GetParentList().size() == 1) { if(capacitor->SetOnline(true)) { auto data = capacitor->GetPUElectricalData(m_powerSystemBase); int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number; @@ -430,7 +430,7 @@ void Electromechanical::SetEvent(double currentTime) for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove inductor (only connected inductors) - if(swData.swType[i] == SW_REMOVE && inductor->IsOnline()) { + if(swData.swType[i] == SwitchingType::SW_REMOVE && inductor->IsOnline()) { inductor->SetOnline(false); auto data = inductor->GetPUElectricalData(m_powerSystemBase); int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number; @@ -438,7 +438,7 @@ void Electromechanical::SetEvent(double currentTime) } // Insert inductor (only disconnected inductors) - if(swData.swType[i] == SW_INSERT && !inductor->IsOnline() && inductor->GetParentList().size() == 1) { + if(swData.swType[i] == SwitchingType::SW_INSERT && !inductor->IsOnline() && inductor->GetParentList().size() == 1) { if(inductor->SetOnline(true)) { auto data = inductor->GetPUElectricalData(m_powerSystemBase); int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number; @@ -1816,7 +1816,7 @@ bool Electromechanical::CalculateIndMachinesTransientValues(IndMotor* motor) double p = dataPU.activePower; double v = std::abs(data.terminalVoltage); - //[Ref.] Induction Motor Static Models for Power Flow and Voltage Stability Studies + //[Ref.] Induction Motor Static Models for Power Flow and Voltage stability Studies // If the motor is offline, calculate the nominal slip to user-defined power input and 1.0 p.u. voltage if(!motor->IsOnline()) v = 1.0; double r1 = data.r1t; diff --git a/Project/Element.cpp b/Project/Element.cpp index 46aaa7d..a108957 100644 --- a/Project/Element.cpp +++ b/Project/Element.cpp @@ -19,6 +19,8 @@ #ifdef USING_WX_3_0_X #include "DegreesAndRadians.h" #endif +#include <wx/pen.h> +#include <wx/brush.h> Element::Element() { m_selectionColour.SetRGBA(0.0, 0.5, 1.0, 0.5); } Element::~Element() {} @@ -40,6 +42,18 @@ void Element::DrawCircle(wxPoint2DDouble position, double radius, int numSegment glEnd(); } +void Element::DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext* gc) const +{ + wxPoint2DDouble* pts = new wxPoint2DDouble[numSegments + 1]; + for (int i = 0; i < numSegments; i++) { + double theta = 2.0 * 3.1415926 * double(i) / double(numSegments); + pts[i] = wxPoint2DDouble(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y); + } + pts[numSegments] = pts[0]; + gc->DrawLines(numSegments + 1, pts); + delete[] pts; +} + void Element::DrawArc(wxPoint2DDouble position, double radius, double initAngle, @@ -57,6 +71,20 @@ void Element::DrawArc(wxPoint2DDouble position, glEnd(); } +void Element::DrawDCArc(wxPoint2DDouble position, double radius, double initAngle, double finalAngle, int numSegments, wxGraphicsContext* gc) const +{ + double initAngRad = wxDegToRad(initAngle); + double finalAngRad = wxDegToRad(finalAngle); + wxPoint2DDouble* points = new wxPoint2DDouble[numSegments + 2]; + for (int i = 0; i <= numSegments; i++) { + double theta = initAngRad + (finalAngRad - initAngRad) * double(i) / double(numSegments); + points[i] = wxPoint2DDouble(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y); + } + + gc->DrawLines(numSegments + 1, points); + delete[] points; +} + void Element::DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode) const { glBegin(mode); @@ -64,6 +92,12 @@ void Element::DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode) con glEnd(); } +void Element::DrawDCTriangle(std::vector<wxPoint2DDouble> points, wxGraphicsContext* gc) const +{ + points.emplace_back(points[0]); + gc->DrawLines(4, &points[0]); +} + void Element::DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode) const { glBegin(mode); // TODO: GL_QUADS é obsoleto (OpenGL 3.0+), encontrar outra solução. @@ -100,6 +134,13 @@ void Element::DrawPickbox(wxPoint2DDouble position) const DrawRectangle(position, 8.0, 8.0, GL_LINE_LOOP); } +void Element::DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext* gc) const +{ + gc->SetPen(wxPen(wxColour(0, 0, 0, 255))); + gc->SetBrush(wxBrush(wxColour(255, 255, 255, 204))); + gc->DrawRectangle(position.m_x, position.m_y, 8, 8); +} + wxPoint2DDouble Element::RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees) const { double radAngle = angle; @@ -350,9 +391,9 @@ void Element::ReplaceParent(Element* oldParent, Element* newParent) void Element::AddChild(Element* child) { m_childList.push_back(child); } void Element::RemoveChild(Element* child) { - for(auto it = m_childList.begin(); it != m_childList.end(); ++it) { - Element* element = *it; - if(element == child) m_childList.erase(it--); + for(auto it = m_childList.begin(); it != m_childList.end();) { + if (*it == child) it = m_childList.erase(it); + else ++it; } } @@ -371,6 +412,11 @@ void OpenGLColour::SetRGBA(GLdouble red, GLdouble green, GLdouble blue, GLdouble rgba[3] = alpha; } +wxColour OpenGLColour::GetDcRGBA() const +{ + return wxColour(rgba[0] * 255, rgba[1] * 255, rgba[2] * 255, rgba[3] * 255); +} + OpenGLColour::OpenGLColour() { SetRGBA(1.0, 1.0, 1.0, 1.0); } OpenGLColour::OpenGLColour(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) { diff --git a/Project/Element.h b/Project/Element.h index b31a81a..2c845ec 100644 --- a/Project/Element.h +++ b/Project/Element.h @@ -24,7 +24,9 @@ #include <wx/menu.h> #include <wx/stdpaths.h> #include <wx/filename.h> +#include <windows.h> #include <GL/gl.h> +#include <wx/graphics.h> #include <complex> @@ -101,6 +103,7 @@ class OpenGLColour * @return RGBA colour. */ const GLdouble* GetRGBA() const { return rgba; } + wxColour GetDcRGBA() const; protected: GLdouble rgba[4]; }; @@ -297,12 +300,19 @@ class Element */ virtual wxString GetTipText() const { return wxEmptyString; } /** - * @brief Draw the element. + * @brief Draw the element using OpenGL. * @param translation Translation of the system. * @param scale Scale of the system. */ virtual void Draw(wxPoint2DDouble translation, double scale) const {} /** + * @brief Draw the element using GDI+. + * @param translation Translation of the system. + * @param scale Scale of the system. + * @param gc Graphics context + */ + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const {} + /** * @brief Rotate the element. * @param clockwise True to rotate clockwise, false to rotate counter-clockwise. */ @@ -443,6 +453,15 @@ class Element * @param mode OpenGl primitive. */ virtual void DrawCircle(wxPoint2DDouble position, double radius, int numSegments, GLenum mode = GL_LINE_LOOP) const; + + /** + * @brief Draw a circle using device context. + * @param position Circle position. + * @param radius Circle radius + * @param numSegments Num of segments of the circle. + * @param gl Device context. + */ + virtual void DrawDCCircle(wxPoint2DDouble position, double radius, int numSegments, wxGraphicsContext* gc) const; virtual void DrawArc(wxPoint2DDouble position, double radius, double initAngle, @@ -450,6 +469,8 @@ class Element int numSegments, GLenum mode = GL_LINE_LOOP) const; + virtual void DrawDCArc(wxPoint2DDouble position, double radius, double initAngle, double finalAngle, int numSegments, wxGraphicsContext* gc) const; + /** * @brief Draw rectangle. * @param position Rectangle position. @@ -474,6 +495,13 @@ class Element virtual void DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode = GL_TRIANGLES) const; /** + * @brief Draw a triangle. + * @param points Triangle vertices. + * @param gc Device context. + */ + virtual void DrawDCTriangle(std::vector<wxPoint2DDouble> points, wxGraphicsContext* gc) const; + + /** * @brief Draw a point. * @param position Point position. * @param size Point size. @@ -494,6 +522,13 @@ class Element virtual void DrawPickbox(wxPoint2DDouble position) const; /** + * @brief Draw pickbox using direct context. + * @param position Pickbox position. + * @param gc Direct context. + */ + virtual void DrawDCPickbox(wxPoint2DDouble position, wxGraphicsContext* gc) const; + + /** * @brief Rotate a point as element position being the origin. * @param pointToRotate Point that will be rotated. * @param angle Angle of rotation. diff --git a/Project/ElementFormBase.h b/Project/ElementFormBase.h index c8fe7f0..9556f7d 100644 --- a/Project/ElementFormBase.h +++ b/Project/ElementFormBase.h @@ -386,7 +386,7 @@ class GeneratorStabFormBase : public wxDialog wxButton* GetButtonCancel() { return m_ButtonCancel; } GeneratorStabFormBase(wxWindow* parent, wxWindowID id = wxID_ANY, - const wxString& title = _("Generator: Stability"), + const wxString& title = _("Generator: stability"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(-1, -1), long style = wxDEFAULT_DIALOG_STYLE); diff --git a/Project/Exponential.cpp b/Project/Exponential.cpp index 136a2fa..61e5bff 100644 --- a/Project/Exponential.cpp +++ b/Project/Exponential.cpp @@ -21,9 +21,9 @@ Exponential::Exponential(int id) : ControlElement(id) { m_width = m_height = 36.0; - Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize); + Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NodeType::NODE_IN, m_borderSize); nodeIn->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn); diff --git a/Project/Fault.cpp b/Project/Fault.cpp index a71d2ce..cf4dc61 100644 --- a/Project/Fault.cpp +++ b/Project/Fault.cpp @@ -60,8 +60,8 @@ bool Fault::RunFaultCalculation(double systemPowerBase) // Get fault parameters. int fNumber = -1; - FaultData fType = FAULT_THREEPHASE; - FaultData fLocation = FAULT_LINE_A; + FaultData fType = FaultData::FAULT_THREEPHASE; + FaultData fLocation = FaultData::FAULT_LINE_A; std::complex<double> fImpedance = std::complex<double>(0.0, 0.0); for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) { Bus* bus = *it; @@ -90,27 +90,27 @@ bool Fault::RunFaultCalculation(double systemPowerBase) std::complex<double> a2 = std::complex<double>(-0.5, -0.866025403784); switch(fType) { - case FAULT_THREEPHASE: { + case FaultData::FAULT_THREEPHASE: { fCurrentPos = preFaultVoltage / (m_zBusPos[fNumber][fNumber] + fImpedance); } break; - case FAULT_2LINE: { + case FaultData::FAULT_2LINE: { fCurrentPos = preFaultVoltage / (m_zBusPos[fNumber][fNumber] + m_zBusNeg[fNumber][fNumber] + fImpedance); switch(fLocation) { - case FAULT_LINE_A: { + case FaultData::FAULT_LINE_A: { fCurrentNeg = -a2 * fCurrentPos; } break; - case FAULT_LINE_B: { + case FaultData::FAULT_LINE_B: { fCurrentNeg = -fCurrentPos; } break; - case FAULT_LINE_C: { + case FaultData::FAULT_LINE_C: { fCurrentNeg = -a * fCurrentPos; } break; default: break; } } break; - case FAULT_2LINE_GROUND: { + case FaultData::FAULT_2LINE_GROUND: { std::complex<double> z1 = m_zBusPos[fNumber][fNumber]; std::complex<double> z2 = m_zBusNeg[fNumber][fNumber]; std::complex<double> z0 = m_zBusZero[fNumber][fNumber]; @@ -119,15 +119,15 @@ bool Fault::RunFaultCalculation(double systemPowerBase) fCurrentPos = (preFaultVoltage * (z2 + z0 + zf_3)) / (z1 * z2 + z2 * z0 + z2 * zf_3 + z1 * z0 + z1 * zf_3); switch(fLocation) { - case FAULT_LINE_A: { + case FaultData::FAULT_LINE_A: { fCurrentNeg = -a2 * ((preFaultVoltage - z1 * fCurrentPos) / z2); fCurrentZero = -a * ((preFaultVoltage - z1 * fCurrentPos) / (z0 + zf_3)); } break; - case FAULT_LINE_B: { + case FaultData::FAULT_LINE_B: { fCurrentNeg = -((preFaultVoltage - z1 * fCurrentPos) / z2); fCurrentZero = -((preFaultVoltage - z1 * fCurrentPos) / (z0 + zf_3)); } break; - case FAULT_LINE_C: { + case FaultData::FAULT_LINE_C: { fCurrentNeg = -a * ((preFaultVoltage - z1 * fCurrentPos) / z2); fCurrentZero = -a2 * ((preFaultVoltage - z1 * fCurrentPos) / (z0 + zf_3)); } break; @@ -135,20 +135,20 @@ bool Fault::RunFaultCalculation(double systemPowerBase) break; } } break; - case FAULT_LINE_GROUND: { + case FaultData::FAULT_LINE_GROUND: { fCurrentPos = preFaultVoltage / (m_zBusPos[fNumber][fNumber] + m_zBusNeg[fNumber][fNumber] + m_zBusZero[fNumber][fNumber] + std::complex<double>(3.0, 0.0) * fImpedance); switch(fLocation) { - case FAULT_LINE_A: { + case FaultData::FAULT_LINE_A: { fCurrentNeg = fCurrentPos; fCurrentZero = fCurrentPos; } break; - case FAULT_LINE_B: { + case FaultData::FAULT_LINE_B: { fCurrentNeg = a * fCurrentPos; fCurrentZero = a2 * fCurrentPos; } break; - case FAULT_LINE_C: { + case FaultData::FAULT_LINE_C: { fCurrentNeg = a2 * fCurrentPos; fCurrentZero = a * fCurrentPos; } break; diff --git a/Project/Gain.cpp b/Project/Gain.cpp index 2977f1f..596d8ad 100644 --- a/Project/Gain.cpp +++ b/Project/Gain.cpp @@ -22,9 +22,9 @@ Gain::Gain(int id) : ControlElement(id) { m_triPts.resize(3); SetValue(m_value); - Node* nodeIn = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize); + Node* nodeIn = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NodeType::NODE_IN, m_borderSize); nodeIn->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn); diff --git a/Project/GeneralPropertiesForm.cpp b/Project/GeneralPropertiesForm.cpp index 2761d16..c6ef565 100644 --- a/Project/GeneralPropertiesForm.cpp +++ b/Project/GeneralPropertiesForm.cpp @@ -65,7 +65,9 @@ bool GeneralPropertiesForm::ValidateData() auto checkData = m_properties->GetGeneralPropertiesData(); bool hasChanges = false; - wxTextFile file("config.ini"); + //wxTextFile file("config.ini"); + wxFileName fn(wxStandardPaths::Get().GetExecutablePath()); + wxTextFile file(fn.GetPath() + wxFileName::GetPathSeparator() + "config.ini"); if(!file.Create()) { if(!file.Open()) { // Fail to access the file. diff --git a/Project/GeneratorStabForm.cpp b/Project/GeneratorStabForm.cpp index 3eb3a39..f22ecdb 100644 --- a/Project/GeneratorStabForm.cpp +++ b/Project/GeneratorStabForm.cpp @@ -21,12 +21,13 @@ #include "SwitchingForm.h" #include "SyncGenerator.h" -GeneratorStabForm::GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator) +GeneratorStabForm::GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator, wxGLContext* sharedGLContext) : GeneratorStabFormBase(parent) { SetSize(GetBestSize()); m_syncGenerator = syncGenerator; m_parent = parent; + m_sharedGLContext = sharedGLContext; SyncGeneratorElectricalData data = syncGenerator->GetElectricalData(); @@ -75,7 +76,7 @@ void GeneratorStabForm::OnEditAVRButtonClick(wxCommandEvent& event) data.avr = new ControlElementContainer(); m_syncGenerator->SetElectricalData(data); } - ControlEditor* cEditor = new ControlEditor(m_parent, IOControl::IN_TERMINAL_VOLTAGE | IOControl::IN_ACTIVE_POWER | + ControlEditor* cEditor = new ControlEditor(NULL, m_sharedGLContext, IOControl::IN_TERMINAL_VOLTAGE | IOControl::IN_ACTIVE_POWER | IOControl::IN_REACTIVE_POWER | IOControl::IN_INITIAL_TERMINAL_VOLTAGE | IOControl::IN_VELOCITY | IOControl::IN_INITIAL_VELOCITY | IOControl::IN_DELTA_VELOCITY | IOControl::IN_DELTA_ACTIVE_POWER | IOControl::OUT_FIELD_VOLTAGE); @@ -105,7 +106,7 @@ void GeneratorStabForm::OnSpeedGovernorButtonClick(wxCommandEvent& event) m_syncGenerator->SetElectricalData(data); } ControlEditor* cEditor = - new ControlEditor(NULL, IOControl::IN_VELOCITY | IOControl::IN_ACTIVE_POWER | IOControl::IN_REACTIVE_POWER | + new ControlEditor(NULL, m_sharedGLContext, IOControl::IN_VELOCITY | IOControl::IN_ACTIVE_POWER | IOControl::IN_REACTIVE_POWER | IOControl::IN_INITIAL_VELOCITY | IOControl::IN_INITIAL_MEC_POWER | IOControl::OUT_MEC_POWER); cEditor->SetElementsList(data.speedGov->GetControlElementsList()); cEditor->SetConnectionsList(data.speedGov->GetConnectionLineList()); diff --git a/Project/GeneratorStabForm.h b/Project/GeneratorStabForm.h index 14bcd11..3f1305c 100644 --- a/Project/GeneratorStabForm.h +++ b/Project/GeneratorStabForm.h @@ -18,6 +18,7 @@ #ifndef GENERATORSTABFORM_H #define GENERATORSTABFORM_H +#include <wx/glcanvas.h> #include "ElementFormBase.h" class SwitchingForm; @@ -35,7 +36,7 @@ class ControlElementContainer; class GeneratorStabForm : public GeneratorStabFormBase { public: - GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator); + GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator, wxGLContext* sharedGLContext); virtual ~GeneratorStabForm(); protected: @@ -46,10 +47,12 @@ class GeneratorStabForm : public GeneratorStabFormBase virtual void OnOKButtonClick(wxCommandEvent& event); virtual void OnSpeedGovernorButtonClick(wxCommandEvent& event); virtual void OnSwitchingButtonClick(wxCommandEvent& event); + wxGLContext* GetSharedGLContext() const { return m_sharedGLContext; } virtual bool ValidateData(); SyncGenerator* m_syncGenerator = NULL; wxWindow* m_parent = NULL; + wxGLContext* m_sharedGLContext = NULL; }; #endif // GENERATORSTABFORM_H diff --git a/Project/GraphAutoLayout.cpp b/Project/GraphAutoLayout.cpp index 972ce25..bf3bc91 100644 --- a/Project/GraphAutoLayout.cpp +++ b/Project/GraphAutoLayout.cpp @@ -34,7 +34,7 @@ void GraphAutoLayout::AddLink(size_t index1, size_t index2, float weight) m_nodes.push_back(node); } // Add an edge - m_edges.push_back((GraphLayoutEdge){.node1 = m_nodes[index1], .node2 = m_nodes[index2], .weight = weight}); + m_edges.push_back({.node1 = m_nodes[index1], .node2 = m_nodes[index2], .weight = weight}); } void GraphAutoLayout::Compute(size_t iterations) diff --git a/Project/HarmCurrentForm.cpp b/Project/HarmCurrentForm.cpp index 812124c..3a14cc6 100644 --- a/Project/HarmCurrentForm.cpp +++ b/Project/HarmCurrentForm.cpp @@ -16,7 +16,7 @@ HarmCurrentForm::HarmCurrentForm(wxWindow* parent, HarmCurrent* harmCurrent) : H for(unsigned int i = 0; i < data.harmonicOrder.size(); ++i) { long item = m_listCtrlHarmCurrentList->InsertItem(m_maxID, wxString::Format("%d", data.harmonicOrder[i])); m_listCtrlHarmCurrentList->SetItem(item, 1, m_harmCurrent->StringFromDouble(data.injHarmCurrent[i], 1)); - m_listCtrlHarmCurrentList->SetItem(item, 2, data.injHarmCurrentUnit[i] == UNIT_A ? _("A") : _("p.u.")); + m_listCtrlHarmCurrentList->SetItem(item, 2, data.injHarmCurrentUnit[i] == ElectricalUnit::UNIT_A ? _("A") : _("p.u.")); m_listCtrlHarmCurrentList->SetItem(item, 3, m_harmCurrent->StringFromDouble(data.injHarmAngle[i], 1)); m_maxID++; } @@ -50,9 +50,9 @@ bool HarmCurrentForm::ValidateData() if(!m_listCtrlHarmCurrentList->GetItemText(item, 1).ToDouble(&injCurrent)) { return false; } injHarmCurrent.push_back(injCurrent); if(m_listCtrlHarmCurrentList->GetItemText(item, 2) == "A") - injHarmCurrentUnit.push_back(UNIT_A); + injHarmCurrentUnit.push_back(ElectricalUnit::UNIT_A); else - injHarmCurrentUnit.push_back(UNIT_PU); + injHarmCurrentUnit.push_back(ElectricalUnit::UNIT_PU); double injCAngle = 0.0; if(!m_listCtrlHarmCurrentList->GetItemText(item, 3).ToDouble(&injCAngle)) { return false; } injHarmAngle.push_back(injCAngle); @@ -124,9 +124,9 @@ void HarmCurrentForm::SortList() if(!m_listCtrlHarmCurrentList->GetItemText(item, 1).ToDouble(&injCurrent)) return; injHarmCurrent.push_back(injCurrent); if(m_listCtrlHarmCurrentList->GetItemText(item, 2) == "A") - injHarmCurrentUnit.push_back(UNIT_A); + injHarmCurrentUnit.push_back(ElectricalUnit::UNIT_A); else - injHarmCurrentUnit.push_back(UNIT_PU); + injHarmCurrentUnit.push_back(ElectricalUnit::UNIT_PU); double injCAngle = 0.0; if(!m_listCtrlHarmCurrentList->GetItemText(item, 3).ToDouble(&injCAngle)) return; injHarmAngle.push_back(injCAngle); @@ -165,7 +165,7 @@ void HarmCurrentForm::SortList() for(unsigned int i = 0; i < harmonicOrder.size(); ++i) { long item = m_listCtrlHarmCurrentList->InsertItem(m_maxID, wxString::Format("%d", harmonicOrder[i])); m_listCtrlHarmCurrentList->SetItem(item, 1, m_harmCurrent->StringFromDouble(injHarmCurrent[i], 1)); - m_listCtrlHarmCurrentList->SetItem(item, 2, injHarmCurrentUnit[i] == UNIT_A ? _("A") : _("p.u.")); + m_listCtrlHarmCurrentList->SetItem(item, 2, injHarmCurrentUnit[i] == ElectricalUnit::UNIT_A ? _("A") : _("p.u.")); m_listCtrlHarmCurrentList->SetItem(item, 3, m_harmCurrent->StringFromDouble(injHarmAngle[i], 1)); m_maxID++; } diff --git a/Project/IOControl.cpp b/Project/IOControl.cpp index 114e8bf..9a3cd73 100644 --- a/Project/IOControl.cpp +++ b/Project/IOControl.cpp @@ -22,7 +22,7 @@ IOControl::IOControl(int ioFlags, int id) : ControlElement(id) { m_ioFlags = ioFlags; - Node* node = new Node(m_position, Node::NODE_IN, m_borderSize); + Node* node = new Node(m_position, Node::NodeType::NODE_IN, m_borderSize); m_nodeList.push_back(node); if(ioFlags & IN_TERMINAL_VOLTAGE) @@ -157,47 +157,47 @@ wxString IOControl::GenerateText() switch(m_value) { case IN_TERMINAL_VOLTAGE: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return _("Vt"); } break; case IN_VELOCITY: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return omega; } break; case IN_ACTIVE_POWER: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return _("P"); } break; case IN_REACTIVE_POWER: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return _("Q"); } break; case OUT_FIELD_VOLTAGE: { - m_ioNodeType = Node::NODE_IN; + m_ioNodeType = Node::NodeType::NODE_IN; return _("Vf"); } break; case OUT_MEC_POWER: { - m_ioNodeType = Node::NODE_IN; + m_ioNodeType = Node::NodeType::NODE_IN; return _("Pm"); } break; case IN_INITIAL_TERMINAL_VOLTAGE: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return _("Vt") + subZero; } break; case IN_INITIAL_MEC_POWER: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return _("Pm") + subZero; } break; case IN_INITIAL_VELOCITY: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return omega + subZero; } break; case IN_DELTA_VELOCITY: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return capDelta + omega; } break; case IN_DELTA_ACTIVE_POWER: { - m_ioNodeType = Node::NODE_OUT; + m_ioNodeType = Node::NodeType::NODE_OUT; return capDelta + _("P"); } break; } @@ -233,22 +233,22 @@ void IOControl::UpdatePoints() } node->SetNodeType(m_ioNodeType); if(m_angle == 0.0) { - if(m_ioNodeType == Node::NODE_IN) + if(m_ioNodeType == Node::NodeType::NODE_IN) node->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0)); else node->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0)); } else if(m_angle == 90.0) { - if(m_ioNodeType == Node::NODE_IN) + if(m_ioNodeType == Node::NodeType::NODE_IN) node->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2)); else node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2)); } else if(m_angle == 180.0) { - if(m_ioNodeType == Node::NODE_IN) + if(m_ioNodeType == Node::NodeType::NODE_IN) node->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0)); else node->SetPosition(m_position + wxPoint2DDouble(2 - m_width / 2, 0)); } else if(m_angle == 270.0) { - if(m_ioNodeType == Node::NODE_IN) + if(m_ioNodeType == Node::NodeType::NODE_IN) node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2)); else node->SetPosition(m_position + wxPoint2DDouble(0, 2 - m_height / 2)); diff --git a/Project/IOControl.h b/Project/IOControl.h index 0af3429..0fe2f40 100644 --- a/Project/IOControl.h +++ b/Project/IOControl.h @@ -75,7 +75,7 @@ class IOControl : public ControlElement IOFlags m_value; int m_ioFlags; - Node::NodeType m_ioNodeType = Node::NODE_IN; + Node::NodeType m_ioNodeType = Node::NodeType::NODE_IN; OpenGLText* m_glText = NULL; }; diff --git a/Project/IndMotor.cpp b/Project/IndMotor.cpp index 4df2bb1..621eb5e 100644 --- a/Project/IndMotor.cpp +++ b/Project/IndMotor.cpp @@ -32,6 +32,17 @@ void IndMotor::DrawSymbol() const DrawLine(mPts); } +void IndMotor::DrawDCSymbol(wxGraphicsContext* gc) const +{ + std::vector<wxPoint2DDouble> mPts; + mPts.push_back(wxPoint2DDouble(-10, 13) + m_position); + mPts.push_back(wxPoint2DDouble(-10, -13) + m_position); + mPts.push_back(wxPoint2DDouble(0, 2) + m_position); + mPts.push_back(wxPoint2DDouble(10, -13) + m_position); + mPts.push_back(wxPoint2DDouble(10, 13) + m_position); + gc->DrawLines(mPts.size(), &mPts[0]); +} + bool IndMotor::GetContextMenu(wxMenu& menu) { menu.Append(ID_EDIT_ELEMENT, _("Edit induction motor")); diff --git a/Project/IndMotor.h b/Project/IndMotor.h index 0aa6937..7e20a2f 100644 --- a/Project/IndMotor.h +++ b/Project/IndMotor.h @@ -124,6 +124,7 @@ class IndMotor : public Machines virtual Element* GetCopy(); virtual void DrawSymbol() const; + virtual void DrawDCSymbol(wxGraphicsContext* gc) const; virtual bool GetContextMenu(wxMenu& menu); virtual wxString GetTipText() const; virtual bool ShowForm(wxWindow* parent, Element* element); diff --git a/Project/IndMotorForm.cpp b/Project/IndMotorForm.cpp index 8517aef..c4187f2 100644 --- a/Project/IndMotorForm.cpp +++ b/Project/IndMotorForm.cpp @@ -30,13 +30,13 @@ IndMotorForm::IndMotorForm(wxWindow* parent, IndMotor* indMotor) : IndMotorFormB m_textCtrlnominalPower->SetValue(IndMotor::StringFromDouble(data.ratedPower)); switch(data.activePowerUnit) { - case UNIT_VA: { + case ElectricalUnit::UNIT_VA: { m_choiceNominalPower->SetSelection(0); } break; - case UNIT_kVA: { + case ElectricalUnit::UNIT_kVA: { m_choiceNominalPower->SetSelection(1); } break; - case UNIT_MVA: { + case ElectricalUnit::UNIT_MVA: { m_choiceNominalPower->SetSelection(2); } break; default: @@ -45,16 +45,16 @@ IndMotorForm::IndMotorForm(wxWindow* parent, IndMotor* indMotor) : IndMotorFormB m_textCtrlActivePower->SetValue(IndMotor::StringFromDouble(data.activePower)); switch(data.activePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceActivePower->SetSelection(0); } break; case UNIT_W: { m_choiceActivePower->SetSelection(1); } break; - case UNIT_kW: { + case ElectricalUnit::UNIT_kW: { m_choiceActivePower->SetSelection(2); } break; - case UNIT_MW: { + case ElectricalUnit::UNIT_MW: { m_choiceActivePower->SetSelection(3); } break; default: @@ -63,16 +63,16 @@ IndMotorForm::IndMotorForm(wxWindow* parent, IndMotor* indMotor) : IndMotorFormB m_textCtrlReactivePower->SetValue(IndMotor::StringFromDouble(data.reactivePower)); switch(data.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceReactivePower->SetSelection(0); } break; - case UNIT_VAr: { + case ElectricalUnit::UNIT_VAr: { m_choiceReactivePower->SetSelection(1); } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { m_choiceReactivePower->SetSelection(2); } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { m_choiceReactivePower->SetSelection(3); } break; default: @@ -130,13 +130,13 @@ bool IndMotorForm::ValidateData() return false; switch(m_choiceNominalPower->GetSelection()) { case 0: { - data.activePowerUnit = UNIT_VA; + data.activePowerUnit = ElectricalUnit::UNIT_VA; } break; case 1: { - data.activePowerUnit = UNIT_kVA; + data.activePowerUnit = ElectricalUnit::UNIT_kVA; } break; case 2: { - data.activePowerUnit = UNIT_MVA; + data.activePowerUnit = ElectricalUnit::UNIT_MVA; } break; } @@ -145,16 +145,16 @@ bool IndMotorForm::ValidateData() return false; switch(m_choiceActivePower->GetSelection()) { case 0: { - data.activePowerUnit = UNIT_PU; + data.activePowerUnit = ElectricalUnit::UNIT_PU; } break; case 1: { data.activePowerUnit = UNIT_W; } break; case 2: { - data.activePowerUnit = UNIT_kW; + data.activePowerUnit = ElectricalUnit::UNIT_kW; } break; case 3: { - data.activePowerUnit = UNIT_MW; + data.activePowerUnit = ElectricalUnit::UNIT_MW; } break; } @@ -163,16 +163,16 @@ bool IndMotorForm::ValidateData() return false; switch(m_choiceReactivePower->GetSelection()) { case 0: { - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.reactivePowerUnit = UNIT_VAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_VAr; } break; case 2: { - data.reactivePowerUnit = UNIT_kVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_kVAr; } break; case 3: { - data.reactivePowerUnit = UNIT_MVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_MVAr; } break; } diff --git a/Project/Inductor.cpp b/Project/Inductor.cpp index 9bfd599..8bd056d 100644 --- a/Project/Inductor.cpp +++ b/Project/Inductor.cpp @@ -110,6 +110,75 @@ void Inductor::Draw(wxPoint2DDouble translation, double scale) const } } +void Inductor::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + } + else + elementColour = m_offlineElementColour; + + if (m_inserted) { + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 30, gc); + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 30, gc); + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 30, gc); + + DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), gc); + + gc->PopState(); + + // Draw node selection. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc); + } + // Draw Inductor (layer 2). + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0, 10, gc); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + DrawDCSwitches(gc); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 10, gc); + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 10, gc); + DrawDCArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 10, gc); + + DrawDCGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0), gc); + + gc->PopState(); + } +} + void Inductor::Rotate(bool clockwise) { double rotAngle = m_rotationAngle; @@ -152,17 +221,17 @@ InductorElectricalData Inductor::GetPUElectricalData(double systemPowerBase) { InductorElectricalData data = m_electricalData; switch(data.reactivePowerUnit) { - case UNIT_VAr: { + case ElectricalUnit::UNIT_VAr: { data.reactivePower = data.reactivePower / systemPowerBase; - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase; - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase; - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; default: break; @@ -193,16 +262,16 @@ wxString Inductor::GetTipText() const tipText += "\n"; tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5); switch(m_electricalData.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { tipText += _(" p.u."); } break; - case UNIT_VAr: { + case ElectricalUnit::UNIT_VAr: { tipText += _(" VAr"); } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { tipText += _(" kVAr"); } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { tipText += _(" MVAr"); } break; default: diff --git a/Project/Inductor.h b/Project/Inductor.h index 0362dcf..d613a4c 100644 --- a/Project/Inductor.h +++ b/Project/Inductor.h @@ -25,7 +25,7 @@ class ReactiveShuntElementForm; struct InductorElectricalData { wxString name; double reactivePower = 100.0; - ElectricalUnit reactivePowerUnit = UNIT_MVAr; + ElectricalUnit reactivePowerUnit = ElectricalUnit::UNIT_MVAr; }; /** @@ -45,6 +45,7 @@ class Inductor : public Shunt virtual Element* GetCopy(); virtual bool AddParent(Element* parent, wxPoint2DDouble position); virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual bool Contains(wxPoint2DDouble position) const; virtual bool Intersects(wxRect2DDouble rect) const; virtual void Rotate(bool clockwise = true); diff --git a/Project/Limiter.cpp b/Project/Limiter.cpp index 74fbf3d..33ecb66 100644 --- a/Project/Limiter.cpp +++ b/Project/Limiter.cpp @@ -21,9 +21,9 @@ Limiter::Limiter(int id) : ControlElement(id) { m_width = m_height = 36.0; - Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize); + Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NodeType::NODE_IN, m_borderSize); nodeIn->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn); diff --git a/Project/Line.cpp b/Project/Line.cpp index d143355..9750b82 100644 --- a/Project/Line.cpp +++ b/Project/Line.cpp @@ -101,6 +101,80 @@ void Line::Draw(wxPoint2DDouble translation, double scale) const } } +void Line::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + //gc->SetBrush(*wxTRANSPARENT_BRUSH); + + wxGraphicsMatrix identityMatrix = gc->GetTransform(); + identityMatrix.Set(); // Set to identity + + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + + } + else + elementColour = m_offlineElementColour; + + std::vector<wxPoint2DDouble> pointList = m_pointList; + if (!m_inserted && pointList.size() > 0) { + wxPoint2DDouble secondPoint = m_position; + if (pointList.size() > 2) { secondPoint = pointList[2]; } + pointList[1] = GetSwitchPoint(m_parentList[0], pointList[0], secondPoint); + pointList.push_back(m_position); + } + + // Line selected (Layer 1). + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + if (pointList.size() > 0) + gc->DrawLines(pointList.size(), &pointList[0]); + + // Draw nodes selection. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + if (pointList.size() > 0) { + DrawDCCircle(pointList[0], 5.0 + m_borderSize / scale, 10, gc); + if (m_inserted) { DrawDCCircle(pointList[pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); } + } + } + + // Draw line (Layer 2) + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + if(pointList.size() > 0) + gc->DrawLines(pointList.size(), &pointList[0]); + + if (m_inserted) { + DrawDCSwitches(gc); + DrawDCPowerFlowPts(gc); + } + + // Draw nodes. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + if (pointList.size() > 0) { + DrawDCCircle(pointList[0], 5.0, 10, gc); + if (m_inserted) { DrawDCCircle(pointList[pointList.size() - 1], 5.0, 10, gc); } + } + + // Draw pickboxes (Layer 3). + if (m_showPickbox) { + gc->PushState(); + gc->SetTransform(identityMatrix); + + for (int i = 2; i < (int)m_pointList.size() - 2; i++) { + DrawDCPickbox(WorldToScreen(m_pointList[i], translation - wxPoint2DDouble(4 / scale, 4 / scale), scale), gc); + } + + gc->PopState(); + } +} + void Line::Move(wxPoint2DDouble position) { if(!m_parentList[0]) { @@ -445,13 +519,13 @@ void Line::UpdatePowerFlowArrowsPosition() { std::vector<wxPoint2DDouble> edges; switch(m_pfDirection) { - case PF_NONE: { + case PowerFlowDirection::PF_NONE: { m_powerFlowArrow.clear(); } break; - case PF_BUS1_TO_BUS2: { + case PowerFlowDirection::PF_BUS1_TO_BUS2: { for(int i = 1; i < (int)m_pointList.size() - 1; i++) { edges.push_back(m_pointList[i]); } } break; - case PF_BUS2_TO_BUS1: { + case PowerFlowDirection::PF_BUS2_TO_BUS1: { for(int i = (int)m_pointList.size() - 2; i > 0; i--) { edges.push_back(m_pointList[i]); } } break; default: @@ -521,33 +595,33 @@ LineElectricalData Line::GetPUElectricalData(double systemBasePower) // Resistance double r = data.resistance; - if(data.resistanceUnit == UNIT_OHM_km) r *= data.lineSize; - if(data.resistanceUnit == UNIT_PU) { + if(data.resistanceUnit == ElectricalUnit::UNIT_OHM_km) r *= data.lineSize; + if(data.resistanceUnit == ElectricalUnit::UNIT_PU) { if(data.useLinePower) data.resistance = (r * lineBaseImpedance) / systemBaseImpedance; } else { data.resistance = r / systemBaseImpedance; } - data.resistanceUnit = UNIT_PU; + data.resistanceUnit = ElectricalUnit::UNIT_PU; // Inductive reactance double x = data.indReactance; - if(data.indReactanceUnit == UNIT_OHM_km) x *= data.lineSize; - if(data.indReactanceUnit == UNIT_PU) { + if(data.indReactanceUnit == ElectricalUnit::UNIT_OHM_km) x *= data.lineSize; + if(data.indReactanceUnit == ElectricalUnit::UNIT_PU) { if(data.useLinePower) data.indReactance = (x * lineBaseImpedance) / systemBaseImpedance; } else { data.indReactance = x / systemBaseImpedance; } - data.indReactanceUnit = UNIT_PU; + data.indReactanceUnit = ElectricalUnit::UNIT_PU; // Capacitive susceptance double b = data.capSusceptance; - if(data.capSusceptanceUnit == UNIT_OHM_km) b *= data.lineSize; - if(data.capSusceptanceUnit == UNIT_PU) { + if(data.capSusceptanceUnit == ElectricalUnit::UNIT_OHM_km) b *= data.lineSize; + if(data.capSusceptanceUnit == ElectricalUnit::UNIT_PU) { if(data.useLinePower) data.capSusceptance = (b * lineBaseImpedance) / systemBaseImpedance; } else { data.capSusceptance = b / systemBaseImpedance; } - data.capSusceptanceUnit = UNIT_PU; + data.capSusceptanceUnit = ElectricalUnit::UNIT_PU; // Fault diff --git a/Project/Line.h b/Project/Line.h index 75df0f2..3597367 100644 --- a/Project/Line.h +++ b/Project/Line.h @@ -25,15 +25,15 @@ struct LineElectricalData { // General wxString name = ""; double nominalVoltage = 138.0; - ElectricalUnit nominalVoltageUnit = UNIT_kV; + ElectricalUnit nominalVoltageUnit = ElectricalUnit::UNIT_kV; double nominalPower = 100.0; - ElectricalUnit nominalPowerUnit = UNIT_MVA; + ElectricalUnit nominalPowerUnit = ElectricalUnit::UNIT_MVA; double resistance = 0.0; - ElectricalUnit resistanceUnit = UNIT_PU; + ElectricalUnit resistanceUnit = ElectricalUnit::UNIT_PU; double indReactance = 1.0; - ElectricalUnit indReactanceUnit = UNIT_PU; + ElectricalUnit indReactanceUnit = ElectricalUnit::UNIT_PU; double capSusceptance = 0.0; - ElectricalUnit capSusceptanceUnit = UNIT_PU; + ElectricalUnit capSusceptanceUnit = ElectricalUnit::UNIT_PU; double lineSize = 100.0; bool useLinePower = false; @@ -64,6 +64,7 @@ class Line : public Branch ~Line(); virtual bool Contains(wxPoint2DDouble position) const; virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual void Move(wxPoint2DDouble position); virtual void StartMove(wxPoint2DDouble position); virtual void MoveNode(Element* parent, wxPoint2DDouble position); diff --git a/Project/LineForm.cpp b/Project/LineForm.cpp index f0df0c7..204595a 100644 --- a/Project/LineForm.cpp +++ b/Project/LineForm.cpp @@ -47,10 +47,10 @@ LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent) wxString nominalVoltageStr = Line::StringFromDouble(data.nominalVoltage); switch(data.nominalVoltageUnit) { - case UNIT_V: { + case ElectricalUnit::UNIT_V: { nominalVoltageStr += " V"; } break; - case UNIT_kV: { + case ElectricalUnit::UNIT_kV: { nominalVoltageStr += " kV"; } break; default: @@ -60,13 +60,13 @@ LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent) m_textCtrlNominalPower->SetValue(Line::StringFromDouble(data.nominalPower)); switch(data.nominalPowerUnit) { - case UNIT_VA: { + case ElectricalUnit::UNIT_VA: { m_choiceNominalPower->SetSelection(0); } break; - case UNIT_kVA: { + case ElectricalUnit::UNIT_kVA: { m_choiceNominalPower->SetSelection(1); } break; - case UNIT_MVA: { + case ElectricalUnit::UNIT_MVA: { m_choiceNominalPower->SetSelection(2); } break; default: @@ -75,13 +75,13 @@ LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent) m_textCtrlResistance->SetValue(Line::StringFromDouble(data.resistance)); switch(data.resistanceUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceResistance->SetSelection(0); } break; - case UNIT_OHM: { + case ElectricalUnit::UNIT_OHM: { m_choiceResistance->SetSelection(1); } break; - case UNIT_OHM_km: { + case ElectricalUnit::UNIT_OHM_km: { m_choiceResistance->SetSelection(2); } break; default: @@ -90,13 +90,13 @@ LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent) m_textCtrlReactance->SetValue(Line::StringFromDouble(data.indReactance)); switch(data.indReactanceUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceReactance->SetSelection(0); } break; - case UNIT_OHM: { + case ElectricalUnit::UNIT_OHM: { m_choiceReactance->SetSelection(1); } break; - case UNIT_OHM_km: { + case ElectricalUnit::UNIT_OHM_km: { m_choiceReactance->SetSelection(2); } break; default: @@ -105,13 +105,13 @@ LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent) m_textCtrlSusceptance->SetValue(Line::StringFromDouble(data.capSusceptance)); switch(data.capSusceptanceUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceSusceptance->SetSelection(0); } break; - case UNIT_S: { + case ElectricalUnit::UNIT_S: { m_choiceSusceptance->SetSelection(1); } break; - case UNIT_S_km: { + case ElectricalUnit::UNIT_S_km: { m_choiceSusceptance->SetSelection(2); } break; default: @@ -161,13 +161,13 @@ bool LineForm::ValidateData() return false; switch(m_choiceNominalPower->GetSelection()) { case 0: { - data.nominalPowerUnit = UNIT_VA; + data.nominalPowerUnit = ElectricalUnit::UNIT_VA; } break; case 1: { - data.nominalPowerUnit = UNIT_kVA; + data.nominalPowerUnit = ElectricalUnit::UNIT_kVA; } break; case 2: { - data.nominalPowerUnit = UNIT_MVA; + data.nominalPowerUnit = ElectricalUnit::UNIT_MVA; } break; } @@ -176,13 +176,13 @@ bool LineForm::ValidateData() return false; switch(m_choiceResistance->GetSelection()) { case 0: { - data.resistanceUnit = UNIT_PU; + data.resistanceUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.resistanceUnit = UNIT_OHM; + data.resistanceUnit = ElectricalUnit::UNIT_OHM; } break; case 2: { - data.resistanceUnit = UNIT_OHM_km; + data.resistanceUnit = ElectricalUnit::UNIT_OHM_km; } break; } @@ -191,13 +191,13 @@ bool LineForm::ValidateData() return false; switch(m_choiceReactance->GetSelection()) { case 0: { - data.indReactanceUnit = UNIT_PU; + data.indReactanceUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.indReactanceUnit = UNIT_OHM; + data.indReactanceUnit = ElectricalUnit::UNIT_OHM; } break; case 2: { - data.indReactanceUnit = UNIT_OHM_km; + data.indReactanceUnit = ElectricalUnit::UNIT_OHM_km; } break; } @@ -206,13 +206,13 @@ bool LineForm::ValidateData() return false; switch(m_choiceSusceptance->GetSelection()) { case 0: { - data.capSusceptanceUnit = UNIT_PU; + data.capSusceptanceUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.capSusceptanceUnit = UNIT_S; + data.capSusceptanceUnit = ElectricalUnit::UNIT_S; } break; case 2: { - data.capSusceptanceUnit = UNIT_S_km; + data.capSusceptanceUnit = ElectricalUnit::UNIT_S_km; } break; } diff --git a/Project/Load.cpp b/Project/Load.cpp index d9f1b2a..22c9cd9 100644 --- a/Project/Load.cpp +++ b/Project/Load.cpp @@ -116,6 +116,75 @@ void Load::Draw(wxPoint2DDouble translation, double scale) const } } +void Load::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + } + else + elementColour = m_offlineElementColour; + + if (m_inserted) { + // Draw Selection (layer 1). + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + + std::vector<wxPoint2DDouble> selTriangPts; + selTriangPts.push_back(m_triangPts[0] + m_position + + wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale)); + selTriangPts.push_back(m_triangPts[1] + m_position + + wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale)); + selTriangPts.push_back(m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale)); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + DrawDCTriangle(selTriangPts, gc); + gc->PopState(); + + // Draw node selection. + DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc); + } + + // Draw Load (layer 2). + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + // Draw node. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0, 10, gc); + + DrawDCSwitches(gc); + DrawDCPowerFlowPts(gc); + + std::vector<wxPoint2DDouble> triangPts; + for (int i = 0; i < 3; i++) { triangPts.push_back(m_triangPts[i] + m_position); } + gc->PushState(); + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCTriangle(triangPts, gc); + gc->PopState(); + } +} + void Load::Rotate(bool clockwise) { double rotAngle = m_rotationAngle; diff --git a/Project/Load.h b/Project/Load.h index 4fa01ad..56b1549 100644 --- a/Project/Load.h +++ b/Project/Load.h @@ -80,13 +80,14 @@ class Load : public Shunt virtual Element* GetCopy(); virtual bool AddParent(Element* parent, wxPoint2DDouble position); virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual void Rotate(bool clockwise = true); virtual bool GetContextMenu(wxMenu& menu); virtual wxString GetTipText() const; virtual bool ShowForm(wxWindow* parent, Element* element); LoadElectricalData GetElectricalData() { return m_electricalData; } LoadElectricalData GetPUElectricalData(double systemPowerBase); - void SetElectricalData(LoadElectricalData electricalData) { m_electricalData = electricalData; } + void SetElectricalData(const LoadElectricalData& electricalData) { m_electricalData = electricalData; } virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY); virtual rapidxml::xml_node<>* SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode); diff --git a/Project/Machines.cpp b/Project/Machines.cpp index 8ee940f..351fd16 100644 --- a/Project/Machines.cpp +++ b/Project/Machines.cpp @@ -98,6 +98,60 @@ void Machines::Draw(wxPoint2DDouble translation, double scale) const } } +void Machines::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + } + else + elementColour = m_offlineElementColour; + + if (m_inserted) { + // Draw Selection (layer 1). + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + DrawDCCircle(m_position, 25.0 + (m_borderSize + 1.5) / scale, 20, gc); + + // Draw nodes selection. + DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc); + } + + // Draw Machines (layer 2). + // Draw node. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCCircle(m_pointList[0], 5.0, 10, gc); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + DrawDCCircle(m_position, 25.0, 20.0, gc); + + DrawDCSwitches(gc); + DrawDCPowerFlowPts(gc); + + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(*wxWHITE_BRUSH); + DrawDCCircle(m_position, 25.0, 20.0, gc); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + DrawDCCircle(m_position, 25.0, 20.0, gc); + + // Draw machine symbol. + DrawDCSymbol(gc); + } +} + void Machines::UpdateSwitchesPosition() { if(m_parentList[0]) { @@ -246,14 +300,14 @@ void Machines::UpdatePowerFlowArrowsPosition() { std::vector<wxPoint2DDouble> edges; switch(m_pfDirection) { - case PF_NONE: { + case PowerFlowDirection::PF_NONE: { m_powerFlowArrow.clear(); } break; - case PF_TO_BUS: { + case PowerFlowDirection::PF_TO_BUS: { edges.push_back(m_pointList[2]); edges.push_back(m_pointList[1]); } break; - case PF_TO_ELEMENT: { + case PowerFlowDirection::PF_TO_ELEMENT: { edges.push_back(m_pointList[1]); edges.push_back(m_pointList[2]); } break; diff --git a/Project/Machines.h b/Project/Machines.h index db6f449..e3aa844 100644 --- a/Project/Machines.h +++ b/Project/Machines.h @@ -41,6 +41,7 @@ class Machines : public PowerElement virtual bool AddParent(Element* parent, wxPoint2DDouble position); virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); } virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); } virtual void Move(wxPoint2DDouble position); virtual void MoveNode(Element* element, wxPoint2DDouble position); @@ -52,6 +53,7 @@ class Machines : public PowerElement virtual void UpdateNodes(); virtual void Rotate(bool clockwise = true); virtual void DrawSymbol() const {} + virtual void DrawDCSymbol(wxGraphicsContext* gc) const {} virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection); protected: diff --git a/Project/MainFrame.cpp b/Project/MainFrame.cpp index 3447ed5..36712d5 100644 --- a/Project/MainFrame.cpp +++ b/Project/MainFrame.cpp @@ -37,6 +37,7 @@ #include "Transformer.h" #include "Workspace.h" #include "artProvider/ArtMetro.h" +#include "WorkspaceDC.h" MainFrame::MainFrame() : MainFrameBase(NULL) {} MainFrame::MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initProperties, wxString openPath) @@ -50,7 +51,7 @@ MainFrame::MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initPro if(openPath != "") { EnableCurrentProjectRibbon(); Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar(), m_sharedGLContext); - if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetOpenGLContext(); + if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetSharedGLContext(); FileHanding fileHandling(newWorkspace); if(fileHandling.OpenProject(openPath)) { @@ -192,9 +193,19 @@ void MainFrame::OnNewClick(wxRibbonButtonBarEvent& event) { EnableCurrentProjectRibbon(); - Workspace* newWorkspace = new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), - this->GetStatusBar(), m_sharedGLContext); - if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetOpenGLContext(); + Workspace* newWorkspace; + if (m_generalProperties->GetGeneralPropertiesData().useOpenGL) { + newWorkspace = new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), + this->GetStatusBar(), m_sharedGLContext); + if (!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetSharedGLContext(); + } + else { + newWorkspace = new WorkspaceDC(this, wxString::Format(_("New project %d"), m_projectNumber), + this->GetStatusBar()); + } + // Set general properties in new Workspace + newWorkspace->GetProperties()->SetGeneralPropertiesData(m_generalProperties->GetGeneralPropertiesData()); + m_workspaceList.push_back(newWorkspace); m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true); @@ -308,9 +319,22 @@ void MainFrame::OnOpenClick(wxRibbonButtonBarEvent& event) wxFileName fileName(openFileDialog.GetPath()); EnableCurrentProjectRibbon(); - Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar(), m_sharedGLContext); - if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetOpenGLContext(); + Workspace* newWorkspace; + if (m_generalProperties->GetGeneralPropertiesData().useOpenGL) { + newWorkspace = new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), + this->GetStatusBar(), m_sharedGLContext); + // If none shared OpenGL context is loaded, get from this workspace. + if (!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetSharedGLContext(); + } + else { + newWorkspace = new WorkspaceDC(this, wxString::Format(_("New project %d"), m_projectNumber), + this->GetStatusBar()); + } + + // Set general properties in new workspace. + newWorkspace->GetProperties()->SetGeneralPropertiesData(m_generalProperties->GetGeneralPropertiesData()); + FileHanding fileHandling(newWorkspace); if(fileHandling.OpenProject(fileName)) { newWorkspace->SetSavedPath(fileName); @@ -507,7 +531,7 @@ void MainFrame::OnImportClick(wxRibbonButtonBarEvent& event) // Import file(s) EnableCurrentProjectRibbon(); - if(!m_sharedGLContext) m_sharedGLContext = impWorkspace->GetOpenGLContext(); + if(!m_sharedGLContext) m_sharedGLContext = impWorkspace->GetSharedGLContext(); m_workspaceList.push_back(impWorkspace); m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true); @@ -532,14 +556,14 @@ void MainFrame::NotebookPageClosing(wxAuiNotebookEvent& event) auto it = m_workspaceList.begin(); while(it != m_workspaceList.end()) { if(*it == m_auiNotebook->GetCurrentPage()) { - if((*it)->GetOpenGLContext() == m_sharedGLContext) m_sharedGLContext = NULL; + if((*it)->GetSharedGLContext() == m_sharedGLContext) m_sharedGLContext = NULL; m_workspaceList.erase(it); break; } it++; } if(!m_sharedGLContext && m_workspaceList.size() != 0) { - m_sharedGLContext = m_workspaceList[0]->GetOpenGLContext(); + m_sharedGLContext = m_workspaceList[0]->GetSharedGLContext(); } event.Skip(); } @@ -610,7 +634,7 @@ int MainFrame::RunPSPTest() Workspace* newWorkspace = new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), this->GetStatusBar(), m_sharedGLContext); - if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetOpenGLContext(); + if(!m_sharedGLContext) m_sharedGLContext = newWorkspace->GetSharedGLContext(); m_workspaceList.push_back(newWorkspace); m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true); diff --git a/Project/MainFrameBase.cpp b/Project/MainFrameBase.cpp index 3e1da85..295b3e6 100644 --- a/Project/MainFrameBase.cpp +++ b/Project/MainFrameBase.cpp @@ -261,7 +261,7 @@ MainFrameBase::MainFrameBase(wxWindow* parent, wxXmlResource::Get()->LoadBitmap(wxT("powerFLow32")), _("Calculate the circuit power flow"), wxRIBBON_BUTTON_NORMAL); - m_ribbonButtonBarSimulations->AddButton(ID_RIBBON_RUNSTAB, _("Run Stability"), + m_ribbonButtonBarSimulations->AddButton(ID_RIBBON_RUNSTAB, _("Run stability"), wxXmlResource::Get()->LoadBitmap(wxT("playStopped32")), _("Run the stability calculations"), wxRIBBON_BUTTON_HYBRID); diff --git a/Project/MathExpression.cpp b/Project/MathExpression.cpp index 066825f..e6515b5 100644 --- a/Project/MathExpression.cpp +++ b/Project/MathExpression.cpp @@ -45,11 +45,11 @@ MathExpression::MathExpression(int id) : ControlElement(id) } else { nodePosition = m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2); } - Node* nodeIn = new Node(nodePosition, Node::NODE_IN, m_borderSize); + Node* nodeIn = new Node(nodePosition, Node::NodeType::NODE_IN, m_borderSize); nodeIn->StartMove(m_position); m_nodeList.push_back(nodeIn); } - Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeOut); @@ -165,7 +165,7 @@ bool MathExpression::Solve(double* input, double timeStep) int i = 3; for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) { Node* node = *itN; - if(node->GetNodeType() != Node::NODE_OUT) { + if(node->GetNodeType() != Node::NodeType::NODE_OUT) { if(!node->IsConnected()) { m_inputValues[i] = 0.0; // Node not connected means zero value as input. } else { @@ -243,7 +243,7 @@ void MathExpression::UpdatePoints() void MathExpression::AddInNode() { - Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NODE_IN, m_borderSize); + Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize); newNode->SetAngle(m_angle); m_nodeList.insert(m_nodeList.end() - 1, newNode); } diff --git a/Project/MathOperation.cpp b/Project/MathOperation.cpp index 5f544ce..c9128aa 100644 --- a/Project/MathOperation.cpp +++ b/Project/MathOperation.cpp @@ -21,11 +21,11 @@ MathOperation::MathOperation(int id) : ControlElement(id) { m_width = m_height = 36.0; - Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-18, -9), Node::NODE_IN, m_borderSize); + Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-18, -9), Node::NodeType::NODE_IN, m_borderSize); nodeIn1->StartMove(m_position); - Node* nodeIn2 = new Node(m_position + wxPoint2DDouble(-18, 9), Node::NODE_IN, m_borderSize); + Node* nodeIn2 = new Node(m_position + wxPoint2DDouble(-18, 9), Node::NodeType::NODE_IN, m_borderSize); nodeIn2->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn1); diff --git a/Project/Multiplier.cpp b/Project/Multiplier.cpp index 7a9bcd8..75ce701 100644 --- a/Project/Multiplier.cpp +++ b/Project/Multiplier.cpp @@ -38,7 +38,7 @@ bool Multiplier::Solve(double* input, double timeStep) std::vector<double> inputVector; for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) { Node* node = *itN; - if(node->GetNodeType() != Node::NODE_OUT) { + if(node->GetNodeType() != Node::NodeType::NODE_OUT) { if(!node->IsConnected()) { inputVector.push_back(1.0); } else { diff --git a/Project/OpenGLText.cpp b/Project/OpenGLText.cpp index 5e1c40b..0dca4eb 100644 --- a/Project/OpenGLText.cpp +++ b/Project/OpenGLText.cpp @@ -16,7 +16,9 @@ */ #include <wx/log.h> +#include <wx/graphics.h> #include "OpenGLText.h" +#include <algorithm> OpenGLText::OpenGLText() { Init(); } OpenGLText::OpenGLText(wxString text) @@ -69,11 +71,40 @@ void OpenGLText::Draw(wxPoint2DDouble position, double angle) const } } +void OpenGLText::DrawDC(wxPoint2DDouble position, wxGraphicsContext* gc, double angle) const +{ + gc->SetFont(wxFont(m_fontSize, m_fontFamily, m_fontStyle, m_fontWeight), wxColour(0, 0 , 0 , 255)); + gc->DrawText(m_text, position.m_x, position.m_y, angle); +} + void OpenGLText::SetText(wxString text) { m_text = text; - TextToBitmap(); - LoadTextTexture(); + bool contextValid = false; +#ifdef __LINUX__ + if(glXGetCurrentContext()) contextValid = true; +#endif +#ifdef __APPLE__ + if(aglGetCurrentContext()) contextValid = true; +#endif +#ifdef __WINDOWS__ + if (wglGetCurrentContext()) contextValid = true; +#endif + + if (contextValid) { + TextToBitmap(); + LoadTextTexture(); + } + else + { + // If the context is not valid, the text still can be rendered using wxDC. + // So, the text size must be calculated + wxFont font = wxFont(m_fontSize, m_fontFamily, m_fontStyle, m_fontWeight); + + wxMemoryDC memDC; + memDC.SetFont(font); + m_bitmapSize = memDC.GetTextExtent(m_text); + } } int OpenGLText::RoundToPowerOfTwo(int value, int min) @@ -81,7 +112,8 @@ int OpenGLText::RoundToPowerOfTwo(int value, int min) //[Ref] https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2 double baseOfTwo = std::log(static_cast<double>(value)) / std::log(2.0); int powerOfTwo = static_cast<int>(std::pow(2.0, static_cast<int>(std::ceil(baseOfTwo)))); - return std::max(min, powerOfTwo); + //return std::max(min, powerOfTwo); + return min > powerOfTwo ? min : powerOfTwo; } void OpenGLText::TextToBitmap() diff --git a/Project/OpenGLText.h b/Project/OpenGLText.h index 5417ad3..885782e 100644 --- a/Project/OpenGLText.h +++ b/Project/OpenGLText.h @@ -18,8 +18,10 @@ #ifndef OPENGLTEXT_H #define OPENGLTEXT_H +#include <windows.h> #include <GL/gl.h> #include <wx/dcmemory.h> +#include <algorithm> /** * @class OpenGLText @@ -36,6 +38,7 @@ class OpenGLText virtual ~OpenGLText(); virtual void Draw(wxPoint2DDouble position, double angle = 0.0) const; + virtual void DrawDC(wxPoint2DDouble position, wxGraphicsContext* gc, double angle = 0.0) const; virtual OpenGLText* GetCopy(); virtual void SetText(wxString text); @@ -54,6 +57,7 @@ class OpenGLText void TextToBitmap(); void LoadTextTexture(); + wxString m_text = _("Text"); int m_fontSize = 10; wxFontWeight m_fontWeight = wxFONTWEIGHT_NORMAL; diff --git a/Project/PowerElement.cpp b/Project/PowerElement.cpp index 326c1c8..870a30e 100644 --- a/Project/PowerElement.cpp +++ b/Project/PowerElement.cpp @@ -19,6 +19,7 @@ #ifdef USING_WX_3_0_X #include "DegreesAndRadians.h" #endif +#include <wx/brush.h> PowerElement::PowerElement() : Element() { @@ -107,6 +108,36 @@ void PowerElement::DrawSwitches() const } } +void PowerElement::DrawDCSwitches(wxGraphicsContext* gc) const +{ + gc->SetPen(*wxTRANSPARENT_PEN); + + int i = 0; + for (auto parent : m_parentList) { + if (parent) { + if (m_online) { + gc->SetBrush(wxBrush(wxColour(m_closedSwitchColour.GetDcRGBA()))); + } + else { + gc->SetBrush(wxBrush(wxColour(m_openedSwitchColour.GetDcRGBA()))); + } + + gc->PushState(); + gc->Translate(m_switchRect[i].GetPosition().m_x + m_switchSize / 2.0, + m_switchRect[i].GetPosition().m_y + m_switchSize / 2.0); + gc->Rotate(wxDegToRad(parent->GetAngle())); + gc->Translate(-m_switchRect[i].GetPosition().m_x - m_switchSize / 2.0, + -m_switchRect[i].GetPosition().m_y - m_switchSize / 2.0); + + wxPoint2DDouble switchPos = m_switchRect[i].GetPosition(); + gc->DrawRectangle(switchPos.m_x, switchPos.m_y, m_switchSize, m_switchSize); + + gc->PopState(); + } + i++; + } +} + void PowerElement::CalculatePowerFlowPts(std::vector<wxPoint2DDouble> edges) { double arrowRate = 100.0; // One arrow to each "arrowRate" distance in pixels. @@ -159,6 +190,15 @@ void PowerElement::DrawPowerFlowPts() const } } +void PowerElement::DrawDCPowerFlowPts(wxGraphicsContext* gc) const +{ + gc->SetPen(*wxTRANSPARENT_PEN); + if (m_online) { + gc->SetBrush(wxBrush(wxColour(m_powerFlowArrowColour.GetDcRGBA()))); + for (auto arrow : m_powerFlowArrow) { DrawDCTriangle(arrow, gc); } + } +} + double PowerElement::GetValueFromUnit(double value, ElectricalUnit valueUnit) { switch(valueUnit) { diff --git a/Project/PowerElement.h b/Project/PowerElement.h index 031834e..2a106cb 100644 --- a/Project/PowerElement.h +++ b/Project/PowerElement.h @@ -158,6 +158,11 @@ class PowerElement : public Element virtual void DrawSwitches() const; /** + * @brief Draw switch using device context. + */ + virtual void DrawDCSwitches(wxGraphicsContext* gc) const; + + /** * @brief Calculate the points of the power flow arrows. * @param edges Points of the element that arrows point. */ @@ -169,6 +174,12 @@ class PowerElement : public Element virtual void DrawPowerFlowPts() const; /** + * @brief Draw power flow arrows using device context. + * @param gc Device context. + */ + virtual void DrawDCPowerFlowPts(wxGraphicsContext* gc) const; + + /** * @brief Set nominal voltage of the element. * @param nominalVoltage Value of the nominal voltage. * @param nominalVoltageUnit Unit of the nominal voltage. diff --git a/Project/PowerQuality.cpp b/Project/PowerQuality.cpp index c8fcd91..6478132 100644 --- a/Project/PowerQuality.cpp +++ b/Project/PowerQuality.cpp @@ -183,7 +183,7 @@ bool PowerQuality::CalculateDistortions(double systemPowerBase) // Bus voltage double voltage = busData.nominalVoltage; - if(busData.nominalVoltageUnit == UNIT_kV) voltage *= 1e3; + if(busData.nominalVoltageUnit == ElectricalUnit::UNIT_kV) voltage *= 1e3; auto puData = harmCurrent->GetPUElectricalData(systemPowerBase, voltage); diff --git a/Project/Project.project b/Project/Project.project index 82b109b..25c00fe 100644 --- a/Project/Project.project +++ b/Project/Project.project @@ -118,6 +118,7 @@ </VirtualDirectory> </VirtualDirectory> <VirtualDirectory Name="main GUI"> + <File Name="WorkspaceDC.cpp"/> <File Name="Camera.cpp"/> <File Name="MainFrame.cpp"/> <File Name="Workspace.cpp"/> @@ -251,6 +252,7 @@ </VirtualDirectory> </VirtualDirectory> <VirtualDirectory Name="main GUI"> + <File Name="WorkspaceDC.h"/> <File Name="Camera.h"/> <File Name="MainFrame.h"/> <File Name="Workspace.h"/> diff --git a/Project/PropertiesData.h b/Project/PropertiesData.h index 588cc00..b8361fe 100644 --- a/Project/PropertiesData.h +++ b/Project/PropertiesData.h @@ -28,7 +28,7 @@ enum GUITheme { THEME_LIGHT = 0, THEME_DARK }; struct SimulationData { // General simulation data double basePower = 100.0; - ElectricalUnit basePowerUnit = UNIT_MVA; + ElectricalUnit basePowerUnit = ElectricalUnit::UNIT_MVA; bool faultAfterPowerFlow = false; bool scPowerAfterPowerFlow = false; bool harmDistortionAfterPowerFlow = false; @@ -42,7 +42,7 @@ struct SimulationData { double newtonInertia = 1.0; double gaussTolerance = 1e-2; - // Stability + // stability double stabilityFrequency = 60.0; double timeStep = 1e-2; double stabilitySimulationTime = 10.0; @@ -67,6 +67,7 @@ struct SimulationData { struct GeneralData { wxLanguage language = wxLANGUAGE_ENGLISH; GUITheme theme = THEME_LIGHT; + bool useOpenGL = true; }; struct FreqResponseData { diff --git a/Project/PropertiesForm.wxcp b/Project/PropertiesForm.wxcp index 63265ec..367e85e 100644 --- a/Project/PropertiesForm.wxcp +++ b/Project/PropertiesForm.wxcp @@ -3727,7 +3727,7 @@ }, { "type": "string", "m_label": "Label:", - "m_value": "Stability" + "m_value": "stability" }, { "type": "bitmapPicker", "m_label": "Bitmap File:", diff --git a/Project/RateLimiter.cpp b/Project/RateLimiter.cpp index dedd910..94b61ac 100644 --- a/Project/RateLimiter.cpp +++ b/Project/RateLimiter.cpp @@ -21,9 +21,9 @@ RateLimiter::RateLimiter(int id) : ControlElement(id) { m_width = m_height = 36.0; - Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize); + Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NodeType::NODE_IN, m_borderSize); nodeIn->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn); diff --git a/Project/ReactiveShuntElementForm.cpp b/Project/ReactiveShuntElementForm.cpp index 985127d..aceba3e 100644 --- a/Project/ReactiveShuntElementForm.cpp +++ b/Project/ReactiveShuntElementForm.cpp @@ -30,16 +30,16 @@ ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Capacitor* m_textCtrlReactivePower->SetValue(Capacitor::StringFromDouble(data.reactivePower)); switch(data.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceReactivePower->SetSelection(0); } break; - case UNIT_VAr: { + case ElectricalUnit::UNIT_VAr: { m_choiceReactivePower->SetSelection(1); } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { m_choiceReactivePower->SetSelection(2); } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { m_choiceReactivePower->SetSelection(3); } break; default: @@ -59,16 +59,16 @@ ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Inductor* i m_textCtrlReactivePower->SetValue(Inductor::StringFromDouble(data.reactivePower)); switch(data.reactivePowerUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceReactivePower->SetSelection(0); } break; - case UNIT_VAr: { + case ElectricalUnit::UNIT_VAr: { m_choiceReactivePower->SetSelection(1); } break; - case UNIT_kVAr: { + case ElectricalUnit::UNIT_kVAr: { m_choiceReactivePower->SetSelection(2); } break; - case UNIT_MVAr: { + case ElectricalUnit::UNIT_MVAr: { m_choiceReactivePower->SetSelection(3); } break; default: @@ -114,16 +114,16 @@ bool ReactiveShuntElementForm::ValidateData() return false; switch(m_choiceReactivePower->GetSelection()) { case 0: { - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.reactivePowerUnit = UNIT_VAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_VAr; } break; case 2: { - data.reactivePowerUnit = UNIT_kVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_kVAr; } break; case 3: { - data.reactivePowerUnit = UNIT_MVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_MVAr; } break; } @@ -138,16 +138,16 @@ bool ReactiveShuntElementForm::ValidateData() return false; switch(m_choiceReactivePower->GetSelection()) { case 0: { - data.reactivePowerUnit = UNIT_PU; + data.reactivePowerUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.reactivePowerUnit = UNIT_VAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_VAr; } break; case 2: { - data.reactivePowerUnit = UNIT_kVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_kVAr; } break; case 3: { - data.reactivePowerUnit = UNIT_MVAr; + data.reactivePowerUnit = ElectricalUnit::UNIT_MVAr; } break; } diff --git a/Project/Shunt.cpp b/Project/Shunt.cpp index 63def85..0522457 100644 --- a/Project/Shunt.cpp +++ b/Project/Shunt.cpp @@ -165,18 +165,36 @@ void Shunt::DrawGround(wxPoint2DDouble position) const DrawLine(groundPts, GL_LINES); } +void Shunt::DrawDCGround(wxPoint2DDouble position, wxGraphicsContext* gc) const +{ + std::vector<wxPoint2DDouble> groundPts; + groundPts.push_back(position); + groundPts.push_back(position + wxPoint2DDouble(0, 10)); + groundPts.push_back(position + wxPoint2DDouble(-10, 10)); + groundPts.push_back(position + wxPoint2DDouble(10, 10)); + groundPts.push_back(position + wxPoint2DDouble(-6, 15)); + groundPts.push_back(position + wxPoint2DDouble(6, 15)); + groundPts.push_back(position + wxPoint2DDouble(-3, 20)); + groundPts.push_back(position + wxPoint2DDouble(3, 20)); + + gc->DrawLines(2, &groundPts[0]); + gc->DrawLines(2, &groundPts[2]); + gc->DrawLines(2, &groundPts[4]); + gc->DrawLines(2, &groundPts[6]); +} + void Shunt::UpdatePowerFlowArrowsPosition() { std::vector<wxPoint2DDouble> edges; switch(m_pfDirection) { - case PF_NONE: { + case PowerFlowDirection::PF_NONE: { m_powerFlowArrow.clear(); } break; - case PF_TO_BUS: { + case PowerFlowDirection::PF_TO_BUS: { edges.push_back(m_pointList[2]); edges.push_back(m_pointList[1]); } break; - case PF_TO_ELEMENT: { + case PowerFlowDirection::PF_TO_ELEMENT: { edges.push_back(m_pointList[1]); edges.push_back(m_pointList[2]); } break; diff --git a/Project/Shunt.h b/Project/Shunt.h index 94424a4..20969b1 100644 --- a/Project/Shunt.h +++ b/Project/Shunt.h @@ -49,6 +49,7 @@ class Shunt : public PowerElement void UpdateSwitchesPosition(); void UpdatePowerFlowArrowsPosition(); void DrawGround(wxPoint2DDouble position) const; + void DrawDCGround(wxPoint2DDouble position, wxGraphicsContext* gc) const; bool m_inserted = false; }; diff --git a/Project/SimulationsSettingsForm.cpp b/Project/SimulationsSettingsForm.cpp index 5b3cb1c..6f1c987 100644 --- a/Project/SimulationsSettingsForm.cpp +++ b/Project/SimulationsSettingsForm.cpp @@ -26,13 +26,13 @@ SimulationsSettingsForm::SimulationsSettingsForm(wxWindow* parent, PropertiesDat m_textCtrlbasePower->SetValue(Element::StringFromDouble(data.basePower)); switch(data.basePowerUnit) { - case UNIT_VA: { + case ElectricalUnit::UNIT_VA: { m_choiceBasePower->SetSelection(0); } break; - case UNIT_kVA: { + case ElectricalUnit::UNIT_kVA: { m_choiceBasePower->SetSelection(1); } break; - case UNIT_MVA: { + case ElectricalUnit::UNIT_MVA: { m_choiceBasePower->SetSelection(2); } break; default: { @@ -102,13 +102,13 @@ bool SimulationsSettingsForm::ValidateData() return false; switch(m_choiceBasePower->GetSelection()) { case 0: { - data.basePowerUnit = UNIT_VA; + data.basePowerUnit = ElectricalUnit::UNIT_VA; } break; case 1: { - data.basePowerUnit = UNIT_kVA; + data.basePowerUnit = ElectricalUnit::UNIT_kVA; } break; default: { - data.basePowerUnit = UNIT_MVA; + data.basePowerUnit = ElectricalUnit::UNIT_MVA; } break; } data.faultAfterPowerFlow = m_checkBoxFaultAfterPF->GetValue(); @@ -153,10 +153,10 @@ bool SimulationsSettingsForm::ValidateData() _("Value entered incorrectly in the field \"System frequency\"."))) return false; if(!Element::DoubleFromString(this, m_textCtrlStabTolerance->GetValue(), data.stabilityTolerance, - _("Value entered incorrectly in the field \"Tolerance (Stability)\"."))) + _("Value entered incorrectly in the field \"Tolerance (stability)\"."))) return false; if(!Element::IntFromString(this, m_textCtrlStabMaxIterations->GetValue(), data.stabilityMaxIterations, - _("Value entered incorrectly in the field \"Max. iterations (Stability)\"."))) + _("Value entered incorrectly in the field \"Max. iterations (stability)\"."))) return false; if(!Element::IntFromString(this, m_textCtrlCtrlStepRatio->GetValue(), data.controlTimeStepRatio, _("Value entered incorrectly in the field \"Controls step ratio\"."))) diff --git a/Project/StabilityEventList.cpp b/Project/StabilityEventList.cpp index a0c7922..f976ead 100644 --- a/Project/StabilityEventList.cpp +++ b/Project/StabilityEventList.cpp @@ -148,7 +148,7 @@ void StabilityEventList::SetPowerElementSwitchingEvent(PowerElement* element, wx { SwitchingData swData = element->GetSwitchingData(); for(unsigned int i = 0; i < swData.swTime.size(); ++i) { - if(swData.swType[i] == SW_INSERT) { + if(swData.swType[i] == SwitchingType::SW_INSERT) { AddEvent(swData.swTime[i], _("Switching"), _("Insertion of \"") + elementName + _("\""), m_blueColour); } else { AddEvent(swData.swTime[i], _("Switching"), _("Removal of \"") + elementName + _("\""), m_redColour); diff --git a/Project/Sum.cpp b/Project/Sum.cpp index 9908497..a2235fd 100644 --- a/Project/Sum.cpp +++ b/Project/Sum.cpp @@ -22,12 +22,12 @@ Sum::Sum(int id) : ControlElement(id) { m_width = m_height = 36.0; - Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NODE_IN, m_borderSize); + Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NodeType::NODE_IN, m_borderSize); nodeIn1->StartMove(m_position); Node* nodeIn2 = - new Node(m_position + wxPoint2DDouble(-m_width / 2, 27 - m_height / 2), Node::NODE_IN, m_borderSize); + new Node(m_position + wxPoint2DDouble(-m_width / 2, 27 - m_height / 2), Node::NodeType::NODE_IN, m_borderSize); nodeIn2->StartMove(m_position); - Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize); + Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize); nodeOut->SetAngle(180.0); nodeOut->StartMove(m_position); m_nodeList.push_back(nodeIn1); @@ -154,7 +154,7 @@ void Sum::UpdatePoints() void Sum::AddInNode() { - Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NODE_IN, m_borderSize); + Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NodeType::NODE_IN, m_borderSize); newNode->SetAngle(m_angle); m_nodeList.insert(m_nodeList.end() - 1, newNode); } @@ -208,7 +208,7 @@ bool Sum::Solve(double* input, double timeStep) std::vector<double> inputVector; for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) { Node* node = *itN; - if(node->GetNodeType() != Node::NODE_OUT) { + if(node->GetNodeType() != Node::NodeType::NODE_OUT) { if(!node->IsConnected()) { inputVector.push_back(0.0); } else { diff --git a/Project/SwitchingForm.cpp b/Project/SwitchingForm.cpp index 8a52553..8b3a5fd 100644 --- a/Project/SwitchingForm.cpp +++ b/Project/SwitchingForm.cpp @@ -37,7 +37,7 @@ SwitchingForm::SwitchingForm(wxWindow* parent, PowerElement* element) : Switchin SwitchingData data = element->GetSwitchingData(); for(int i = 0; i < (int)data.swType.size(); i++) { - long index = m_listCtrlSwitchings->InsertItem(m_maxID, data.swType[i] == SW_INSERT ? _("Insert") : _("Remove")); + long index = m_listCtrlSwitchings->InsertItem(m_maxID, data.swType[i] == SwitchingType::SW_INSERT ? _("Insert") : _("Remove")); m_listCtrlSwitchings->SetItem(index, 1, wxString::FromDouble(data.swTime[i])); m_maxID++; } @@ -67,9 +67,9 @@ void SwitchingForm::OnOKButtonClick(wxCommandEvent& event) SwitchingData data; for(int i = 0; i < (int)itemList.size(); i++) { if(m_listCtrlSwitchings->GetItemText(itemList[i], 0) == _("Insert")) - data.swType.push_back(SW_INSERT); + data.swType.push_back(SwitchingType::SW_INSERT); else - data.swType.push_back(SW_REMOVE); + data.swType.push_back(SwitchingType::SW_REMOVE); double swTime; m_listCtrlSwitchings->GetItemText(itemList[i], 1).ToDouble(&swTime); diff --git a/Project/SyncGenerator.cpp b/Project/SyncGenerator.cpp index 78082d2..49571ac 100644 --- a/Project/SyncGenerator.cpp +++ b/Project/SyncGenerator.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#include "Workspace.h" #include "ControlElementContainer.h" #include "SyncGenerator.h" #include "SyncMachineForm.h" @@ -51,6 +52,15 @@ void SyncGenerator::DrawSymbol() const for(int i = 0; i < (int)m_sinePts.size(); i++) { sinePts.push_back(m_sinePts[i] + m_position); } DrawLine(sinePts); } + +void SyncGenerator::DrawDCSymbol(wxGraphicsContext* gc) const +{ + // Draw sine. + std::vector<wxPoint2DDouble> sinePts; + for (unsigned int i = 0; i < m_sinePts.size(); i++) { sinePts.push_back(m_sinePts[i] + m_position); } + gc->DrawLines(sinePts.size(), &sinePts[0]); +} + bool SyncGenerator::GetContextMenu(wxMenu& menu) { menu.Append(ID_EDIT_ELEMENT, _("Edit Generator")); @@ -60,7 +70,8 @@ bool SyncGenerator::GetContextMenu(wxMenu& menu) bool SyncGenerator::ShowForm(wxWindow* parent, Element* element) { - SyncMachineForm* generatorForm = new SyncMachineForm(parent, this); + Workspace* ws = static_cast<Workspace*>(parent); + SyncMachineForm* generatorForm = new SyncMachineForm(parent, this, ws->GetSharedGLContext()); generatorForm->SetTitle(_("Generator")); if(generatorForm->ShowModal() == wxID_OK) { generatorForm->Destroy(); diff --git a/Project/SyncGenerator.h b/Project/SyncGenerator.h index 1a25a0e..e696ca4 100644 --- a/Project/SyncGenerator.h +++ b/Project/SyncGenerator.h @@ -148,6 +148,7 @@ class SyncGenerator : public Machines virtual Element* GetCopy(); virtual void Init(); virtual void DrawSymbol() const; + virtual void DrawDCSymbol(wxGraphicsContext* gc) const; virtual bool GetContextMenu(wxMenu& menu); virtual bool ShowForm(wxWindow* parent, Element* element); virtual wxString GetTipText() const; diff --git a/Project/SyncMachineForm.cpp b/Project/SyncMachineForm.cpp index 486a043..3c27a7c 100644 --- a/Project/SyncMachineForm.cpp +++ b/Project/SyncMachineForm.cpp @@ -20,7 +20,7 @@ #include "SyncGenerator.h" #include "SyncMotor.h" -SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator) : SyncMachineFormBase(parent) +SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator, wxGLContext* sharedGLContext) : SyncMachineFormBase(parent) { SetSize(GetBestSize()); ReplaceStaticTextLabelChar(m_staticTextPosResistance, L'\u2081'); @@ -32,6 +32,7 @@ SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator) Layout(); m_syncGenerator = syncGenerator; m_parent = parent; + m_sharedGLContext = sharedGLContext; SyncGeneratorElectricalData data = syncGenerator->GetElectricalData(); @@ -286,7 +287,7 @@ void SyncMachineForm::OnStabilityButtonClick(wxCommandEvent& event) { if(ValidateData()) { if(m_syncGenerator) { - GeneratorStabForm* stabForm = new GeneratorStabForm(m_parent, m_syncGenerator); + GeneratorStabForm* stabForm = new GeneratorStabForm(m_parent, m_syncGenerator, m_sharedGLContext); if(stabForm->ShowModal() == wxID_OK) { stabForm->Destroy(); EndModal(wxID_OK); diff --git a/Project/SyncMachineForm.h b/Project/SyncMachineForm.h index 793ca79..421a975 100644 --- a/Project/SyncMachineForm.h +++ b/Project/SyncMachineForm.h @@ -17,6 +17,7 @@ #ifndef SYNCMACHINEFORM_H #define SYNCMACHINEFORM_H +#include <wx/glcanvas.h> #include "ElementFormBase.h" @@ -34,7 +35,7 @@ class SyncMotor; class SyncMachineForm : public SyncMachineFormBase { public: - SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator); + SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator, wxGLContext* sharedGLContext); SyncMachineForm(wxWindow* parent, SyncMotor* syncMotor); virtual ~SyncMachineForm(); @@ -44,6 +45,7 @@ class SyncMachineForm : public SyncMachineFormBase virtual void OnCheckMinReactive(wxCommandEvent& event); virtual void OnOKButtonClick(wxCommandEvent& event); virtual void OnStabilityButtonClick(wxCommandEvent& event); + wxGLContext* GetSharedGLContext() const { return m_sharedGLContext; } virtual bool ValidateData(); virtual void ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar); @@ -51,5 +53,6 @@ class SyncMachineForm : public SyncMachineFormBase SyncGenerator* m_syncGenerator = NULL; SyncMotor* m_syncMotor = NULL; wxWindow* m_parent = NULL; + wxGLContext* m_sharedGLContext = NULL; }; #endif // SYNCMACHINEFORM_H diff --git a/Project/SyncMotor.cpp b/Project/SyncMotor.cpp index 8283a25..716a432 100644 --- a/Project/SyncMotor.cpp +++ b/Project/SyncMotor.cpp @@ -22,6 +22,10 @@ SyncMotor::SyncMotor() : Machines() {} SyncMotor::SyncMotor(wxString name) : Machines() { m_electricalData.name = name; } SyncMotor::~SyncMotor() {} void SyncMotor::DrawSymbol() const { DrawArc(m_position, 12, 30, 330, 10, GL_LINE_STRIP); } +void SyncMotor::DrawDCSymbol(wxGraphicsContext* gc) const +{ + DrawDCArc(m_position, 12, 30, 330, 10, gc); +} bool SyncMotor::GetContextMenu(wxMenu& menu) { menu.Append(ID_EDIT_ELEMENT, _("Edit Synchronous Condenser")); diff --git a/Project/SyncMotor.h b/Project/SyncMotor.h index 772ef7b..694aa90 100644 --- a/Project/SyncMotor.h +++ b/Project/SyncMotor.h @@ -140,6 +140,7 @@ class SyncMotor : public Machines virtual Element* GetCopy(); virtual void DrawSymbol() const; + virtual void DrawDCSymbol(wxGraphicsContext* gc) const; virtual bool GetContextMenu(wxMenu& menu); virtual wxString GetTipText() const; virtual SyncMotorElectricalData GetElectricalData() { return m_electricalData; } diff --git a/Project/Text.cpp b/Project/Text.cpp index f73b425..3a22c7a 100644 --- a/Project/Text.cpp +++ b/Project/Text.cpp @@ -79,6 +79,42 @@ void Text::Draw(wxPoint2DDouble translation, double scale) glPopMatrix(); } +void Text::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) +{ + // Draw selection rectangle + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + if (m_selected) { + glColor4d(0.0, 0.5, 1.0, 0.5); + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(0, 125, 255, 125))); + wxPoint2DDouble pos = m_position - wxPoint2DDouble(m_borderSize / 2.0 + m_width / 2, m_borderSize / 2.0 + m_height / 2); + gc->DrawRectangle(pos.m_x, pos.m_y, m_rect.m_width, m_rect.m_height); + } + + // Draw text (layer 2) + //gc->SetPen(wxPen(wxColour(0, 0, 0, 255))); + //gc->SetBrush(*wxTRANSPARENT_BRUSH); + wxPoint2DDouble pos = m_position - wxPoint2DDouble(m_width / 2, m_height / 2); + if (m_isMultlineText) { + for (unsigned int i = 0; i < m_openGLTextList.size(); ++i) { + m_openGLTextList[i]->DrawDC( + pos + + wxPoint2DDouble(0.0, (m_height * static_cast<double>(i) / static_cast<double>(m_numberOfLines))), gc); + } + } + else if (m_openGLTextList.size() > 0) { + m_openGLTextList[0]->DrawDC(pos, gc); + } + gc->PopState(); +} + bool Text::Intersects(wxRect2DDouble rect) const { if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect); diff --git a/Project/Text.h b/Project/Text.h index 19e3876..2f4c0ff 100644 --- a/Project/Text.h +++ b/Project/Text.h @@ -18,6 +18,7 @@ #ifndef TEXT_H #define TEXT_H +#include <windows.h> #include <GL/gl.h> #include <wx/dcmemory.h> @@ -86,6 +87,7 @@ class Text : public GraphicalElement virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return true; }; virtual bool Contains(wxPoint2DDouble position) const; virtual void Draw(wxPoint2DDouble translation, double scale); + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc); virtual bool Intersects(wxRect2DDouble rect) const; virtual void Rotate(bool clockwise = true); virtual bool ShowForm(wxWindow* parent, std::vector<Element*> elementList); diff --git a/Project/TransferFunction.cpp b/Project/TransferFunction.cpp index b78d74a..e650ca6 100644 --- a/Project/TransferFunction.cpp +++ b/Project/TransferFunction.cpp @@ -39,9 +39,9 @@ TransferFunction::TransferFunction(int id) : ControlElement(id) m_denominator.push_back(1); UpdateTFText(); - Node* node1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize); + Node* node1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NodeType::NODE_IN, m_borderSize); node1->StartMove(m_position); - Node* node2 = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize); + Node* node2 = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NodeType::NODE_OUT, m_borderSize); node2->SetAngle(180.0); node2->StartMove(m_position); m_nodeList.push_back(node1); diff --git a/Project/Transformer.cpp b/Project/Transformer.cpp index 024a851..bd212d7 100644 --- a/Project/Transformer.cpp +++ b/Project/Transformer.cpp @@ -179,6 +179,92 @@ void Transformer::Draw(wxPoint2DDouble translation, double scale) const } } +void Transformer::DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const +{ + OpenGLColour elementColour; + if (m_online) { + if (m_dynEvent) + elementColour = m_dynamicEventColour; + else + elementColour = m_onlineElementColour; + } + else + elementColour = m_offlineElementColour; + + if (m_inserted) { + // Draw selection (layer 1). + if (m_selected) { + gc->SetPen(wxPen(wxColour(m_selectionColour.GetDcRGBA()), 2 + m_borderSize * 2.0)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20, gc); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20, gc); + + gc->PopState(); + + // Draw nodes selection. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(m_selectionColour.GetDcRGBA()))); + if (m_pointList.size() > 0) { + DrawDCCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, gc); + if (m_inserted) { DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0 + m_borderSize / scale, 10, gc); } + } + } + + // Draw transformer (layer 2). + // Transformer line + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + gc->DrawLines(m_pointList.size(), &m_pointList[0]); + + // Draw nodes. + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + if (m_pointList.size() > 0) { + DrawDCCircle(m_pointList[0], 5.0, 10, gc); + if (m_inserted) { DrawDCCircle(m_pointList[m_pointList.size() - 1], 5.0, 10, gc); } + } + + DrawDCSwitches(gc); + DrawDCPowerFlowPts(gc); + + // Push the current matrix on stack. + gc->PushState(); + // Rotate the matrix around the object position. + gc->Translate(m_position.m_x, m_position.m_y); + gc->Rotate(wxDegToRad(m_angle)); + gc->Translate(-m_position.m_x, -m_position.m_y); + + glColor4d(1.0, 1.0, 1.0, 1.0); + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(*wxWHITE_BRUSH); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, gc); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, gc); + + gc->SetPen(wxPen(wxColour(elementColour.GetDcRGBA()), 2)); + gc->SetBrush(*wxTRANSPARENT_BRUSH); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, gc); + DrawDCCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, gc); + + // Point + gc->SetPen(*wxTRANSPARENT_PEN); + gc->SetBrush(wxBrush(wxColour(elementColour.GetDcRGBA()))); + DrawDCCircle(m_rect.GetPosition(), 4, 10, gc); + + gc->PopState(); + } +} + bool Transformer::Intersects(wxRect2DDouble rect) const { if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect); diff --git a/Project/Transformer.h b/Project/Transformer.h index 46dfe77..207f6d1 100644 --- a/Project/Transformer.h +++ b/Project/Transformer.h @@ -86,6 +86,7 @@ class Transformer : public Branch virtual bool AddParent(Element* parent, wxPoint2DDouble position); virtual bool Contains(wxPoint2DDouble position) const; virtual void Draw(wxPoint2DDouble translation, double scale) const; + virtual void DrawDC(wxPoint2DDouble translation, double scale, wxGraphicsContext* gc) const; virtual bool Intersects(wxRect2DDouble rect) const; virtual void Rotate(bool clockwise = true); virtual void Move(wxPoint2DDouble position); diff --git a/Project/TransformerForm.cpp b/Project/TransformerForm.cpp index 7c921c4..a41d1bd 100644 --- a/Project/TransformerForm.cpp +++ b/Project/TransformerForm.cpp @@ -47,10 +47,10 @@ TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : T wxString primVoltStr = Transformer::StringFromDouble(data.primaryNominalVoltage); switch(data.primaryNominalVoltageUnit) { - case UNIT_V: { + case ElectricalUnit::UNIT_V: { primVoltStr += " V"; } break; - case UNIT_kV: { + case ElectricalUnit::UNIT_kV: { primVoltStr += " kV"; } break; default: @@ -58,10 +58,10 @@ TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : T } wxString secVoltStr = Transformer::StringFromDouble(data.secondaryNominalVoltage); switch(data.secondaryNominalVoltageUnit) { - case UNIT_V: { + case ElectricalUnit::UNIT_V: { secVoltStr += " V"; } break; - case UNIT_kV: { + case ElectricalUnit::UNIT_kV: { secVoltStr += " kV"; } break; default: @@ -75,13 +75,13 @@ TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : T m_textCtrlNominalPower->SetValue(Transformer::StringFromDouble(data.nominalPower)); switch(data.nominalPowerUnit) { - case UNIT_VA: { + case ElectricalUnit::UNIT_VA: { m_choiceNominalPower->SetSelection(0); } break; - case UNIT_kVA: { + case ElectricalUnit::UNIT_kVA: { m_choiceNominalPower->SetSelection(1); } break; - case UNIT_MVA: { + case ElectricalUnit::UNIT_MVA: { m_choiceNominalPower->SetSelection(2); } break; default: @@ -90,10 +90,10 @@ TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : T m_textCtrlResistance->SetValue(Transformer::StringFromDouble(data.resistance)); switch(data.resistanceUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceResistance->SetSelection(0); } break; - case UNIT_OHM: { + case ElectricalUnit::UNIT_OHM: { m_choiceResistance->SetSelection(1); } break; default: @@ -102,10 +102,10 @@ TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : T m_textCtrlReactance->SetValue(Transformer::StringFromDouble(data.indReactance)); switch(data.indReactanceUnit) { - case UNIT_PU: { + case ElectricalUnit::UNIT_PU: { m_choiceReactance->SetSelection(0); } break; - case UNIT_OHM: { + case ElectricalUnit::UNIT_OHM: { m_choiceReactance->SetSelection(1); } break; default: @@ -155,13 +155,13 @@ bool TransformerForm::ValidateData() return false; switch(m_choiceNominalPower->GetSelection()) { case 0: { - data.nominalPowerUnit = UNIT_VA; + data.nominalPowerUnit = ElectricalUnit::UNIT_VA; } break; case 1: { - data.nominalPowerUnit = UNIT_kVA; + data.nominalPowerUnit = ElectricalUnit::UNIT_kVA; } break; case 2: { - data.nominalPowerUnit = UNIT_MVA; + data.nominalPowerUnit = ElectricalUnit::UNIT_MVA; } break; } @@ -170,10 +170,10 @@ bool TransformerForm::ValidateData() return false; switch(m_choiceResistance->GetSelection()) { case 0: { - data.resistanceUnit = UNIT_PU; + data.resistanceUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.resistanceUnit = UNIT_OHM; + data.resistanceUnit = ElectricalUnit::UNIT_OHM; } break; } @@ -182,10 +182,10 @@ bool TransformerForm::ValidateData() return false; switch(m_choiceReactance->GetSelection()) { case 0: { - data.indReactanceUnit = UNIT_PU; + data.indReactanceUnit = ElectricalUnit::UNIT_PU; } break; case 1: { - data.indReactanceUnit = UNIT_OHM; + data.indReactanceUnit = ElectricalUnit::UNIT_OHM; } break; } diff --git a/Project/Workspace.cpp b/Project/Workspace.cpp index 82989b5..9cd1bb6 100644 --- a/Project/Workspace.cpp +++ b/Project/Workspace.cpp @@ -83,13 +83,13 @@ void Workspace::OnPaint(wxPaintEvent& event) if(!m_glCanvas->IsShown()) return; wxPaintDC dc(m_glCanvas); + m_glContext->SetCurrent(*m_glCanvas); SetViewport(); // Set GLCanvas scale and translation. glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation - // Draw // Elements @@ -122,6 +122,7 @@ void Workspace::OnPaint(wxPaintEvent& event) glEnd(); glFlush(); // Sends all pending information directly to the GPU. + m_glCanvas->SwapBuffers(); event.Skip(); } @@ -983,7 +984,7 @@ void Workspace::RotateSelectedElements(bool clockwise) void Workspace::DeleteSelectedElements() { // Don't set the end of the list at the loop's begin. - for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) { + for(auto it = m_elementList.begin(); it != m_elementList.end();) { Element* element = *it; if(element->IsSelected()) { @@ -1010,9 +1011,10 @@ void Workspace::DeleteSelectedElements() } } - m_elementList.erase(it--); + it = m_elementList.erase(it); if(element) delete element; } + else it++; } for(auto it = m_textList.begin(); it != m_textList.end(); ++it) { diff --git a/Project/Workspace.h b/Project/Workspace.h index a48ad4e..3ac9b3a 100644 --- a/Project/Workspace.h +++ b/Project/Workspace.h @@ -18,6 +18,7 @@ #ifndef WORKSPACE_H #define WORKSPACE_H +#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <wx/dcclient.h> @@ -103,7 +104,7 @@ class Workspace : public WorkspaceBase Workspace(); Workspace(wxWindow* parent, wxString name = wxEmptyString, wxStatusBar* statusBar = NULL, wxGLContext* sharedGLContext = NULL); - ~Workspace(); + virtual ~Workspace(); wxString GetName() const { return m_name; } std::vector<Element*> GetElementList() const; @@ -122,8 +123,8 @@ class Workspace : public WorkspaceBase void SetWorkspaceMode(WorkspaceMode mode) { m_mode = mode; } void SetSavedPath(wxFileName savedPath) { m_savedPath = savedPath; } void SetJustOpened(bool justOpened) { m_justOpened = justOpened; } - void Redraw() { m_glCanvas->Refresh(); } - wxGLContext* GetOpenGLContext() { return m_glContext; } + virtual void Redraw() { m_glCanvas->Refresh(); } + wxGLContext* GetSharedGLContext() const { return m_glContext; } void RotateSelectedElements(bool clockwise = true); void DeleteSelectedElements(); bool GetElementsCorners(wxPoint2DDouble& leftUpCorner, @@ -152,22 +153,23 @@ class Workspace : public WorkspaceBase bool RunHarmonicDistortion(); bool RunFrequencyResponse(); - protected: - virtual void OnMiddleDoubleClick(wxMouseEvent& event); - virtual void OnIdle(wxIdleEvent& event); - virtual void OnTimer(wxTimerEvent& event); - virtual void OnLeftDoubleClick(wxMouseEvent& event); - virtual void OnRightClickDown(wxMouseEvent& event); - virtual void OnLeftClickUp(wxMouseEvent& event); - virtual void OnScroll(wxMouseEvent& event); - virtual void OnMiddleDown(wxMouseEvent& event); - virtual void OnMiddleUp(wxMouseEvent& event); - virtual void OnMouseMotion(wxMouseEvent& event); - virtual void OnKeyDown(wxKeyEvent& event); - virtual void OnLeftClickDown(wxMouseEvent& event); - virtual void OnPaint(wxPaintEvent& event); - virtual void OnPopupClick(wxCommandEvent& event); - + + virtual void OnMiddleDoubleClick(wxMouseEvent& event); + virtual void OnIdle(wxIdleEvent& event); + virtual void OnTimer(wxTimerEvent& event); + virtual void OnLeftDoubleClick(wxMouseEvent& event); + virtual void OnRightClickDown(wxMouseEvent& event); + virtual void OnLeftClickUp(wxMouseEvent& event); + virtual void OnScroll(wxMouseEvent& event); + virtual void OnMiddleDown(wxMouseEvent& event); + virtual void OnMiddleUp(wxMouseEvent& event); + virtual void OnMouseMotion(wxMouseEvent& event); + virtual void OnKeyDown(wxKeyEvent& event); + virtual void OnLeftClickDown(wxMouseEvent& event); + virtual void OnPaint(wxPaintEvent& event); + virtual void OnPopupClick(wxCommandEvent& event); + +protected: void SetViewport(); void UpdateStatusBar(); diff --git a/Project/WorkspaceDC.cpp b/Project/WorkspaceDC.cpp new file mode 100644 index 0000000..947b248 --- /dev/null +++ b/Project/WorkspaceDC.cpp @@ -0,0 +1,136 @@ +#include "WorkspaceDC.h" + +#include "Camera.h" +#include "Element.h" +#include "Workspace.h" +//#include "Bus.h" +#include "Capacitor.h" +#include "ElementDataObject.h" +#include "HarmCurrent.h" +#include "IndMotor.h" +#include "Inductor.h" +#include "Line.h" +#include "Load.h" +#include "SyncGenerator.h" +#include "SyncMotor.h" +#include "Transformer.h" + +#include "Text.h" + +#include "Electromechanical.h" +#include "Fault.h" +#include "PowerFlow.h" +#include "PowerQuality.h" + +#include "ChartView.h" +#include "ElementPlotData.h" + +#include "PropertiesData.h" + +#include "FrequencyResponseForm.h" + +WorkspaceDC::WorkspaceDC() +{ +} + +WorkspaceDC::WorkspaceDC(wxWindow* parent, wxString name, wxStatusBar* statusBar) : Workspace(parent, name, statusBar, nullptr) +{ + // Disconnect events from GLCanvas + m_glCanvas->Disconnect(wxEVT_PAINT, wxPaintEventHandler(Workspace::OnPaint), NULL, this); + m_glCanvas->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(Workspace::OnLeftClickDown), NULL, this); + m_glCanvas->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(Workspace::OnKeyDown), NULL, this); + m_glCanvas->Disconnect(wxEVT_MOTION, wxMouseEventHandler(Workspace::OnMouseMotion), NULL, this); + m_glCanvas->Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(Workspace::OnMiddleDown), NULL, this); + m_glCanvas->Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(Workspace::OnMiddleUp), NULL, this); + m_glCanvas->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(Workspace::OnLeftClickUp), NULL, this); + m_glCanvas->Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(Workspace::OnScroll), NULL, this); + m_glCanvas->Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(Workspace::OnRightClickDown), NULL, this); + m_glCanvas->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(Workspace::OnLeftDoubleClick), NULL, this); + m_glCanvas->Disconnect(wxEVT_IDLE, wxIdleEventHandler(Workspace::OnIdle), NULL, this); + m_glCanvas->Disconnect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(Workspace::OnMiddleDoubleClick), NULL, this); + + // Reconnect events to this + this->Connect(wxEVT_PAINT, wxPaintEventHandler(WorkspaceDC::OnPaint), NULL, this); // Connect to overloaded method + this->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(Workspace::OnLeftClickDown), NULL, this); + this->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(Workspace::OnKeyDown), NULL, this); + this->Connect(wxEVT_MOTION, wxMouseEventHandler(Workspace::OnMouseMotion), NULL, this); + this->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(Workspace::OnMiddleDown), NULL, this); + this->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(Workspace::OnMiddleUp), NULL, this); + this->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(Workspace::OnLeftClickUp), NULL, this); + this->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(Workspace::OnScroll), NULL, this); + this->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(Workspace::OnRightClickDown), NULL, this); + this->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(Workspace::OnLeftDoubleClick), NULL, this); + this->Connect(wxEVT_IDLE, wxIdleEventHandler(WorkspaceDC::OnIdle), NULL, this); // Connect to overloaded method + this->Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(Workspace::OnMiddleDoubleClick), NULL, this); + + this->GetSizer()->Remove(this->GetSizer()->GetChildren()[0]->GetId()); // remove m_glCanvas object from sizer + + //for (int i = 0; i < this->GetSizer()->GetChildren().GetCount(); ++i) { + //wxMessageBox(wxString::Format("%d", this->GetSizer()->GetChildren()[i]->GetId())); + //} + + delete m_glCanvas; // Delete GLcanvas to allow drawing with wxDC + m_glCanvas = nullptr; + SetBackgroundColour(wxColour(255, 255, 255)); + SetBackgroundStyle(wxBG_STYLE_PAINT); // To allow wxBufferedPaintDC works properly. + Redraw(); +} + +WorkspaceDC::~WorkspaceDC() +{ + // Disconnect events + this->Disconnect(wxEVT_PAINT, wxPaintEventHandler(WorkspaceDC::OnPaint), NULL, this); + this->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(Workspace::OnLeftClickDown), NULL, this); + this->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(Workspace::OnKeyDown), NULL, this); + this->Disconnect(wxEVT_MOTION, wxMouseEventHandler(Workspace::OnMouseMotion), NULL, this); + this->Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(Workspace::OnMiddleDown), NULL, this); + this->Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(Workspace::OnMiddleUp), NULL, this); + this->Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(Workspace::OnLeftClickUp), NULL, this); + this->Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(Workspace::OnScroll), NULL, this); + this->Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(Workspace::OnRightClickDown), NULL, this); + this->Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(Workspace::OnLeftDoubleClick), NULL, this); + this->Disconnect(wxEVT_IDLE, wxIdleEventHandler(WorkspaceDC::OnIdle), NULL, this); + this->Disconnect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(Workspace::OnMiddleDoubleClick), NULL, this); + + // Recreate the GLCanvas. This is necessary to prevent WorkspaceBase destructor access nullpr. + // Also avoid the code editing of WorkspaceBase, since is automatically generated by wxCrafter. + // TODO(?): Find a better way to solve this problem. + m_glCanvas = new wxGLCanvas(this); +} + +void WorkspaceDC::OnPaint(wxPaintEvent& event) +{ + wxBufferedPaintDC dc(this); + dc.Clear(); + wxGraphicsContext* gc = wxGraphicsContext::Create(dc); + + + // Draw + if (gc) { + + gc->Scale(m_camera->GetScale(), m_camera->GetScale()); + gc->Translate(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y); + + // Elements + for (auto it = m_elementList.begin(); it != m_elementList.end(); ++it) { + Element* element = *it; + element->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc); + } + + // Texts + for (auto it = m_textList.begin(); it != m_textList.end(); ++it) { + Text* text = *it; + text->DrawDC(m_camera->GetTranslation(), m_camera->GetScale(), gc); + } + + // Selection rectangle + //dc.SetPen(wxPen(wxColour(0, 125, 255))); + gc->SetPen(wxPen(wxColour(0, 125, 255, 255))); + gc->SetBrush(wxBrush(wxColour(0, 125, 255, 125))); + //dc.SetBrush(wxBrush(wxColour(0, 125, 255, 125))); + gc->DrawRectangle(m_selectionRect.m_x, m_selectionRect.m_y, m_selectionRect.m_width, m_selectionRect.m_height); + + delete gc; + } + event.Skip(); +} diff --git a/Project/WorkspaceDC.h b/Project/WorkspaceDC.h new file mode 100644 index 0000000..609663a --- /dev/null +++ b/Project/WorkspaceDC.h @@ -0,0 +1,21 @@ +#pragma once +#include "Workspace.h" + +#include <wx/graphics.h> +//#include <wx/dcclient.h> +#include <wx/dcbuffer.h> + +class WorkspaceDC : public Workspace +{ +public: + WorkspaceDC(); + WorkspaceDC(wxWindow* parent, wxString name = wxEmptyString, wxStatusBar* statusBar = nullptr); + ~WorkspaceDC(); + + virtual void Redraw() { this->Refresh(); } + + protected: + virtual void OnPaint(wxPaintEvent& event); + virtual void OnIdle(wxIdleEvent& event) {} // Prevent OpenGL checks +}; + diff --git a/Project/compile_flags.txt b/Project/compile_flags.txt index 350b93a..2bba831 100644 --- a/Project/compile_flags.txt +++ b/Project/compile_flags.txt @@ -8,4 +8,4 @@ -DNDEBUG -DUNICODE -target -x86_64-pc-windows-gnu +i686-pc-windows-gnu diff --git a/Project/main.cpp b/Project/main.cpp index a9bf579..c4b0dc6 100644 --- a/Project/main.cpp +++ b/Project/main.cpp @@ -71,6 +71,14 @@ class MainApp : public wxApp data.theme = THEME_DARK; } } + if (tag == "useOpenGL") { + if (tagValue == "yes") { + data.useOpenGL = true; + } + else if (tagValue == "no") { + data.useOpenGL = false; + } + } } file.Close(); } else { // Create default init file. @@ -79,12 +87,14 @@ class MainApp : public wxApp // Default parameters. file.AddLine("lang=en"); file.AddLine("theme=light"); + file.AddLine("useOpenGL=yes"); file.Write(); file.Close(); data.language = wxLANGUAGE_ENGLISH; data.theme = THEME_LIGHT; + data.useOpenGL = true; propertiesData->SetGeneralPropertiesData(data); } diff --git a/Project/win_resources.aps b/Project/win_resources.aps Binary files differnew file mode 100644 index 0000000..88c78d4 --- /dev/null +++ b/Project/win_resources.aps |