From 89befdb9b259d02249876e39ec6fd28860272439 Mon Sep 17 00:00:00 2001 From: Thales Lima Oliveira Date: Fri, 6 Oct 2017 17:06:15 -0300 Subject: A lot of documentation written --- docs/doxygen/html/_branch_8cpp_source.html | 7 +- docs/doxygen/html/_branch_8h.html | 116 +++++++++++++++ docs/doxygen/html/_branch_8h_source.html | 33 ++--- docs/doxygen/html/_bus_8cpp_source.html | 11 +- docs/doxygen/html/_bus_8h.html | 118 ++++++++++++++++ docs/doxygen/html/_bus_8h_source.html | 14 +- docs/doxygen/html/_bus_form_8cpp_source.html | 5 +- docs/doxygen/html/_bus_form_8h_source.html | 2 +- docs/doxygen/html/_capacitor_8cpp_source.html | 13 +- docs/doxygen/html/_capacitor_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_capacitor_8h_source.html | 9 +- docs/doxygen/html/_chart_view_8cpp_source.html | 7 +- docs/doxygen/html/_chart_view_8h_source.html | 4 +- .../doxygen/html/_connection_line_8cpp_source.html | 2 +- docs/doxygen/html/_connection_line_8h_source.html | 2 +- docs/doxygen/html/_constant_8cpp_source.html | 2 +- docs/doxygen/html/_constant_8h_source.html | 2 +- docs/doxygen/html/_control_editor_8cpp_source.html | 17 ++- docs/doxygen/html/_control_editor_8h_source.html | 12 +- .../doxygen/html/_control_element_8cpp_source.html | 2 +- docs/doxygen/html/_control_element_8h_source.html | 4 +- .../_control_element_container_8cpp_source.html | 10 +- .../html/_control_element_container_8h.html | 4 +- .../html/_control_element_container_8h_source.html | 4 +- .../html/_control_element_solver_8cpp_source.html | 7 +- .../html/_control_element_solver_8h_source.html | 8 +- docs/doxygen/html/_data_report_8cpp_source.html | 12 +- docs/doxygen/html/_data_report_8h_source.html | 2 +- .../html/_electric_calculation_8cpp_source.html | 22 +-- docs/doxygen/html/_electric_calculation_8h.html | 30 ++-- .../html/_electric_calculation_8h_source.html | 20 ++- .../html/_electromechanical_8cpp_source.html | 20 +-- docs/doxygen/html/_electromechanical_8h.html | 10 +- .../doxygen/html/_electromechanical_8h_source.html | 8 +- docs/doxygen/html/_element_8cpp_source.html | 4 +- docs/doxygen/html/_element_8h.html | 12 +- docs/doxygen/html/_element_8h_source.html | 4 +- .../html/_element_data_object_8cpp_source.html | 5 +- docs/doxygen/html/_element_data_object_8h.html | 118 ++++++++++++++++ .../html/_element_data_object_8h_source.html | 6 +- .../html/_element_plot_data_8cpp_source.html | 3 +- docs/doxygen/html/_element_plot_data_8h.html | 120 ++++++++++++++++ .../doxygen/html/_element_plot_data_8h_source.html | 6 +- docs/doxygen/html/_exponential_8cpp_source.html | 5 +- docs/doxygen/html/_exponential_8h.html | 2 +- docs/doxygen/html/_exponential_8h_source.html | 9 +- .../html/_exponential_form_8cpp_source.html | 2 +- docs/doxygen/html/_exponential_form_8h_source.html | 2 +- docs/doxygen/html/_fault_8cpp_source.html | 14 +- docs/doxygen/html/_fault_8h.html | 10 +- docs/doxygen/html/_fault_8h_source.html | 6 +- docs/doxygen/html/_file_handing_8cpp_source.html | 34 ++--- docs/doxygen/html/_file_handing_8h.html | 2 +- docs/doxygen/html/_file_handing_8h_source.html | 5 +- docs/doxygen/html/_gain_8cpp_source.html | 7 +- docs/doxygen/html/_gain_8h.html | 2 +- docs/doxygen/html/_gain_8h_source.html | 11 +- docs/doxygen/html/_gain_form_8cpp_source.html | 2 +- docs/doxygen/html/_gain_form_8h_source.html | 2 +- .../html/_general_properties_form_8cpp_source.html | 3 +- .../html/_general_properties_form_8h_source.html | 2 +- .../html/_generator_stab_form_8cpp_source.html | 5 +- .../html/_generator_stab_form_8h_source.html | 2 +- .../html/_graphical_element_8cpp_source.html | 3 +- docs/doxygen/html/_graphical_element_8h.html | 115 +++++++++++++++ .../doxygen/html/_graphical_element_8h_source.html | 8 +- docs/doxygen/html/_i_o_control_8cpp_source.html | 2 +- docs/doxygen/html/_i_o_control_8h_source.html | 2 +- docs/doxygen/html/_ind_motor_8cpp_source.html | 9 +- docs/doxygen/html/_ind_motor_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_ind_motor_8h_source.html | 11 +- docs/doxygen/html/_ind_motor_form_8cpp_source.html | 5 +- docs/doxygen/html/_ind_motor_form_8h_source.html | 2 +- docs/doxygen/html/_inductor_8cpp_source.html | 13 +- docs/doxygen/html/_inductor_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_inductor_8h_source.html | 9 +- docs/doxygen/html/_limiter_8cpp_source.html | 2 +- docs/doxygen/html/_limiter_8h_source.html | 2 +- docs/doxygen/html/_line_8cpp_source.html | 13 +- docs/doxygen/html/_line_8h.html | 118 ++++++++++++++++ docs/doxygen/html/_line_8h_source.html | 11 +- docs/doxygen/html/_line_form_8cpp_source.html | 5 +- docs/doxygen/html/_line_form_8h_source.html | 2 +- docs/doxygen/html/_load_8cpp_source.html | 13 +- docs/doxygen/html/_load_8h.html | 126 +++++++++++++++++ docs/doxygen/html/_load_8h.js | 9 ++ docs/doxygen/html/_load_8h_source.html | 9 +- docs/doxygen/html/_load_form_8cpp_source.html | 5 +- docs/doxygen/html/_load_form_8h_source.html | 2 +- docs/doxygen/html/_machines_8cpp_source.html | 9 +- docs/doxygen/html/_machines_8h.html | 115 +++++++++++++++ docs/doxygen/html/_machines_8h_source.html | 14 +- docs/doxygen/html/_main_frame_8cpp_source.html | 36 +++-- docs/doxygen/html/_main_frame_8h_source.html | 2 +- docs/doxygen/html/_multiplier_8cpp_source.html | 2 +- docs/doxygen/html/_multiplier_8h_source.html | 2 +- docs/doxygen/html/_power_element_8cpp_source.html | 4 +- docs/doxygen/html/_power_element_8h.html | 26 ++-- docs/doxygen/html/_power_element_8h_source.html | 17 +-- docs/doxygen/html/_power_flow_8cpp_source.html | 15 +- docs/doxygen/html/_power_flow_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_power_flow_8h_source.html | 8 +- .../doxygen/html/_properties_data_8cpp_source.html | 3 +- docs/doxygen/html/_properties_data_8h.html | 133 ++++++++++++++++++ docs/doxygen/html/_properties_data_8h.js | 14 ++ docs/doxygen/html/_properties_data_8h_source.html | 8 +- docs/doxygen/html/_rate_limiter_8cpp_source.html | 4 +- docs/doxygen/html/_rate_limiter_8h_source.html | 4 +- .../_reactive_shunt_element_form_8cpp_source.html | 8 +- .../_reactive_shunt_element_form_8h_source.html | 4 +- docs/doxygen/html/_shunt_8cpp_source.html | 7 +- docs/doxygen/html/_shunt_8h.html | 116 +++++++++++++++ docs/doxygen/html/_shunt_8h_source.html | 15 +- .../_simulations_settings_form_8cpp_source.html | 3 +- .../html/_simulations_settings_form_8h_source.html | 2 +- docs/doxygen/html/_sum_8cpp_source.html | 7 +- docs/doxygen/html/_sum_8h.html | 115 +++++++++++++++ docs/doxygen/html/_sum_8h_source.html | 12 +- docs/doxygen/html/_sum_form_8cpp_source.html | 3 +- docs/doxygen/html/_sum_form_8h_source.html | 2 +- docs/doxygen/html/_switching_form_8cpp_source.html | 6 +- docs/doxygen/html/_switching_form_8h_source.html | 2 +- docs/doxygen/html/_sync_generator_8cpp_source.html | 11 +- docs/doxygen/html/_sync_generator_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_sync_generator_8h_source.html | 15 +- .../html/_sync_machine_form_8cpp_source.html | 8 +- .../doxygen/html/_sync_machine_form_8h_source.html | 4 +- docs/doxygen/html/_sync_motor_8cpp_source.html | 7 +- docs/doxygen/html/_sync_motor_8h.html | 117 ++++++++++++++++ docs/doxygen/html/_sync_motor_8h_source.html | 11 +- docs/doxygen/html/_text_8cpp_source.html | 38 +++-- docs/doxygen/html/_text_8h.html | 155 +++++++++++++++++++++ docs/doxygen/html/_text_8h.js | 30 ++++ docs/doxygen/html/_text_8h_source.html | 33 ++--- docs/doxygen/html/_text_form_8cpp_source.html | 20 +-- docs/doxygen/html/_text_form_8h.html | 2 +- docs/doxygen/html/_text_form_8h_source.html | 7 +- .../html/_transfer_function_8cpp_source.html | 11 +- docs/doxygen/html/_transfer_function_8h.html | 119 ++++++++++++++++ .../doxygen/html/_transfer_function_8h_source.html | 16 ++- .../html/_transfer_function_form_8cpp_source.html | 5 +- .../html/_transfer_function_form_8h_source.html | 2 +- docs/doxygen/html/_transformer_8cpp_source.html | 13 +- docs/doxygen/html/_transformer_8h.html | 136 ++++++++++++++++++ docs/doxygen/html/_transformer_8h.js | 16 +++ docs/doxygen/html/_transformer_8h_source.html | 9 +- .../html/_transformer_form_8cpp_source.html | 5 +- docs/doxygen/html/_transformer_form_8h_source.html | 2 +- docs/doxygen/html/_workspace_8cpp_source.html | 57 +++++--- docs/doxygen/html/_workspace_8h.html | 2 +- docs/doxygen/html/_workspace_8h_source.html | 33 ++--- docs/doxygen/html/annotated.html | 60 ++++---- docs/doxygen/html/class_branch.html | 42 +++--- docs/doxygen/html/class_bus.html | 22 ++- docs/doxygen/html/class_capacitor.html | 22 ++- docs/doxygen/html/class_connection_line.html | 2 +- docs/doxygen/html/class_constant.html | 4 +- docs/doxygen/html/class_control_element.html | 10 +- docs/doxygen/html/class_electric_calculation.html | 12 +- docs/doxygen/html/class_electromechanical.html | 8 +- docs/doxygen/html/class_element.html | 66 ++++----- docs/doxygen/html/class_element_data_object.html | 12 +- docs/doxygen/html/class_element_plot_data.html | 2 +- docs/doxygen/html/class_exponential-members.html | 2 +- docs/doxygen/html/class_exponential.html | 68 +++++++-- docs/doxygen/html/class_fault.html | 8 +- docs/doxygen/html/class_gain-members.html | 2 +- docs/doxygen/html/class_gain.html | 68 +++++++-- docs/doxygen/html/class_graphical_element.html | 16 ++- docs/doxygen/html/class_i_o_control.html | 4 +- docs/doxygen/html/class_ind_motor.html | 20 ++- docs/doxygen/html/class_inductor.html | 22 ++- docs/doxygen/html/class_limiter.html | 4 +- docs/doxygen/html/class_line.html | 24 ++-- docs/doxygen/html/class_load.html | 22 ++- docs/doxygen/html/class_machines.html | 28 ++-- docs/doxygen/html/class_multiplier.html | 4 +- docs/doxygen/html/class_open_g_l_colour.html | 6 +- docs/doxygen/html/class_plot_data.html | 12 +- docs/doxygen/html/class_power_element.html | 36 ++--- docs/doxygen/html/class_power_flow.html | 14 +- docs/doxygen/html/class_properties_data.html | 12 +- docs/doxygen/html/class_rate_limiter.html | 41 ++---- docs/doxygen/html/class_shunt.html | 26 ++-- docs/doxygen/html/class_sum.html | 20 ++- docs/doxygen/html/class_sync_generator.html | 20 ++- docs/doxygen/html/class_sync_motor.html | 20 ++- docs/doxygen/html/class_text.html | 20 ++- .../html/class_transfer_function-members.html | 4 +- docs/doxygen/html/class_transfer_function.html | 127 +++++++++++++++-- docs/doxygen/html/class_transformer.html | 22 ++- .../html/dir_ffd1f789ec7bd0a45fc6ad92579c5070.html | 45 +++++- .../html/dir_ffd1f789ec7bd0a45fc6ad92579c5070.js | 82 ++++++++--- docs/doxygen/html/files.html | 50 +++---- docs/doxygen/html/functions_c.html | 3 + docs/doxygen/html/functions_func_c.html | 3 + docs/doxygen/html/functions_func_s.html | 5 +- docs/doxygen/html/functions_s.html | 5 +- docs/doxygen/html/hierarchy.html | 60 ++++---- docs/doxygen/html/main_8cpp_source.html | 3 +- docs/doxygen/html/navtreedata.js | 27 ++-- docs/doxygen/html/navtreeindex0.js | 34 ++--- docs/doxygen/html/navtreeindex1.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex10.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex11.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex12.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex13.js | 81 ++++++++--- docs/doxygen/html/navtreeindex14.js | 19 +++ docs/doxygen/html/navtreeindex2.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex3.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex4.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex5.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex6.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex7.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex8.js | 128 ++++++++--------- docs/doxygen/html/navtreeindex9.js | 128 ++++++++--------- docs/doxygen/html/search/all_1.js | 2 + docs/doxygen/html/search/all_10.js | 3 + docs/doxygen/html/search/all_2.js | 2 + docs/doxygen/html/search/all_4.js | 2 + docs/doxygen/html/search/all_6.js | 3 +- docs/doxygen/html/search/all_8.js | 2 + docs/doxygen/html/search/all_9.js | 2 + docs/doxygen/html/search/all_a.js | 1 + docs/doxygen/html/search/all_d.js | 4 +- docs/doxygen/html/search/all_f.js | 6 +- docs/doxygen/html/search/files_1.js | 2 + docs/doxygen/html/search/files_2.js | 1 + docs/doxygen/html/search/files_4.js | 2 + docs/doxygen/html/search/files_6.js | 3 +- docs/doxygen/html/search/files_7.js | 2 + docs/doxygen/html/search/files_8.js | 2 + docs/doxygen/html/search/files_9.js | 1 + docs/doxygen/html/search/files_a.js | 4 +- docs/doxygen/html/search/files_c.js | 6 +- docs/doxygen/html/search/files_d.js | 3 + docs/doxygen/html/search/functions_2.js | 1 + docs/doxygen/html/search/functions_e.js | 2 +- docs/doxygen/html/struct_integration_constant.html | 6 +- docs/doxygen/html/struct_switching_data.html | 6 +- .../struct_transfer_function_1_1_space_state.html | 2 +- 241 files changed, 4858 insertions(+), 1726 deletions(-) create mode 100644 docs/doxygen/html/_branch_8h.html create mode 100644 docs/doxygen/html/_bus_8h.html create mode 100644 docs/doxygen/html/_capacitor_8h.html create mode 100644 docs/doxygen/html/_element_data_object_8h.html create mode 100644 docs/doxygen/html/_element_plot_data_8h.html create mode 100644 docs/doxygen/html/_graphical_element_8h.html create mode 100644 docs/doxygen/html/_ind_motor_8h.html create mode 100644 docs/doxygen/html/_inductor_8h.html create mode 100644 docs/doxygen/html/_line_8h.html create mode 100644 docs/doxygen/html/_load_8h.html create mode 100644 docs/doxygen/html/_load_8h.js create mode 100644 docs/doxygen/html/_machines_8h.html create mode 100644 docs/doxygen/html/_power_flow_8h.html create mode 100644 docs/doxygen/html/_properties_data_8h.html create mode 100644 docs/doxygen/html/_properties_data_8h.js create mode 100644 docs/doxygen/html/_shunt_8h.html create mode 100644 docs/doxygen/html/_sum_8h.html create mode 100644 docs/doxygen/html/_sync_generator_8h.html create mode 100644 docs/doxygen/html/_sync_motor_8h.html create mode 100644 docs/doxygen/html/_text_8h.html create mode 100644 docs/doxygen/html/_text_8h.js create mode 100644 docs/doxygen/html/_transfer_function_8h.html create mode 100644 docs/doxygen/html/_transformer_8h.html create mode 100644 docs/doxygen/html/_transformer_8h.js create mode 100644 docs/doxygen/html/navtreeindex14.js (limited to 'docs/doxygen') diff --git a/docs/doxygen/html/_branch_8cpp_source.html b/docs/doxygen/html/_branch_8cpp_source.html index 05e75d5..cdf0040 100644 --- a/docs/doxygen/html/_branch_8cpp_source.html +++ b/docs/doxygen/html/_branch_8cpp_source.html @@ -88,16 +88,17 @@ $(document).ready(function(){initNavTree('_branch_8cpp_source.html','');});
Branch.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Branch.h"
19 
20 Branch::Branch() : PowerElement() {}
21 Branch::~Branch() {}
22 bool Branch::NodeContains(wxPoint2DDouble position)
23 {
24  wxRect2DDouble nodeRect1(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
25  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
26  wxRect2DDouble nodeRect2(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
27  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize, 10 + 2.0 * m_borderSize,
28  10 + 2.0 * m_borderSize);
29 
30  if(nodeRect1.Contains(position)) {
31  m_activeNodeID = 1;
32  return true;
33  }
34  if(nodeRect2.Contains(position)) {
35  m_activeNodeID = 2;
36  return true;
37  }
38 
39  m_activeNodeID = 0;
40  return false;
41 }
42 
44 {
45  if(m_activeNodeID == 1 && parent == m_parentList[0]) return false;
46  if(m_activeNodeID == 2 && parent == m_parentList[1]) return false;
47 
48  if(parent && m_activeNodeID != 0) {
49  wxRect2DDouble nodeRect(0, 0, 0, 0);
50  if(m_activeNodeID == 1) {
51  nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
52  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
53  }
54  if(m_activeNodeID == 2) {
55  nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
56  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
57  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
58  }
59 
60  if(parent->Intersects(nodeRect)) {
61  if(m_activeNodeID == 1) {
62  // Check if the user is trying to connect the same bus.
63  if(m_parentList[1] == parent) {
64  m_activeNodeID = 0;
65  return false;
66  }
67 
68  m_parentList[0] = parent;
69 
70  // Centralize the node on bus.
71  wxPoint2DDouble parentPt = parent->RotateAtPosition(
72  m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
73  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
74  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
75  m_pointList[0] = parentPt;
76 
77  UpdateSwitchesPosition();
78  return true;
79  }
80  if(m_activeNodeID == 2) {
81  if(m_parentList[0] == parent) {
82  m_activeNodeID = 0;
83  return false;
84  }
85 
86  m_parentList[1] = parent;
87 
88  wxPoint2DDouble parentPt =
89  parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], -parent->GetAngle());
90  parentPt.m_y = parent->GetPosition().m_y;
91  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
92  m_pointList[m_pointList.size() - 1] = parentPt;
93 
94  UpdateSwitchesPosition();
95  return true;
96  }
97  } else {
98  if(m_activeNodeID == 1) m_parentList[0] = NULL;
99  if(m_activeNodeID == 2) m_parentList[1] = NULL;
100  }
101  }
102  return false;
103 }
104 
106 {
107  for(int i = 0; i < 2; i++) {
108  if(parent == m_parentList[i]) {
109  m_parentList[i] = NULL;
110  m_online = false;
111  UpdateSwitchesPosition();
112  }
113  }
114 }
115 
117 {
118  if(m_parentList[0]) {
119  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
120  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
121 
122  if(!m_parentList[0]->Intersects(nodeRect)) {
123  m_parentList[0]->RemoveChild(this);
124  m_parentList[0] = NULL;
125  m_online = false;
126  UpdateSwitchesPosition();
127  }
128  }
129  if(m_parentList[1]) {
130  wxRect2DDouble nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
131  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
132  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
133 
134  if(!m_parentList[1]->Intersects(nodeRect)) {
135  m_parentList[1]->RemoveChild(this);
136  m_parentList[1] = NULL;
137  m_online = false;
138  UpdateSwitchesPosition();
139  }
140  }
141 }
142 
143 void Branch::RotateNode(Element* parent, bool clockwise)
144 {
145  double rotAngle = m_rotationAngle;
146  if(!clockwise) rotAngle = -m_rotationAngle;
147 
148  if(parent == m_parentList[0]) {
149  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
150  } else if(parent == m_parentList[1]) {
151  m_pointList[m_pointList.size() - 1] = parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
152  }
153  UpdateSwitchesPosition();
154 }
155 
156 void Branch::UpdateSwitchesPosition()
157 {
158  if(m_parentList[0]) {
159  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
160  } else {
161  m_pointList[1] = m_pointList[0];
162  }
163  if(m_parentList[1]) {
164  m_pointList[m_pointList.size() - 2] =
165  GetSwitchPoint(m_parentList[1], m_pointList[m_pointList.size() - 1], m_pointList[m_pointList.size() - 3]);
166  } else {
167  m_pointList[m_pointList.size() - 2] = m_pointList[m_pointList.size() - 1];
168  }
169  UpdateSwitches();
170 }
171 
173 {
174  wxPoint2DDouble swCenter = wxPoint2DDouble((m_pointList[0].m_x + m_pointList[1].m_x) / 2.0,
175  (m_pointList[0].m_y + m_pointList[1].m_y) / 2.0);
176  m_switchRect[0] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0, m_switchSize,
177  m_switchSize);
178 
179  if(m_switchRect.size() > 1) {
180  swCenter =
181  wxPoint2DDouble((m_pointList[m_pointList.size() - 1].m_x + m_pointList[m_pointList.size() - 2].m_x) / 2.0,
182  (m_pointList[m_pointList.size() - 1].m_y + m_pointList[m_pointList.size() - 2].m_y) / 2.0);
183  m_switchRect[1] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0,
184  m_switchSize, m_switchSize);
185  }
186 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Branch.h"
19 
20 Branch::Branch() : PowerElement() {}
21 Branch::~Branch() {}
22 bool Branch::NodeContains(wxPoint2DDouble position)
23 {
24  wxRect2DDouble nodeRect1(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
25  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
26  wxRect2DDouble nodeRect2(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
27  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize, 10 + 2.0 * m_borderSize,
28  10 + 2.0 * m_borderSize);
29 
30  if(nodeRect1.Contains(position)) {
31  m_activeNodeID = 1;
32  return true;
33  }
34  if(nodeRect2.Contains(position)) {
35  m_activeNodeID = 2;
36  return true;
37  }
38 
39  m_activeNodeID = 0;
40  return false;
41 }
42 
44 {
45  if(m_activeNodeID == 1 && parent == m_parentList[0]) return false;
46  if(m_activeNodeID == 2 && parent == m_parentList[1]) return false;
47 
48  if(parent && m_activeNodeID != 0) {
49  wxRect2DDouble nodeRect(0, 0, 0, 0);
50  if(m_activeNodeID == 1) {
51  nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
52  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
53  }
54  if(m_activeNodeID == 2) {
55  nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
56  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
57  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
58  }
59 
60  if(parent->Intersects(nodeRect)) {
61  if(m_activeNodeID == 1) {
62  // Check if the user is trying to connect the same bus.
63  if(m_parentList[1] == parent) {
64  m_activeNodeID = 0;
65  return false;
66  }
67 
68  m_parentList[0] = parent;
69 
70  // Centralize the node on bus.
71  wxPoint2DDouble parentPt = parent->RotateAtPosition(
72  m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
73  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
74  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
75  m_pointList[0] = parentPt;
76 
77  UpdateSwitchesPosition();
78  return true;
79  }
80  if(m_activeNodeID == 2) {
81  if(m_parentList[0] == parent) {
82  m_activeNodeID = 0;
83  return false;
84  }
85 
86  m_parentList[1] = parent;
87 
88  wxPoint2DDouble parentPt =
89  parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], -parent->GetAngle());
90  parentPt.m_y = parent->GetPosition().m_y;
91  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
92  m_pointList[m_pointList.size() - 1] = parentPt;
93 
94  UpdateSwitchesPosition();
95  return true;
96  }
97  } else {
98  if(m_activeNodeID == 1) m_parentList[0] = NULL;
99  if(m_activeNodeID == 2) m_parentList[1] = NULL;
100  }
101  }
102  return false;
103 }
104 
106 {
107  for(int i = 0; i < 2; i++) {
108  if(parent == m_parentList[i]) {
109  m_parentList[i] = NULL;
110  m_online = false;
111  UpdateSwitchesPosition();
112  }
113  }
114 }
115 
117 {
118  if(m_parentList[0]) {
119  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
120  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
121 
122  if(!m_parentList[0]->Intersects(nodeRect)) {
123  m_parentList[0]->RemoveChild(this);
124  m_parentList[0] = NULL;
125  m_online = false;
126  UpdateSwitchesPosition();
127  }
128  }
129  if(m_parentList[1]) {
130  wxRect2DDouble nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
131  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
132  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
133 
134  if(!m_parentList[1]->Intersects(nodeRect)) {
135  m_parentList[1]->RemoveChild(this);
136  m_parentList[1] = NULL;
137  m_online = false;
138  UpdateSwitchesPosition();
139  }
140  }
141 }
142 
143 void Branch::RotateNode(Element* parent, bool clockwise)
144 {
145  double rotAngle = m_rotationAngle;
146  if(!clockwise) rotAngle = -m_rotationAngle;
147 
148  if(parent == m_parentList[0]) {
149  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
150  } else if(parent == m_parentList[1]) {
151  m_pointList[m_pointList.size() - 1] = parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
152  }
153  UpdateSwitchesPosition();
154 }
155 
156 void Branch::UpdateSwitchesPosition()
157 {
158  if(m_parentList[0]) {
159  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
160  } else {
161  m_pointList[1] = m_pointList[0];
162  }
163  if(m_parentList[1]) {
164  m_pointList[m_pointList.size() - 2] =
165  GetSwitchPoint(m_parentList[1], m_pointList[m_pointList.size() - 1], m_pointList[m_pointList.size() - 3]);
166  } else {
167  m_pointList[m_pointList.size() - 2] = m_pointList[m_pointList.size() - 1];
168  }
169  UpdateSwitches();
170 }
171 
173 {
174  wxPoint2DDouble swCenter = wxPoint2DDouble((m_pointList[0].m_x + m_pointList[1].m_x) / 2.0,
175  (m_pointList[0].m_y + m_pointList[1].m_y) / 2.0);
176  m_switchRect[0] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0, m_switchSize,
177  m_switchSize);
178 
179  if(m_switchRect.size() > 1) {
180  swCenter =
181  wxPoint2DDouble((m_pointList[m_pointList.size() - 1].m_x + m_pointList[m_pointList.size() - 2].m_x) / 2.0,
182  (m_pointList[m_pointList.size() - 1].m_y + m_pointList[m_pointList.size() - 2].m_y) / 2.0);
183  m_switchRect[1] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0,
184  m_switchSize, m_switchSize);
185  }
186 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Branch.cpp:105
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Branch.cpp:43
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition: Element.cpp:107
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element&#39;s rect intersects other rect.
virtual void UpdateSwitches()
Update the switch position.
Definition: Branch.cpp:172
+
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Branch.cpp:116
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement...
Definition: Branch.cpp:22
- +
Abstract class of power elements.
Definition: PowerElement.h:117
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition: Branch.cpp:143
diff --git a/docs/doxygen/html/_branch_8h.html b/docs/doxygen/html/_branch_8h.html new file mode 100644 index 0000000..1f595ab --- /dev/null +++ b/docs/doxygen/html/_branch_8h.html @@ -0,0 +1,116 @@ + + + + + + + + + +Project/Branch.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Branch.h File Reference
+
+
+
#include "PowerElement.h"
+#include "Bus.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  Branch
 Abstract class for branch power elements. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_branch_8h_source.html b/docs/doxygen/html/_branch_8h_source.html index 564f01b..9042af4 100644 --- a/docs/doxygen/html/_branch_8h_source.html +++ b/docs/doxygen/html/_branch_8h_source.html @@ -88,33 +88,34 @@ $(document).ready(function(){initNavTree('_branch_8h_source.html','');});
Branch.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BRANCH_H
19 #define BRANCH_H
20 
21 #include "PowerElement.h"
22 #include "Bus.h"
23 
24 class Branch : public PowerElement
25 {
26  public:
27  Branch();
28  ~Branch();
29 
30  virtual bool Contains(wxPoint2DDouble position) const { return false; }
31  virtual void Draw(wxPoint2DDouble translation, double scale) const {}
32  virtual void Move(wxPoint2DDouble position) {}
33  virtual void StartMove(wxPoint2DDouble position) {}
34  virtual void MoveNode(Element* parent, wxPoint2DDouble position) {}
35  virtual bool NodeContains(wxPoint2DDouble position);
36  virtual bool SetNodeParent(Element* parent);
37  virtual void RemoveParent(Element* parent);
38  virtual void UpdateNodes();
39  virtual wxCursor GetBestPickboxCursor() const { return wxCURSOR_ARROW; }
40  virtual bool Intersects(wxRect2DDouble rect) const { return false; }
41  virtual void MovePickbox(wxPoint2DDouble position) {}
42  virtual bool PickboxContains(wxPoint2DDouble position) { return false; }
43  virtual void RotateNode(Element* parent, bool clockwise = true);
44  virtual void AddPoint(wxPoint2DDouble point){};
45  virtual bool GetContextMenu(wxMenu& menu) { return false; }
46  virtual void UpdateSwitchesPosition();
47  virtual void UpdateSwitches();
48 
49  protected:
50  bool m_inserted = false;
51 };
52 
53 #endif // BRANCH_H
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Branch.h:31
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BRANCH_H
19 #define BRANCH_H
20 
21 #include "PowerElement.h"
22 #include "Bus.h"
23 
31 class Branch : public PowerElement
32 {
33  public:
34  Branch();
35  ~Branch();
36 
37  virtual bool Contains(wxPoint2DDouble position) const { return false; }
38  virtual void Draw(wxPoint2DDouble translation, double scale) const {}
39  virtual void Move(wxPoint2DDouble position) {}
40  virtual void StartMove(wxPoint2DDouble position) {}
41  virtual void MoveNode(Element* parent, wxPoint2DDouble position) {}
42  virtual bool NodeContains(wxPoint2DDouble position);
43  virtual bool SetNodeParent(Element* parent);
44  virtual void RemoveParent(Element* parent);
45  virtual void UpdateNodes();
46  virtual wxCursor GetBestPickboxCursor() const { return wxCURSOR_ARROW; }
47  virtual bool Intersects(wxRect2DDouble rect) const { return false; }
48  virtual void MovePickbox(wxPoint2DDouble position) {}
49  virtual bool PickboxContains(wxPoint2DDouble position) { return false; }
50  virtual void RotateNode(Element* parent, bool clockwise = true);
51  virtual void AddPoint(wxPoint2DDouble point){};
52  virtual bool GetContextMenu(wxMenu& menu) { return false; }
53  virtual void UpdateSwitchesPosition();
54  virtual void UpdateSwitches();
55 
56  protected:
57  bool m_inserted = false;
58 };
59 
60 #endif // BRANCH_H
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Branch.h:38
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Branch.cpp:105
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Branch.cpp:43
-
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Branch.h:45
-
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
Definition: Branch.h:41
-
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Branch.h:33
+
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Branch.h:52
+
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
Definition: Branch.h:48
+
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Branch.h:40
+
virtual void UpdateSwitches()
Update the switch position.
Definition: Branch.cpp:172
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Branch.h:30
-
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
Definition: Branch.h:44
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Branch.h:40
-
Switching data of power elements.
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Branch.h:37
+
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
Definition: Branch.h:51
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Branch.h:47
+
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Branch.cpp:116
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement...
Definition: Branch.cpp:22
- -
virtual bool PickboxContains(wxPoint2DDouble position)
Check if a pickbox contains a point. If contains the attributes related to pickbox movement will be c...
Definition: Branch.h:42
-
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Branch.h:32
+
Abstract class of power elements.
Definition: PowerElement.h:117
+
virtual bool PickboxContains(wxPoint2DDouble position)
Check if a pickbox contains a point. If contains the attributes related to pickbox movement will be c...
Definition: Branch.h:49
+
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Branch.h:39
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition: Branch.cpp:143
-
virtual void MoveNode(Element *parent, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Branch.h:34
-
virtual wxCursor GetBestPickboxCursor() const
Get the best cursor to shown to the user when the mouse is above a pickbox.
Definition: Branch.h:39
-
Definition: Branch.h:24
+
virtual void MoveNode(Element *parent, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Branch.h:41
+
virtual wxCursor GetBestPickboxCursor() const
Get the best cursor to shown to the user when the mouse is above a pickbox.
Definition: Branch.h:46
+
Abstract class for branch power elements.
Definition: Branch.h:31
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Bus.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
23 Bus::Bus() : PowerElement() {}
24 Bus::Bus(wxPoint2DDouble position) : PowerElement()
25 {
26  m_width = 100.0;
27  m_height = 5.0;
28  SetPosition(position);
29 }
30 
31 Bus::Bus(wxPoint2DDouble position, wxString name)
32 {
33  m_width = 100.0;
34  m_height = 5.0;
35  SetPosition(position);
36 
37  m_electricalData.name = name;
38 }
39 
40 Bus::~Bus() {}
41 void Bus::Draw(wxPoint2DDouble translation, double scale) const
42 {
43  // Draw selection (layer 1)
44  if(m_selected) {
45  // If the object is selected, the matrix is reset to remove scale effects applied to it, thus keeping the
46  // edges with fixed sizes for all zoom levels.
47  glPushMatrix();
48  glLoadIdentity();
49  // The matrix was reset, so we must use screen coordinates (WorldToScreen).
50  wxPoint2DDouble screenPt = WorldToScreen(translation, scale);
51  glTranslated(screenPt.m_x, screenPt.m_y, 0.0);
52  glRotated(m_angle, 0.0, 0.0, 1.0);
53  glTranslated(-screenPt.m_x, -screenPt.m_y, 0.0);
54 
55  glColor4dv(m_selectionColour.GetRGBA());
56 
57  wxPoint2DDouble pts[4] = {WorldToScreen(translation, scale, -(m_width / 2.0), -(m_height / 2.0)) -
58  wxPoint2DDouble(m_borderSize, m_borderSize),
59  WorldToScreen(translation, scale, -(m_width / 2.0), (m_height / 2.0)) -
60  wxPoint2DDouble(m_borderSize, -m_borderSize),
61  WorldToScreen(translation, scale, (m_width / 2.0), (m_height / 2.0)) -
62  wxPoint2DDouble(-m_borderSize, -m_borderSize),
63  WorldToScreen(translation, scale, (m_width / 2.0), -(m_height / 2.0)) -
64  wxPoint2DDouble(-m_borderSize, m_borderSize)};
65  DrawRectangle(pts);
66  glPopMatrix();
67  }
68  // Draw bus (layer 2)
69  // Push the current matrix on stack.
70  glPushMatrix();
71  // Rotate the matrix around the object position.
72  glTranslated(m_position.m_x, m_position.m_y, 0.0);
73  glRotated(m_angle, 0.0, 0.0, 1.0);
74  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
75 
76  if(m_dynEvent)
77  glColor4dv(m_dynamicEventColour.GetRGBA());
78  else
79  glColor4dv(m_busColour.GetRGBA());
80 
81  DrawRectangle(m_position, m_width, m_height);
82  // Pop the old matrix back.
83  glPopMatrix();
84 
85  // Draw pickbox (layer 3)
86  if(m_showPickbox) {
87  glPushMatrix();
88  glLoadIdentity();
89 
90  wxPoint2DDouble screenPt = WorldToScreen(translation, scale);
91  glTranslated(screenPt.m_x, screenPt.m_y, 0.0);
92  glRotated(m_angle, 0.0, 0.0, 1.0);
93  glTranslated(-screenPt.m_x, -screenPt.m_y, 0.0);
94 
95  wxPoint2DDouble pbPosition[2] = {WorldToScreen(translation, scale, m_width / 2.0),
96  WorldToScreen(translation, scale, -m_width / 2.0)};
97  DrawPickbox(pbPosition[0]);
98  DrawPickbox(pbPosition[1]);
99 
100  glPopMatrix();
101  }
102 }
103 
104 bool Bus::Contains(wxPoint2DDouble position) const
105 {
106  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
107  return m_rect.Contains(ptR);
108 }
109 
110 bool Bus::Intersects(wxRect2DDouble rect) const
111 {
112  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
113 
114  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
115 }
116 
117 bool Bus::PickboxContains(wxPoint2DDouble position)
118 {
119  m_activePickboxID = ID_PB_NONE;
120 
121  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
122 
123  wxPoint2DDouble center(m_position.m_x + m_width / 2.0, m_position.m_y);
124  wxRect2DDouble rectRight(center.m_x - 5.0, center.m_y - 5.0, 10.0, 10.0);
125 
126  center = wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y);
127  wxRect2DDouble rectLeft(center.m_x - 5.0, center.m_y - 5.0, 10.0, 10.0);
128 
129  if(rectRight.Contains(ptR)) {
130  m_activePickboxID = ID_PB_RIGHT;
131  return true;
132  }
133  if(rectLeft.Contains(ptR)) {
134  m_activePickboxID = ID_PB_LEFT;
135  return true;
136  }
137 
138  return false;
139 }
140 
142 {
143  double angle = m_angle;
144  while(angle >= 157.5) angle -= 180.0;
145 
146  if(angle >= -22.5 && angle < 22.5)
147  return wxCursor(wxCURSOR_SIZEWE);
148  else if(angle >= 22.5 && angle < 67.5)
149  return wxCursor(wxCURSOR_SIZENWSE);
150  else if(angle >= 67.5 && angle < 112.5)
151  return wxCursor(wxCURSOR_SIZENS);
152  else if(angle >= 112.5 && angle < 157.5)
153  return wxCursor(wxCURSOR_SIZENESW);
154 
155  return wxCursor(wxCURSOR_ARROW);
156 }
157 
158 void Bus::MovePickbox(wxPoint2DDouble position)
159 {
160  if(m_activePickboxID == ID_PB_NONE) return;
161 
162  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
163 
164  double dx = 0.0;
165  if(m_activePickboxID == ID_PB_RIGHT)
166  dx = ptR.m_x - m_position.m_x - m_width / 2.0;
167  else if(m_activePickboxID == ID_PB_LEFT)
168  dx = m_position.m_x - m_width / 2.0 - ptR.m_x;
169 
170  if(m_width + dx < 20.0) return;
171 
172  if(m_activePickboxID == ID_PB_RIGHT) {
173  m_position.m_x += (dx / 2.0) * std::cos(wxDegToRad(m_angle));
174  m_position.m_y += (dx / 2.0) * std::sin(wxDegToRad(m_angle));
175  } else if(m_activePickboxID == ID_PB_LEFT) {
176  m_position.m_x -= (dx / 2.0) * std::cos(wxDegToRad(m_angle));
177  m_position.m_y -= (dx / 2.0) * std::sin(wxDegToRad(m_angle));
178  }
179  m_width += dx;
180 
181  SetPosition(m_position);
182 }
183 
184 void Bus::Rotate(bool clockwise)
185 {
186  double rotAngle = m_rotationAngle;
187  if(!clockwise) rotAngle = -m_rotationAngle;
188 
189  m_angle += rotAngle;
190  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
191 }
192 
193 bool Bus::GetContextMenu(wxMenu& menu)
194 {
195  menu.Append(ID_EDIT_ELEMENT, _("Edit bus"));
196  GeneralMenuItens(menu);
197  return true;
198 }
199 
200 bool Bus::ShowForm(wxWindow* parent, Element* element)
201 {
202  BusForm* busForm = new BusForm(parent, this);
203  if(busForm->ShowModal() == wxID_OK) {
204  busForm->Destroy();
205  return true;
206  }
207 
208  busForm->Destroy();
209  return false;
210 }
211 
213 {
214  Bus* copy = new Bus();
215  *copy = *this;
216  return copy;
217 }
218 wxString Bus::GetTipText() const
219 {
220  wxString tipText = m_electricalData.name;
221  tipText += wxString::Format(" (%d)", m_electricalData.number + 1);
222  tipText += "\n";
223  tipText += StringFromDouble(m_electricalData.nominalVoltage, 1) +
224  (m_electricalData.nominalVoltageUnit == UNIT_V ? _(" V") : _(" kV"));
225  tipText += "\n";
226  tipText += _("\nV = ") + wxString::FromDouble(std::abs(m_electricalData.voltage), 5) + _(" p.u.");
227  tipText += "\n";
228  tipText += wxString(L'\u03B8') + " = " + wxString::FromDouble(wxRadToDeg(std::arg(m_electricalData.voltage)), 5) +
229  " " + wxString(L'\u00B0');
230 
231  tipText += _("\n\nFault info:");
232  tipText += _("\nVa = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[0]), 5) + _(" p.u.");
233  tipText += _("\nVb = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[1]), 5) + _(" p.u.");
234  tipText += _("\nVc = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[2]), 5) + _(" p.u.");
235  if(m_electricalData.hasFault) {
236  tipText += _("\nIa = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[0]), 5) + _(" p.u.");
237  tipText += _("\nIb = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[1]), 5) + _(" p.u.");
238  tipText += _("\nIc = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[2]), 5) + _(" p.u.");
239  }
240 
241  tipText += _("\n\nSsc = ") + wxString::FromDouble(std::abs(m_electricalData.scPower), 5) + _(" p.u.");
242 
243  return tipText;
244 }
245 
247 {
248  if(!m_electricalData.plotBus) return false;
249  plotData.SetName(m_electricalData.name);
250  plotData.SetCurveType(ElementPlotData::CT_BUS);
251 
252  std::vector<double> absVoltage, argVoltage;
253  for(unsigned int i = 0; i < m_electricalData.stabVoltageVector.size(); ++i) {
254  absVoltage.push_back(std::abs(m_electricalData.stabVoltageVector[i]));
255  argVoltage.push_back(wxRadToDeg(std::arg(m_electricalData.stabVoltageVector[i])));
256  }
257  plotData.AddData(absVoltage, _("Voltage"));
258  plotData.AddData(argVoltage, _("Angle"));
259  return true;
260 }
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Bus.cpp:200
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Bus.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
23 Bus::Bus() : PowerElement() {}
24 Bus::Bus(wxPoint2DDouble position) : PowerElement()
25 {
26  m_width = 100.0;
27  m_height = 5.0;
28  SetPosition(position);
29 }
30 
31 Bus::Bus(wxPoint2DDouble position, wxString name)
32 {
33  m_width = 100.0;
34  m_height = 5.0;
35  SetPosition(position);
36 
37  m_electricalData.name = name;
38 }
39 
40 Bus::~Bus() {}
41 void Bus::Draw(wxPoint2DDouble translation, double scale) const
42 {
43  // Draw selection (layer 1)
44  if(m_selected) {
45  // If the object is selected, the matrix is reset to remove scale effects applied to it, thus keeping the
46  // edges with fixed sizes for all zoom levels.
47  glPushMatrix();
48  glLoadIdentity();
49  // The matrix was reset, so we must use screen coordinates (WorldToScreen).
50  wxPoint2DDouble screenPt = WorldToScreen(translation, scale);
51  glTranslated(screenPt.m_x, screenPt.m_y, 0.0);
52  glRotated(m_angle, 0.0, 0.0, 1.0);
53  glTranslated(-screenPt.m_x, -screenPt.m_y, 0.0);
54 
55  glColor4dv(m_selectionColour.GetRGBA());
56 
57  wxPoint2DDouble pts[4] = {WorldToScreen(translation, scale, -(m_width / 2.0), -(m_height / 2.0)) -
58  wxPoint2DDouble(m_borderSize, m_borderSize),
59  WorldToScreen(translation, scale, -(m_width / 2.0), (m_height / 2.0)) -
60  wxPoint2DDouble(m_borderSize, -m_borderSize),
61  WorldToScreen(translation, scale, (m_width / 2.0), (m_height / 2.0)) -
62  wxPoint2DDouble(-m_borderSize, -m_borderSize),
63  WorldToScreen(translation, scale, (m_width / 2.0), -(m_height / 2.0)) -
64  wxPoint2DDouble(-m_borderSize, m_borderSize)};
65  DrawRectangle(pts);
66  glPopMatrix();
67  }
68  // Draw bus (layer 2)
69  // Push the current matrix on stack.
70  glPushMatrix();
71  // Rotate the matrix around the object position.
72  glTranslated(m_position.m_x, m_position.m_y, 0.0);
73  glRotated(m_angle, 0.0, 0.0, 1.0);
74  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
75 
76  if(m_dynEvent)
77  glColor4dv(m_dynamicEventColour.GetRGBA());
78  else
79  glColor4dv(m_busColour.GetRGBA());
80 
81  DrawRectangle(m_position, m_width, m_height);
82  // Pop the old matrix back.
83  glPopMatrix();
84 
85  // Draw pickbox (layer 3)
86  if(m_showPickbox) {
87  glPushMatrix();
88  glLoadIdentity();
89 
90  wxPoint2DDouble screenPt = WorldToScreen(translation, scale);
91  glTranslated(screenPt.m_x, screenPt.m_y, 0.0);
92  glRotated(m_angle, 0.0, 0.0, 1.0);
93  glTranslated(-screenPt.m_x, -screenPt.m_y, 0.0);
94 
95  wxPoint2DDouble pbPosition[2] = {WorldToScreen(translation, scale, m_width / 2.0),
96  WorldToScreen(translation, scale, -m_width / 2.0)};
97  DrawPickbox(pbPosition[0]);
98  DrawPickbox(pbPosition[1]);
99 
100  glPopMatrix();
101  }
102 }
103 
104 bool Bus::Contains(wxPoint2DDouble position) const
105 {
106  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
107  return m_rect.Contains(ptR);
108 }
109 
110 bool Bus::Intersects(wxRect2DDouble rect) const
111 {
112  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
113 
114  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
115 }
116 
117 bool Bus::PickboxContains(wxPoint2DDouble position)
118 {
119  m_activePickboxID = ID_PB_NONE;
120 
121  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
122 
123  wxPoint2DDouble center(m_position.m_x + m_width / 2.0, m_position.m_y);
124  wxRect2DDouble rectRight(center.m_x - 5.0, center.m_y - 5.0, 10.0, 10.0);
125 
126  center = wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y);
127  wxRect2DDouble rectLeft(center.m_x - 5.0, center.m_y - 5.0, 10.0, 10.0);
128 
129  if(rectRight.Contains(ptR)) {
130  m_activePickboxID = ID_PB_RIGHT;
131  return true;
132  }
133  if(rectLeft.Contains(ptR)) {
134  m_activePickboxID = ID_PB_LEFT;
135  return true;
136  }
137 
138  return false;
139 }
140 
142 {
143  double angle = m_angle;
144  while(angle >= 157.5) angle -= 180.0;
145 
146  if(angle >= -22.5 && angle < 22.5)
147  return wxCursor(wxCURSOR_SIZEWE);
148  else if(angle >= 22.5 && angle < 67.5)
149  return wxCursor(wxCURSOR_SIZENWSE);
150  else if(angle >= 67.5 && angle < 112.5)
151  return wxCursor(wxCURSOR_SIZENS);
152  else if(angle >= 112.5 && angle < 157.5)
153  return wxCursor(wxCURSOR_SIZENESW);
154 
155  return wxCursor(wxCURSOR_ARROW);
156 }
157 
158 void Bus::MovePickbox(wxPoint2DDouble position)
159 {
160  if(m_activePickboxID == ID_PB_NONE) return;
161 
162  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
163 
164  double dx = 0.0;
165  if(m_activePickboxID == ID_PB_RIGHT)
166  dx = ptR.m_x - m_position.m_x - m_width / 2.0;
167  else if(m_activePickboxID == ID_PB_LEFT)
168  dx = m_position.m_x - m_width / 2.0 - ptR.m_x;
169 
170  if(m_width + dx < 20.0) return;
171 
172  if(m_activePickboxID == ID_PB_RIGHT) {
173  m_position.m_x += (dx / 2.0) * std::cos(wxDegToRad(m_angle));
174  m_position.m_y += (dx / 2.0) * std::sin(wxDegToRad(m_angle));
175  } else if(m_activePickboxID == ID_PB_LEFT) {
176  m_position.m_x -= (dx / 2.0) * std::cos(wxDegToRad(m_angle));
177  m_position.m_y -= (dx / 2.0) * std::sin(wxDegToRad(m_angle));
178  }
179  m_width += dx;
180 
181  SetPosition(m_position);
182 }
183 
184 void Bus::Rotate(bool clockwise)
185 {
186  double rotAngle = m_rotationAngle;
187  if(!clockwise) rotAngle = -m_rotationAngle;
188 
189  m_angle += rotAngle;
190  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
191 }
192 
193 bool Bus::GetContextMenu(wxMenu& menu)
194 {
195  menu.Append(ID_EDIT_ELEMENT, _("Edit bus"));
196  GeneralMenuItens(menu);
197  return true;
198 }
199 
200 bool Bus::ShowForm(wxWindow* parent, Element* element)
201 {
202  BusForm* busForm = new BusForm(parent, this);
203  if(busForm->ShowModal() == wxID_OK) {
204  busForm->Destroy();
205  return true;
206  }
207 
208  busForm->Destroy();
209  return false;
210 }
211 
213 {
214  Bus* copy = new Bus();
215  *copy = *this;
216  return copy;
217 }
218 wxString Bus::GetTipText() const
219 {
220  wxString tipText = m_electricalData.name;
221  tipText += wxString::Format(" (%d)", m_electricalData.number + 1);
222  tipText += "\n";
223  tipText += StringFromDouble(m_electricalData.nominalVoltage, 1) +
224  (m_electricalData.nominalVoltageUnit == UNIT_V ? _(" V") : _(" kV"));
225  tipText += "\n";
226  tipText += _("\nV = ") + wxString::FromDouble(std::abs(m_electricalData.voltage), 5) + _(" p.u.");
227  tipText += "\n";
228  tipText += wxString(L'\u03B8') + " = " + wxString::FromDouble(wxRadToDeg(std::arg(m_electricalData.voltage)), 5) +
229  " " + wxString(L'\u00B0');
230 
231  tipText += _("\n\nFault info:");
232  tipText += _("\nVa = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[0]), 5) + _(" p.u.");
233  tipText += _("\nVb = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[1]), 5) + _(" p.u.");
234  tipText += _("\nVc = ") + wxString::FromDouble(std::abs(m_electricalData.faultVoltage[2]), 5) + _(" p.u.");
235  if(m_electricalData.hasFault) {
236  tipText += _("\nIa = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[0]), 5) + _(" p.u.");
237  tipText += _("\nIb = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[1]), 5) + _(" p.u.");
238  tipText += _("\nIc = ") + wxString::FromDouble(std::abs(m_electricalData.faultCurrent[2]), 5) + _(" p.u.");
239  }
240 
241  tipText += _("\n\nSsc = ") + wxString::FromDouble(std::abs(m_electricalData.scPower), 5) + _(" p.u.");
242 
243  return tipText;
244 }
245 
247 {
248  if(!m_electricalData.plotBus) return false;
249  plotData.SetName(m_electricalData.name);
250  plotData.SetCurveType(ElementPlotData::CT_BUS);
251 
252  std::vector<double> absVoltage, argVoltage;
253  for(unsigned int i = 0; i < m_electricalData.stabVoltageVector.size(); ++i) {
254  absVoltage.push_back(std::abs(m_electricalData.stabVoltageVector[i]));
255  argVoltage.push_back(wxRadToDeg(std::arg(m_electricalData.stabVoltageVector[i])));
256  }
257  plotData.AddData(absVoltage, _("Voltage"));
258  plotData.AddData(argVoltage, _("Angle"));
259  return true;
260 }
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Bus.cpp:200
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
Definition: Bus.cpp:158
@@ -100,10 +100,11 @@ $(document).ready(function(){initNavTree('_bus_8cpp_source.html','');});
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition: Element.cpp:107
Form to edit the bus power data.
Definition: BusForm.h:31
virtual void DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode=GL_QUADS) const
Draw rectangle.
Definition: Element.cpp:69
+
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition: Element.cpp:245
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual bool GetPlotData(ElementPlotData &plotData)
Fill the plot data.
Definition: Bus.cpp:246
- +
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition: Element.cpp:25
virtual wxCursor GetBestPickboxCursor() const
Get the best cursor to shown to the user when the mouse is above a pickbox.
Definition: Bus.cpp:141
virtual void DrawPickbox(wxPoint2DDouble position) const
Draw pickbox.
Definition: Element.cpp:98
@@ -112,7 +113,7 @@ $(document).ready(function(){initNavTree('_bus_8cpp_source.html','');});
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
- +
Abstract class of power elements.
Definition: PowerElement.h:117
virtual Element * GetCopy()
Get a the element copy.
Definition: Bus.cpp:212
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Bus.cpp:104
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Bus.cpp:110
diff --git a/docs/doxygen/html/_bus_8h.html b/docs/doxygen/html/_bus_8h.html new file mode 100644 index 0000000..b589e3e --- /dev/null +++ b/docs/doxygen/html/_bus_8h.html @@ -0,0 +1,118 @@ + + + + + + + + + +Project/Bus.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Bus.h File Reference
+
+
+
#include "BusForm.h"
+#include "PowerElement.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  BusElectricalData
 
class  Bus
 Node for power elements. All others power elements are connected through this. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_bus_8h_source.html b/docs/doxygen/html/_bus_8h_source.html index 8fa6343..970bebe 100644 --- a/docs/doxygen/html/_bus_8h_source.html +++ b/docs/doxygen/html/_bus_8h_source.html @@ -88,25 +88,25 @@ $(document).ready(function(){initNavTree('_bus_8h_source.html','');});
Bus.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BUS_H
19 #define BUS_H
20 
21 #include "BusForm.h"
22 #include "PowerElement.h"
23 
25  int number = 0;
26  wxString name = "";
27  double nominalVoltage = 138.0;
28  ElectricalUnit nominalVoltageUnit = UNIT_kV;
29  bool isVoltageControlled = false;
30  double controlledVoltage = 1.0;
31  int controlledVoltageUnitChoice = 0; // 0 = p.u., 1 = same as nominalVoltageUnit (UNIT_V or UNIT_kV).
32  bool slackBus = false;
33 
34  // Power flow (p.u.)
35  std::complex<double> voltage = std::complex<double>(1.0, 0.0);
36  std::complex<double> power = std::complex<double>(0.0, 0.0);
37  int busType = 2; // PQ
38 
39  // Fault
40  bool hasFault = false;
41  FaultData faultType = FAULT_THREEPHASE;
42  FaultData faultLocation = FAULT_LINE_A;
43  // p.u. fault data
44  double faultResistance = 0.0;
45  double faultReactance = 0.0;
46  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
47  std::complex<double>(0.0, 0.0)};
48  std::complex<double> faultVoltage[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
49  std::complex<double>(0.0, 0.0)};
50  double scPower = 0.0;
51 
52  // Stability
53  bool plotBus = false;
54  bool stabHasFault = false;
55  double stabFaultTime = 0.0;
56  double stabFaultLength = 0.0;
57  double stabFaultResistance = 0.0;
58  double stabFaultReactance = 0.0;
59  std::vector<std::complex<double> > stabVoltageVector;
60 };
61 
62 class Bus : public PowerElement
63 {
64  public:
65  Bus();
66  Bus(wxPoint2DDouble position);
67  Bus(wxPoint2DDouble position, wxString name);
68  ~Bus();
69  virtual Element* GetCopy();
70  virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return true; }
71  virtual bool Contains(wxPoint2DDouble position) const;
72  virtual bool Intersects(wxRect2DDouble rect) const;
73  virtual void Draw(wxPoint2DDouble translation, double scale) const;
74  virtual void Rotate(bool clockwise = true);
75  virtual wxCursor GetBestPickboxCursor() const;
76  virtual void MovePickbox(wxPoint2DDouble position);
77  virtual bool PickboxContains(wxPoint2DDouble position);
78  virtual bool GetContextMenu(wxMenu& menu);
79  virtual wxString GetTipText() const;
80  virtual BusElectricalData GetElectricalData() const { return m_electricalData; }
81  virtual void SetElectricalData(BusElectricalData electricalData) { m_electricalData = electricalData; }
82  virtual bool ShowForm(wxWindow* parent, Element* element);
83  virtual bool GetPlotData(ElementPlotData& plotData);
84 
85  protected:
86  BusElectricalData m_electricalData;
87 };
88 
89 #endif // BUS_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BUS_H
19 #define BUS_H
20 
21 #include "BusForm.h"
22 #include "PowerElement.h"
23 
25  int number = 0;
26  wxString name = "";
27  double nominalVoltage = 138.0;
28  ElectricalUnit nominalVoltageUnit = UNIT_kV;
29  bool isVoltageControlled = false;
30  double controlledVoltage = 1.0;
31  int controlledVoltageUnitChoice = 0; // 0 = p.u., 1 = same as nominalVoltageUnit (UNIT_V or UNIT_kV).
32  bool slackBus = false;
33 
34  // Power flow (p.u.)
35  std::complex<double> voltage = std::complex<double>(1.0, 0.0);
36  std::complex<double> power = std::complex<double>(0.0, 0.0);
37  int busType = 2; // PQ
38 
39  // Fault
40  bool hasFault = false;
41  FaultData faultType = FAULT_THREEPHASE;
42  FaultData faultLocation = FAULT_LINE_A;
43  // p.u. fault data
44  double faultResistance = 0.0;
45  double faultReactance = 0.0;
46  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
47  std::complex<double>(0.0, 0.0)};
48  std::complex<double> faultVoltage[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
49  std::complex<double>(0.0, 0.0)};
50  double scPower = 0.0;
51 
52  // Stability
53  bool plotBus = false;
54  bool stabHasFault = false;
55  double stabFaultTime = 0.0;
56  double stabFaultLength = 0.0;
57  double stabFaultResistance = 0.0;
58  double stabFaultReactance = 0.0;
59  std::vector<std::complex<double> > stabVoltageVector;
60 };
61 
69 class Bus : public PowerElement
70 {
71  public:
72  Bus();
73  Bus(wxPoint2DDouble position);
74  Bus(wxPoint2DDouble position, wxString name);
75  ~Bus();
76  virtual Element* GetCopy();
77  virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return true; }
78  virtual bool Contains(wxPoint2DDouble position) const;
79  virtual bool Intersects(wxRect2DDouble rect) const;
80  virtual void Draw(wxPoint2DDouble translation, double scale) const;
81  virtual void Rotate(bool clockwise = true);
82  virtual wxCursor GetBestPickboxCursor() const;
83  virtual void MovePickbox(wxPoint2DDouble position);
84  virtual bool PickboxContains(wxPoint2DDouble position);
85  virtual bool GetContextMenu(wxMenu& menu);
86  virtual wxString GetTipText() const;
87  virtual BusElectricalData GetElectricalData() const { return m_electricalData; }
88  virtual void SetElectricalData(BusElectricalData electricalData) { m_electricalData = electricalData; }
89  virtual bool ShowForm(wxWindow* parent, Element* element);
90  virtual bool GetPlotData(ElementPlotData& plotData);
91 
92  protected:
93  BusElectricalData m_electricalData;
94 };
95 
96 #endif // BUS_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
FaultData
Information about fault (type and location).
Definition: PowerElement.h:55
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
- + -
Switching data of power elements.
-
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Bus.h:70
- + +
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Bus.h:77
+
Abstract class of power elements.
Definition: PowerElement.h:117
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "BusForm.h"
19 #include "Bus.h"
20 
21 BusForm::BusForm(wxWindow* parent, Bus* bus) : BusFormBase(parent)
22 {
23  m_choiceFaultType->SetString(0, _("Three-phase"));
24  m_choiceFaultType->SetString(1, _("Line-to-line"));
25  m_choiceFaultType->SetString(2, _("Double line-to-ground"));
26  m_choiceFaultType->SetString(3, _("Line-to-ground"));
27 
28  SetSize(GetBestSize());
29 
30  m_parent = parent;
31  m_bus = bus;
32 
33  m_textCtrlName->SetValue(bus->GetElectricalData().name);
34  m_textCtrlNomVoltage->SetValue(bus->StringFromDouble(bus->GetElectricalData().nominalVoltage));
35 
36  if(bus->GetElectricalData().nominalVoltageUnit == UNIT_V)
37  m_choiceNomVoltage->SetSelection(0);
38  else
39  m_choiceNomVoltage->SetSelection(1);
40 
41  m_checkBoxCtrlVoltage->SetValue(bus->GetElectricalData().isVoltageControlled);
42  m_textCtrlCtrlVoltage->SetValue(bus->StringFromDouble(bus->GetElectricalData().controlledVoltage));
43  m_choiceCtrlVoltage->SetSelection(bus->GetElectricalData().controlledVoltageUnitChoice);
44  m_checkBoxSlackBus->SetValue(bus->GetElectricalData().slackBus);
45 
46  m_checkBoxFault->SetValue(bus->GetElectricalData().hasFault);
47  switch(bus->GetElectricalData().faultType) {
48  case FAULT_THREEPHASE: {
49  m_choiceFaultType->SetSelection(0);
50  } break;
51  case FAULT_2LINE: {
52  m_choiceFaultType->SetSelection(1);
53  } break;
54  case FAULT_2LINE_GROUND: {
55  m_choiceFaultType->SetSelection(2);
56  } break;
57  case FAULT_LINE_GROUND: {
58  m_choiceFaultType->SetSelection(3);
59  } break;
60  default:
61  break;
62  }
63  switch(bus->GetElectricalData().faultLocation) {
64  case FAULT_LINE_A: {
65  m_choiceFaultPlace->SetSelection(0);
66  } break;
67  case FAULT_LINE_B: {
68  m_choiceFaultPlace->SetSelection(1);
69  } break;
70  case FAULT_LINE_C: {
71  m_choiceFaultPlace->SetSelection(2);
72  } break;
73  default:
74  break;
75  }
76  m_textCtrlFaultResistance->SetValue(bus->StringFromDouble(bus->GetElectricalData().faultResistance));
77  m_textCtrlFaultReactance->SetValue(bus->StringFromDouble(bus->GetElectricalData().faultReactance));
78 
79  m_checkBoxPlotData->SetValue(bus->GetElectricalData().plotBus);
80  m_checkBoxStabFault->SetValue(bus->GetElectricalData().stabHasFault);
81  m_textCtrlStabFaultTime->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultTime));
82  m_textCtrlStabFaultLength->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultLength));
83  m_textCtrlStabFaultResistance->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultResistance));
84  m_textCtrlStabFaultReactance->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultReactance));
85 
86  EnableCtrlVoltageFields(bus->GetElectricalData().isVoltageControlled);
87  EnableFaultFields(bus->GetElectricalData().hasFault);
88  EnableStabFaultFields(bus->GetElectricalData().stabHasFault);
89 }
90 
91 BusForm::~BusForm() {}
92 void BusForm::OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
93 void BusForm::OnButtonOKClick(wxCommandEvent& event)
94 {
95  BusElectricalData data = m_bus->GetElectricalData();
96  data.name = m_textCtrlName->GetValue();
97  if(!m_bus->DoubleFromString(m_parent, m_textCtrlNomVoltage->GetValue(), data.nominalVoltage,
98  _("Value entered incorrectly in the field \"Rated voltage\".")))
99  return;
100  data.nominalVoltageUnit = m_choiceNomVoltage->GetSelection() == 0 ? UNIT_V : UNIT_kV;
101  data.isVoltageControlled = m_checkBoxCtrlVoltage->GetValue();
102  if(data.isVoltageControlled) {
103  if(!m_bus->DoubleFromString(m_parent, m_textCtrlCtrlVoltage->GetValue(), data.controlledVoltage,
104  _("Value entered incorrectly in the field \"Controlled voltage\".")))
105  return;
106  data.controlledVoltageUnitChoice = m_choiceCtrlVoltage->GetSelection();
107  }
108  data.slackBus = m_checkBoxSlackBus->GetValue();
109 
110  data.hasFault = m_checkBoxFault->GetValue();
111  switch(m_choiceFaultType->GetSelection()) {
112  case 0: {
113  data.faultType = FAULT_THREEPHASE;
114  } break;
115  case 1: {
116  data.faultType = FAULT_2LINE;
117  } break;
118  case 2: {
119  data.faultType = FAULT_2LINE_GROUND;
120  } break;
121  case 3: {
122  data.faultType = FAULT_LINE_GROUND;
123  } break;
124  }
125 
126  switch(m_choiceFaultPlace->GetSelection()) {
127  case 0: {
128  data.faultLocation = FAULT_LINE_A;
129  } break;
130  case 1: {
131  data.faultLocation = FAULT_LINE_B;
132  } break;
133  case 2: {
134  data.faultLocation = FAULT_LINE_C;
135  } break;
136  }
137 
138  if(!m_bus->DoubleFromString(m_parent, m_textCtrlFaultResistance->GetValue(), data.faultResistance,
139  _("Value entered incorrectly in the field \"Fault resistance\".")))
140  return;
141 
142  if(!m_bus->DoubleFromString(m_parent, m_textCtrlFaultReactance->GetValue(), data.faultReactance,
143  _("Value entered incorrectly in the field \"Fault reactance\".")))
144  return;
145 
146  data.plotBus = m_checkBoxPlotData->GetValue();
147  data.stabHasFault = m_checkBoxStabFault->GetValue();
148 
149  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultTime->GetValue(), data.stabFaultTime,
150  _("Value entered incorrectly in the field \"Time\".")))
151  return;
152 
153  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultLength->GetValue(), data.stabFaultLength,
154  _("Value entered incorrectly in the field \"Fault lenght\".")))
155  return;
156 
157  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultResistance->GetValue(), data.stabFaultResistance,
158  _("Value entered incorrectly in the field \"Fault resistence (stability)\".")))
159  return;
160 
161  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultReactance->GetValue(), data.stabFaultReactance,
162  _("Value entered incorrectly in the field \"Fault reactance (stability)\".")))
163  return;
164 
165  m_bus->SetElectricalData(data);
166 
167  if(data.stabHasFault)
168  m_bus->SetDynamicEvent(true);
169  else
170  m_bus->SetDynamicEvent(false);
171 
172  EndModal(wxID_OK);
173 }
174 
175 void BusForm::OnNominalVoltageChoice(wxCommandEvent& event) { UpdateChoiceBoxes(); }
176 void BusForm::OnFaultTypeChoice(wxCommandEvent& event) { UpdateChoiceBoxes(); }
177 void BusForm::OnControlledVoltageClick(wxCommandEvent& event)
178 {
179  EnableCtrlVoltageFields(m_checkBoxCtrlVoltage->GetValue());
180 }
181 void BusForm::OnInsertFaultClick(wxCommandEvent& event) { EnableFaultFields(m_checkBoxFault->GetValue()); }
182 void BusForm::OnInsertStabFaultClick(wxCommandEvent& event) { EnableStabFaultFields(m_checkBoxStabFault->GetValue()); }
183 void BusForm::EnableCtrlVoltageFields(bool enable)
184 {
185  m_textCtrlCtrlVoltage->Enable(enable);
186  m_choiceCtrlVoltage->Enable(enable);
187 
188  UpdateChoiceBoxes();
189 }
190 
191 void BusForm::EnableFaultFields(bool enable)
192 {
193  m_choiceFaultType->Enable(enable);
194  m_choiceFaultPlace->Enable(enable);
195  m_textCtrlFaultReactance->Enable(enable);
196  m_textCtrlFaultResistance->Enable(enable);
197  m_staticTextPU_1->Enable(enable);
198  m_staticTextPU_2->Enable(enable);
199 
200  UpdateChoiceBoxes();
201 }
202 
203 void BusForm::EnableStabFaultFields(bool enable)
204 {
205  m_textCtrlStabFaultTime->Enable(enable);
206  m_textCtrlStabFaultLength->Enable(enable);
207  m_staticTextS_1->Enable(enable);
208  m_staticTextS_2->Enable(enable);
209  m_textCtrlStabFaultReactance->Enable(enable);
210  m_textCtrlStabFaultResistance->Enable(enable);
211  m_staticTextPU_3->Enable(enable);
212  m_staticTextPU_4->Enable(enable);
213 }
214 
215 void BusForm::UpdateChoiceBoxes()
216 {
217  switch(m_choiceFaultType->GetSelection()) {
218  case 0: // three-phase
219  {
220  m_choiceFaultPlace->Enable(false);
221  } break;
222  case 1: // line-to-line
223  case 2: // double line-to-line
224  {
225  if(m_checkBoxFault->GetValue()) m_choiceFaultPlace->Enable(true);
226  m_choiceFaultPlace->SetString(0, _("Lines AB"));
227  m_choiceFaultPlace->SetString(1, _("Lines BC"));
228  m_choiceFaultPlace->SetString(2, _("Lines CA"));
229  } break;
230  case 3: // line-to-ground
231  {
232  if(m_checkBoxFault->GetValue()) m_choiceFaultPlace->Enable(true);
233  m_choiceFaultPlace->SetString(0, _("Line A"));
234  m_choiceFaultPlace->SetString(1, _("Line B"));
235  m_choiceFaultPlace->SetString(2, _("Line C"));
236  } break;
237  default:
238  break;
239  }
240  switch(m_choiceNomVoltage->GetSelection()) {
241  case 0: {
242  m_choiceCtrlVoltage->SetString(1, _("V"));
243  } break;
244  case 1: {
245  m_choiceCtrlVoltage->SetString(1, _("kV"));
246  } break;
247  default:
248  break;
249  }
250 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "BusForm.h"
19 #include "Bus.h"
20 
21 BusForm::BusForm(wxWindow* parent, Bus* bus) : BusFormBase(parent)
22 {
23  m_choiceFaultType->SetString(0, _("Three-phase"));
24  m_choiceFaultType->SetString(1, _("Line-to-line"));
25  m_choiceFaultType->SetString(2, _("Double line-to-ground"));
26  m_choiceFaultType->SetString(3, _("Line-to-ground"));
27 
28  SetSize(GetBestSize());
29 
30  m_parent = parent;
31  m_bus = bus;
32 
33  m_textCtrlName->SetValue(bus->GetElectricalData().name);
34  m_textCtrlNomVoltage->SetValue(bus->StringFromDouble(bus->GetElectricalData().nominalVoltage));
35 
36  if(bus->GetElectricalData().nominalVoltageUnit == UNIT_V)
37  m_choiceNomVoltage->SetSelection(0);
38  else
39  m_choiceNomVoltage->SetSelection(1);
40 
41  m_checkBoxCtrlVoltage->SetValue(bus->GetElectricalData().isVoltageControlled);
42  m_textCtrlCtrlVoltage->SetValue(bus->StringFromDouble(bus->GetElectricalData().controlledVoltage));
43  m_choiceCtrlVoltage->SetSelection(bus->GetElectricalData().controlledVoltageUnitChoice);
44  m_checkBoxSlackBus->SetValue(bus->GetElectricalData().slackBus);
45 
46  m_checkBoxFault->SetValue(bus->GetElectricalData().hasFault);
47  switch(bus->GetElectricalData().faultType) {
48  case FAULT_THREEPHASE: {
49  m_choiceFaultType->SetSelection(0);
50  } break;
51  case FAULT_2LINE: {
52  m_choiceFaultType->SetSelection(1);
53  } break;
54  case FAULT_2LINE_GROUND: {
55  m_choiceFaultType->SetSelection(2);
56  } break;
57  case FAULT_LINE_GROUND: {
58  m_choiceFaultType->SetSelection(3);
59  } break;
60  default:
61  break;
62  }
63  switch(bus->GetElectricalData().faultLocation) {
64  case FAULT_LINE_A: {
65  m_choiceFaultPlace->SetSelection(0);
66  } break;
67  case FAULT_LINE_B: {
68  m_choiceFaultPlace->SetSelection(1);
69  } break;
70  case FAULT_LINE_C: {
71  m_choiceFaultPlace->SetSelection(2);
72  } break;
73  default:
74  break;
75  }
76  m_textCtrlFaultResistance->SetValue(bus->StringFromDouble(bus->GetElectricalData().faultResistance));
77  m_textCtrlFaultReactance->SetValue(bus->StringFromDouble(bus->GetElectricalData().faultReactance));
78 
79  m_checkBoxPlotData->SetValue(bus->GetElectricalData().plotBus);
80  m_checkBoxStabFault->SetValue(bus->GetElectricalData().stabHasFault);
81  m_textCtrlStabFaultTime->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultTime));
82  m_textCtrlStabFaultLength->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultLength));
83  m_textCtrlStabFaultResistance->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultResistance));
84  m_textCtrlStabFaultReactance->SetValue(bus->StringFromDouble(bus->GetElectricalData().stabFaultReactance));
85 
86  EnableCtrlVoltageFields(bus->GetElectricalData().isVoltageControlled);
87  EnableFaultFields(bus->GetElectricalData().hasFault);
88  EnableStabFaultFields(bus->GetElectricalData().stabHasFault);
89 }
90 
91 BusForm::~BusForm() {}
92 void BusForm::OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
93 void BusForm::OnButtonOKClick(wxCommandEvent& event)
94 {
95  BusElectricalData data = m_bus->GetElectricalData();
96  data.name = m_textCtrlName->GetValue();
97  if(!m_bus->DoubleFromString(m_parent, m_textCtrlNomVoltage->GetValue(), data.nominalVoltage,
98  _("Value entered incorrectly in the field \"Rated voltage\".")))
99  return;
100  data.nominalVoltageUnit = m_choiceNomVoltage->GetSelection() == 0 ? UNIT_V : UNIT_kV;
101  data.isVoltageControlled = m_checkBoxCtrlVoltage->GetValue();
102  if(data.isVoltageControlled) {
103  if(!m_bus->DoubleFromString(m_parent, m_textCtrlCtrlVoltage->GetValue(), data.controlledVoltage,
104  _("Value entered incorrectly in the field \"Controlled voltage\".")))
105  return;
106  data.controlledVoltageUnitChoice = m_choiceCtrlVoltage->GetSelection();
107  }
108  data.slackBus = m_checkBoxSlackBus->GetValue();
109 
110  data.hasFault = m_checkBoxFault->GetValue();
111  switch(m_choiceFaultType->GetSelection()) {
112  case 0: {
113  data.faultType = FAULT_THREEPHASE;
114  } break;
115  case 1: {
116  data.faultType = FAULT_2LINE;
117  } break;
118  case 2: {
119  data.faultType = FAULT_2LINE_GROUND;
120  } break;
121  case 3: {
122  data.faultType = FAULT_LINE_GROUND;
123  } break;
124  }
125 
126  switch(m_choiceFaultPlace->GetSelection()) {
127  case 0: {
128  data.faultLocation = FAULT_LINE_A;
129  } break;
130  case 1: {
131  data.faultLocation = FAULT_LINE_B;
132  } break;
133  case 2: {
134  data.faultLocation = FAULT_LINE_C;
135  } break;
136  }
137 
138  if(!m_bus->DoubleFromString(m_parent, m_textCtrlFaultResistance->GetValue(), data.faultResistance,
139  _("Value entered incorrectly in the field \"Fault resistance\".")))
140  return;
141 
142  if(!m_bus->DoubleFromString(m_parent, m_textCtrlFaultReactance->GetValue(), data.faultReactance,
143  _("Value entered incorrectly in the field \"Fault reactance\".")))
144  return;
145 
146  data.plotBus = m_checkBoxPlotData->GetValue();
147  data.stabHasFault = m_checkBoxStabFault->GetValue();
148 
149  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultTime->GetValue(), data.stabFaultTime,
150  _("Value entered incorrectly in the field \"Time\".")))
151  return;
152 
153  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultLength->GetValue(), data.stabFaultLength,
154  _("Value entered incorrectly in the field \"Fault lenght\".")))
155  return;
156 
157  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultResistance->GetValue(), data.stabFaultResistance,
158  _("Value entered incorrectly in the field \"Fault resistence (stability)\".")))
159  return;
160 
161  if(!m_bus->DoubleFromString(m_parent, m_textCtrlStabFaultReactance->GetValue(), data.stabFaultReactance,
162  _("Value entered incorrectly in the field \"Fault reactance (stability)\".")))
163  return;
164 
165  m_bus->SetElectricalData(data);
166 
167  if(data.stabHasFault)
168  m_bus->SetDynamicEvent(true);
169  else
170  m_bus->SetDynamicEvent(false);
171 
172  EndModal(wxID_OK);
173 }
174 
175 void BusForm::OnNominalVoltageChoice(wxCommandEvent& event) { UpdateChoiceBoxes(); }
176 void BusForm::OnFaultTypeChoice(wxCommandEvent& event) { UpdateChoiceBoxes(); }
177 void BusForm::OnControlledVoltageClick(wxCommandEvent& event)
178 {
179  EnableCtrlVoltageFields(m_checkBoxCtrlVoltage->GetValue());
180 }
181 void BusForm::OnInsertFaultClick(wxCommandEvent& event) { EnableFaultFields(m_checkBoxFault->GetValue()); }
182 void BusForm::OnInsertStabFaultClick(wxCommandEvent& event) { EnableStabFaultFields(m_checkBoxStabFault->GetValue()); }
183 void BusForm::EnableCtrlVoltageFields(bool enable)
184 {
185  m_textCtrlCtrlVoltage->Enable(enable);
186  m_choiceCtrlVoltage->Enable(enable);
187 
188  UpdateChoiceBoxes();
189 }
190 
191 void BusForm::EnableFaultFields(bool enable)
192 {
193  m_choiceFaultType->Enable(enable);
194  m_choiceFaultPlace->Enable(enable);
195  m_textCtrlFaultReactance->Enable(enable);
196  m_textCtrlFaultResistance->Enable(enable);
197  m_staticTextPU_1->Enable(enable);
198  m_staticTextPU_2->Enable(enable);
199 
200  UpdateChoiceBoxes();
201 }
202 
203 void BusForm::EnableStabFaultFields(bool enable)
204 {
205  m_textCtrlStabFaultTime->Enable(enable);
206  m_textCtrlStabFaultLength->Enable(enable);
207  m_staticTextS_1->Enable(enable);
208  m_staticTextS_2->Enable(enable);
209  m_textCtrlStabFaultReactance->Enable(enable);
210  m_textCtrlStabFaultResistance->Enable(enable);
211  m_staticTextPU_3->Enable(enable);
212  m_staticTextPU_4->Enable(enable);
213 }
214 
215 void BusForm::UpdateChoiceBoxes()
216 {
217  switch(m_choiceFaultType->GetSelection()) {
218  case 0: // three-phase
219  {
220  m_choiceFaultPlace->Enable(false);
221  } break;
222  case 1: // line-to-line
223  case 2: // double line-to-line
224  {
225  if(m_checkBoxFault->GetValue()) m_choiceFaultPlace->Enable(true);
226  m_choiceFaultPlace->SetString(0, _("Lines AB"));
227  m_choiceFaultPlace->SetString(1, _("Lines BC"));
228  m_choiceFaultPlace->SetString(2, _("Lines CA"));
229  } break;
230  case 3: // line-to-ground
231  {
232  if(m_checkBoxFault->GetValue()) m_choiceFaultPlace->Enable(true);
233  m_choiceFaultPlace->SetString(0, _("Line A"));
234  m_choiceFaultPlace->SetString(1, _("Line B"));
235  m_choiceFaultPlace->SetString(2, _("Line C"));
236  } break;
237  default:
238  break;
239  }
240  switch(m_choiceNomVoltage->GetSelection()) {
241  case 0: {
242  m_choiceCtrlVoltage->SetString(1, _("V"));
243  } break;
244  case 1: {
245  m_choiceCtrlVoltage->SetString(1, _("kV"));
246  } break;
247  default:
248  break;
249  }
250 }
-
Definition: Bus.h:62
+ +
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
diff --git a/docs/doxygen/html/_bus_form_8h_source.html b/docs/doxygen/html/_bus_form_8h_source.html index 4278bd7..4f4106d 100644 --- a/docs/doxygen/html/_bus_form_8h_source.html +++ b/docs/doxygen/html/_bus_form_8h_source.html @@ -90,7 +90,7 @@ $(document).ready(function(){initNavTree('_bus_form_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BUSFORM_H
19 #define BUSFORM_H
20 
21 #include "ElementForm.h"
22 class Bus;
23 
31 class BusForm : public BusFormBase
32 {
33  public:
34  BusForm(wxWindow* parent, Bus* bus);
35  virtual ~BusForm();
36 
37  protected:
38  virtual void OnFaultTypeChoice(wxCommandEvent& event);
39  virtual void OnControlledVoltageClick(wxCommandEvent& event);
40  virtual void OnInsertFaultClick(wxCommandEvent& event);
41  virtual void OnInsertStabFaultClick(wxCommandEvent& event);
42  virtual void OnNominalVoltageChoice(wxCommandEvent& event);
43  virtual void OnButtonCancelClick(wxCommandEvent& event);
44  virtual void OnButtonOKClick(wxCommandEvent& event);
45  virtual void EnableCtrlVoltageFields(bool enable = true);
46  virtual void EnableFaultFields(bool enable = true);
47  virtual void EnableStabFaultFields(bool enable = true);
48  virtual void UpdateChoiceBoxes();
49 
50  Bus* m_bus = NULL;
51  wxWindow* m_parent = NULL;
52 };
53 #endif // BUSFORM_H
Form to edit the bus power data.
Definition: BusForm.h:31
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
diff --git a/docs/doxygen/html/_capacitor_8cpp_source.html b/docs/doxygen/html/_capacitor_8cpp_source.html index 14bd837..e97535d 100644 --- a/docs/doxygen/html/_capacitor_8cpp_source.html +++ b/docs/doxygen/html/_capacitor_8cpp_source.html @@ -88,9 +88,9 @@ $(document).ready(function(){initNavTree('_capacitor_8cpp_source.html','');});
Capacitor.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "Capacitor.h"
20 
21 Capacitor::Capacitor() : Shunt() {}
22 Capacitor::Capacitor(wxString name) : Shunt() { m_electricalData.name = name; }
23 Capacitor::~Capacitor() {}
24 bool Capacitor::AddParent(Element* parent, wxPoint2DDouble position)
25 {
26  if(parent) {
27  m_parentList.push_back(parent);
28  parent->AddChild(this);
29  wxPoint2DDouble parentPt =
30  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
31  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
32  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
33 
34  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
35  m_width = 40;
36  m_height = 30;
37  m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
43 
44  m_inserted = true;
45 
46  wxRect2DDouble genRect(0, 0, 0, 0);
47  m_switchRect.push_back(genRect); // Push a general rectangle.
48  UpdateSwitches();
49 
50  return true;
51  }
52  return false;
53 }
54 
55 void Capacitor::Draw(wxPoint2DDouble translation, double scale) const
56 {
57  OpenGLColour elementColour;
58  if(m_online) {
59  if(m_dynEvent)
60  elementColour = m_dynamicEventColour;
61  else
62  elementColour = m_onlineElementColour;
63  } else
64  elementColour = m_offlineElementColour;
65 
66  if(m_inserted) {
67  std::vector<wxPoint2DDouble> capPts;
68  capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0));
69  capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0));
70  capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0));
71  capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0));
72 
73  if(m_selected) {
74  glLineWidth(1.5 + m_borderSize * 2.0);
75  glColor4dv(m_selectionColour.GetRGBA());
76 
77  DrawLine(m_pointList);
78 
79  glPushMatrix();
80  glTranslated(m_position.m_x, m_position.m_y, 0.0);
81  glRotated(m_angle, 0.0, 0.0, 1.0);
82  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
83 
84  DrawLine(capPts, GL_LINES);
85 
86  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0));
87 
88  glPopMatrix();
89 
90  // Draw node selection.
91  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
92  }
93  // Draw Capacitor (layer 2).
94  glLineWidth(1.5);
95  glColor4dv(elementColour.GetRGBA());
96  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
97  DrawLine(m_pointList);
98 
99  DrawSwitches();
100 
101  glPushMatrix();
102  glTranslated(m_position.m_x, m_position.m_y, 0.0);
103  glRotated(m_angle, 0.0, 0.0, 1.0);
104  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
105 
106  glColor4dv(elementColour.GetRGBA());
107  DrawLine(capPts, GL_LINES);
108 
109  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0));
110 
111  glPopMatrix();
112  }
113 }
114 
115 void Capacitor::Rotate(bool clockwise)
116 {
117  double rotAngle = m_rotationAngle;
118  if(!clockwise) rotAngle = -m_rotationAngle;
119 
120  m_angle += rotAngle;
121  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
122  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
123  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
124  UpdateSwitchesPosition();
125 }
126 
127 bool Capacitor::GetContextMenu(wxMenu& menu)
128 {
129  menu.Append(ID_EDIT_ELEMENT, _("Edit Capacitor"));
130  GeneralMenuItens(menu);
131  return true;
132 }
133 
134 bool Capacitor::Contains(wxPoint2DDouble position) const
135 {
136  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
137  return m_rect.Contains(ptR);
138 }
139 
140 bool Capacitor::Intersects(wxRect2DDouble rect) const
141 {
142  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
143 }
144 
145 bool Capacitor::ShowForm(wxWindow* parent, Element* element)
146 {
147  ReactiveShuntElementForm* capacitorForm = new ReactiveShuntElementForm(parent, this);
148  capacitorForm->SetTitle(_("Capacitor"));
149  if(capacitorForm->ShowModal() == wxID_OK) {
150  capacitorForm->Destroy();
151  return true;
152  }
153  capacitorForm->Destroy();
154  return false;
155 }
156 
157 CapacitorElectricalData Capacitor::GetPUElectricalData(double systemPowerBase)
158 {
159  CapacitorElectricalData data = m_electricalData;
160  switch(data.reactivePowerUnit) {
161  case UNIT_VAr: {
162  data.reactivePower = data.reactivePower / systemPowerBase;
163  data.reactivePowerUnit = UNIT_PU;
164  } break;
165  case UNIT_kVAr: {
166  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
167  data.reactivePowerUnit = UNIT_PU;
168  } break;
169  case UNIT_MVAr: {
170  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
171  data.reactivePowerUnit = UNIT_PU;
172  } break;
173  default:
174  break;
175  }
176 
177  return data;
178 }
179 
181 {
182  Capacitor* copy = new Capacitor();
183  *copy = *this;
184  return copy;
185 }
186 
187 wxString Capacitor::GetTipText() const
188 {
189  wxString tipText = m_electricalData.name;
190 
191  // TODO: Avoid reactive power calculation.
192  double reactivePower = m_electricalData.reactivePower;
193  if(!m_online)
194  reactivePower = 0.0;
195  else {
196  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
197  reactivePower *= std::pow(std::abs(v), 2);
198  }
199  tipText += "\n";
200  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
201  switch(m_electricalData.reactivePowerUnit) {
202  case UNIT_PU: {
203  tipText += _(" p.u.");
204  } break;
205  case UNIT_VAr: {
206  tipText += _(" VAr");
207  } break;
208  case UNIT_kVAr: {
209  tipText += _(" kVAr");
210  } break;
211  case UNIT_MVAr: {
212  tipText += _(" MVAr");
213  } break;
214  default:
215  break;
216  }
217 
218  return tipText;
219 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "Capacitor.h"
20 
21 Capacitor::Capacitor() : Shunt() {}
22 Capacitor::Capacitor(wxString name) : Shunt() { m_electricalData.name = name; }
23 Capacitor::~Capacitor() {}
24 bool Capacitor::AddParent(Element* parent, wxPoint2DDouble position)
25 {
26  if(parent) {
27  m_parentList.push_back(parent);
28  parent->AddChild(this);
29  wxPoint2DDouble parentPt =
30  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
31  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
32  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
33 
34  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
35  m_width = 40;
36  m_height = 30;
37  m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
43 
44  m_inserted = true;
45 
46  wxRect2DDouble genRect(0, 0, 0, 0);
47  m_switchRect.push_back(genRect); // Push a general rectangle.
48  UpdateSwitches();
49 
50  return true;
51  }
52  return false;
53 }
54 
55 void Capacitor::Draw(wxPoint2DDouble translation, double scale) const
56 {
57  OpenGLColour elementColour;
58  if(m_online) {
59  if(m_dynEvent)
60  elementColour = m_dynamicEventColour;
61  else
62  elementColour = m_onlineElementColour;
63  } else
64  elementColour = m_offlineElementColour;
65 
66  if(m_inserted) {
67  std::vector<wxPoint2DDouble> capPts;
68  capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0));
69  capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0));
70  capPts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0));
71  capPts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2.0, m_position.m_y - m_height / 2.0 + 10.0));
72 
73  if(m_selected) {
74  glLineWidth(1.5 + m_borderSize * 2.0);
75  glColor4dv(m_selectionColour.GetRGBA());
76 
77  DrawLine(m_pointList);
78 
79  glPushMatrix();
80  glTranslated(m_position.m_x, m_position.m_y, 0.0);
81  glRotated(m_angle, 0.0, 0.0, 1.0);
82  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
83 
84  DrawLine(capPts, GL_LINES);
85 
86  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0));
87 
88  glPopMatrix();
89 
90  // Draw node selection.
91  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
92  }
93  // Draw Capacitor (layer 2).
94  glLineWidth(1.5);
95  glColor4dv(elementColour.GetRGBA());
96  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
97  DrawLine(m_pointList);
98 
99  DrawSwitches();
100 
101  glPushMatrix();
102  glTranslated(m_position.m_x, m_position.m_y, 0.0);
103  glRotated(m_angle, 0.0, 0.0, 1.0);
104  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
105 
106  glColor4dv(elementColour.GetRGBA());
107  DrawLine(capPts, GL_LINES);
108 
109  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0));
110 
111  glPopMatrix();
112  }
113 }
114 
115 void Capacitor::Rotate(bool clockwise)
116 {
117  double rotAngle = m_rotationAngle;
118  if(!clockwise) rotAngle = -m_rotationAngle;
119 
120  m_angle += rotAngle;
121  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
122  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
123  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
124  UpdateSwitchesPosition();
125 }
126 
127 bool Capacitor::GetContextMenu(wxMenu& menu)
128 {
129  menu.Append(ID_EDIT_ELEMENT, _("Edit Capacitor"));
130  GeneralMenuItens(menu);
131  return true;
132 }
133 
134 bool Capacitor::Contains(wxPoint2DDouble position) const
135 {
136  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
137  return m_rect.Contains(ptR);
138 }
139 
140 bool Capacitor::Intersects(wxRect2DDouble rect) const
141 {
142  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
143 }
144 
145 bool Capacitor::ShowForm(wxWindow* parent, Element* element)
146 {
147  ReactiveShuntElementForm* capacitorForm = new ReactiveShuntElementForm(parent, this);
148  capacitorForm->SetTitle(_("Capacitor"));
149  if(capacitorForm->ShowModal() == wxID_OK) {
150  capacitorForm->Destroy();
151  return true;
152  }
153  capacitorForm->Destroy();
154  return false;
155 }
156 
157 CapacitorElectricalData Capacitor::GetPUElectricalData(double systemPowerBase)
158 {
159  CapacitorElectricalData data = m_electricalData;
160  switch(data.reactivePowerUnit) {
161  case UNIT_VAr: {
162  data.reactivePower = data.reactivePower / systemPowerBase;
163  data.reactivePowerUnit = UNIT_PU;
164  } break;
165  case UNIT_kVAr: {
166  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
167  data.reactivePowerUnit = UNIT_PU;
168  } break;
169  case UNIT_MVAr: {
170  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
171  data.reactivePowerUnit = UNIT_PU;
172  } break;
173  default:
174  break;
175  }
176 
177  return data;
178 }
179 
181 {
182  Capacitor* copy = new Capacitor();
183  *copy = *this;
184  return copy;
185 }
186 
187 wxString Capacitor::GetTipText() const
188 {
189  wxString tipText = m_electricalData.name;
190 
191  // TODO: Avoid reactive power calculation.
192  double reactivePower = m_electricalData.reactivePower;
193  if(!m_online)
194  reactivePower = 0.0;
195  else {
196  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
197  reactivePower *= std::pow(std::abs(v), 2);
198  }
199  tipText += "\n";
200  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
201  switch(m_electricalData.reactivePowerUnit) {
202  case UNIT_PU: {
203  tipText += _(" p.u.");
204  } break;
205  case UNIT_VAr: {
206  tipText += _(" VAr");
207  } break;
208  case UNIT_kVAr: {
209  tipText += _(" kVAr");
210  } break;
211  case UNIT_MVAr: {
212  tipText += _(" MVAr");
213  } break;
214  default:
215  break;
216  }
217 
218  return tipText;
219 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Capacitor.cpp:145
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Capacitor.cpp:127
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Capacitor.cpp:115
@@ -100,17 +100,18 @@ $(document).ready(function(){initNavTree('_capacitor_8cpp_source.html','');});
virtual Element * GetCopy()
Get a the element copy.
Definition: Capacitor.cpp:180
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Capacitor.cpp:134
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Capacitor.cpp:140
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Capacitor.cpp:55
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
- - +
Class to manage color of OpenGL.
Definition: Element.h:67
+
Shunt capactior power element.
Definition: Capacitor.h:38
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
-
Definition: Shunt.h:24
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
virtual wxString GetTipText() const
Get the tip text.
Definition: Capacitor.cpp:187
+
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Capacitor.cpp:24
Form to edit the reactive shunt element power data.
diff --git a/docs/doxygen/html/_capacitor_8h.html b/docs/doxygen/html/_capacitor_8h.html new file mode 100644 index 0000000..88cfe9e --- /dev/null +++ b/docs/doxygen/html/_capacitor_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/Capacitor.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Capacitor.h File Reference
+
+
+
#include "Shunt.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  CapacitorElectricalData
 
class  Capacitor
 Shunt capactior power element. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_capacitor_8h_source.html b/docs/doxygen/html/_capacitor_8h_source.html index 179289e..311d0db 100644 --- a/docs/doxygen/html/_capacitor_8h_source.html +++ b/docs/doxygen/html/_capacitor_8h_source.html @@ -88,11 +88,12 @@ $(document).ready(function(){initNavTree('_capacitor_8h_source.html','');});
Capacitor.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CAPACITOR_H
19 #define CAPACITOR_H
20 
21 #include "Shunt.h"
22 
24 
26  wxString name;
27  double reactivePower = 100.0;
28  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
29 };
30 
31 class Capacitor : public Shunt
32 {
33  public:
34  Capacitor();
35  Capacitor(wxString name);
36  ~Capacitor();
37 
38  virtual Element* GetCopy();
39  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
40  virtual void Draw(wxPoint2DDouble translation, double scale) const;
41  virtual bool Contains(wxPoint2DDouble position) const;
42  virtual bool Intersects(wxRect2DDouble rect) const;
43  virtual void Rotate(bool clockwise = true);
44  virtual bool GetContextMenu(wxMenu& menu);
45  virtual wxString GetTipText() const;
46  virtual bool ShowForm(wxWindow* parent, Element* element);
47  virtual CapacitorElectricalData GetElectricalData() { return m_electricalData; }
48  virtual CapacitorElectricalData GetPUElectricalData(double systemPowerBase);
49  virtual void SetElectricalData(CapacitorElectricalData electricalData) { m_electricalData = electricalData; }
50  protected:
51  CapacitorElectricalData m_electricalData;
52 };
53 
54 #endif // CAPACITOR_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CAPACITOR_H
19 #define CAPACITOR_H
20 
21 #include "Shunt.h"
22 
24 
26  wxString name;
27  double reactivePower = 100.0;
28  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
29 };
30 
38 class Capacitor : public Shunt
39 {
40  public:
41  Capacitor();
42  Capacitor(wxString name);
43  ~Capacitor();
44 
45  virtual Element* GetCopy();
46  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
47  virtual void Draw(wxPoint2DDouble translation, double scale) const;
48  virtual bool Contains(wxPoint2DDouble position) const;
49  virtual bool Intersects(wxRect2DDouble rect) const;
50  virtual void Rotate(bool clockwise = true);
51  virtual bool GetContextMenu(wxMenu& menu);
52  virtual wxString GetTipText() const;
53  virtual bool ShowForm(wxWindow* parent, Element* element);
54  virtual CapacitorElectricalData GetElectricalData() { return m_electricalData; }
55  virtual CapacitorElectricalData GetPUElectricalData(double systemPowerBase);
56  virtual void SetElectricalData(CapacitorElectricalData electricalData) { m_electricalData = electricalData; }
57  protected:
58  CapacitorElectricalData m_electricalData;
59 };
60 
61 #endif // CAPACITOR_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- -
Definition: Shunt.h:24
+
Shunt capactior power element.
Definition: Capacitor.h:38
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
Form to edit the reactive shunt element power data.
@@ -100,7 +101,7 @@ $(document).ready(function(){initNavTree('_capacitor_8h_source.html','');});
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ChartView.h"
19 #include "ElementPlotData.h"
20 
21 ChartView::ChartView(wxWindow* parent, std::vector<ElementPlotData> epdList, std::vector<double> time)
22  : ChartViewBase(parent)
23 {
24  m_epdList = epdList;
25  m_time = time;
26  m_xAxisValues = time;
27 
28  m_menuItemShowGrid->Check(m_hideGrid ? false : true);
29  m_menuItemShowLabel->Check(m_showLeg);
30  m_menuItemShowCoordinates->Check(m_showCoords);
31  m_menuItemDarkTheme->Check(m_darkTheme);
32 
33  // Create color property.
34  m_pgPropColor = m_pgMgr->Insert(m_pgPropLineProp, 1, new wxColourProperty(_("Color")));
35  m_pgPropColor->SetEditor(wxT("ChoiceAndButton"));
36  m_pgPropColor->SetValue(static_cast<wxVariant>(*wxBLACK));
37 
38  // Set margins and axis limit to composed mode.
39  m_pgPropMargins->SetValue(wxT("<composed>"));
40  m_pgMgr->Collapse(m_pgPropMargins);
41  m_pgPropAxisLimit->SetValue(wxT("<composed>"));
42  m_pgMgr->Collapse(m_pgPropAxisLimit);
43 
44  // Add line type choices
45  m_pgProplineType->AddChoice(_("Solid"), wxPENSTYLE_SOLID);
46  m_pgProplineType->AddChoice(_("Dot"), wxPENSTYLE_DOT);
47  m_pgProplineType->AddChoice(_("Dash"), wxPENSTYLE_SHORT_DASH);
48  m_pgProplineType->AddChoice(_("Dot and dash"), wxPENSTYLE_DOT_DASH);
49  m_pgProplineType->AddChoice(_("Cross"), wxPENSTYLE_CROSS_HATCH);
50  m_pgProplineType->AddChoice(_("Driagonal cross"), wxPENSTYLE_CROSSDIAG_HATCH);
51 
52  SetMPWindow();
53  GetSizer()->Add(m_mpWindow, 1, wxEXPAND, WXC_FROM_DIP(5));
54  SetTreectrl();
55  Layout();
56  SetInitialSize();
57 
58  BuildColourList();
59 }
60 
61 ChartView::~ChartView() {}
62 void ChartView::SetMPWindow()
63 {
64  m_mpWindow = new mpWindow(this, wxID_ANY);
65 
66  m_mpWindow->SetDoubleBuffered(true);
67 
68  m_mpWindow->SetMargins(20, 10, 40, 60);
69  m_xaxis = new mpScaleX("", mpALIGN_BOTTOM, true);
70  m_yaxis = new mpScaleY("", mpALIGN_LEFT, true);
71  m_xaxis->SetDrawOutsideMargins(false);
72  m_yaxis->SetDrawOutsideMargins(false);
73  m_xaxis->SetTicks(m_hideGrid);
74  m_yaxis->SetTicks(m_hideGrid);
75 
76  m_leg = new mpInfoLegend(wxRect(200, 20, 40, 40), wxWHITE_BRUSH);
77  m_coords = new mpInfoCoords(wxRect(0, 0, 0, 0), wxWHITE_BRUSH);
78 
79  m_chartTitle = new mpText("", 50, 0);
80  wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
81  m_chartTitle->SetFont(chartTitleFont);
82 
83  m_mpWindow->AddLayer(m_xaxis);
84  m_mpWindow->AddLayer(m_yaxis);
85  m_mpWindow->AddLayer(m_leg);
86  m_mpWindow->AddLayer(m_coords);
87  m_mpWindow->AddLayer(m_chartTitle);
88 
89  m_leg->SetVisible(m_showLeg);
90  m_coords->SetVisible(m_showCoords);
91 
92  m_mpWindow->EnableDoubleBuffer(true);
93  m_mpWindow->LockAspect(false);
94  Fit();
95 }
96 
97 void ChartView::SetTreectrl()
98 {
99  wxTreeItemId rootID = m_treeCtrl->AddRoot(wxT("root"));
100  m_treeTimeID = m_treeCtrl->AppendItem(rootID, _("Time"));
101  m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
102 
103  bool firstElement[ElementPlotData::NUM_ELEMENTS];
104  for(int i = 0; i < ElementPlotData::NUM_ELEMENTS; ++i) firstElement[i] = true;
105 
106  wxString rootElementName[ElementPlotData::NUM_ELEMENTS];
107  rootElementName[ElementPlotData::CT_BUS] = _("Bus");
108  rootElementName[ElementPlotData::CT_IND_MOTOR] = _("Induction motor");
109  rootElementName[ElementPlotData::CT_LINE] = _("Line");
110  rootElementName[ElementPlotData::CT_LOAD] = _("Load");
111  rootElementName[ElementPlotData::CT_SHUNT_CAPACITOR] = _("Capacitor");
112  rootElementName[ElementPlotData::CT_SHUNT_INDUCTOR] = _("Inductor");
113  rootElementName[ElementPlotData::CT_SYNC_COMPENSATOR] = _("Synchronous compensator");
114  rootElementName[ElementPlotData::CT_SYNC_GENERATOR] = _("Synchronous generator");
115  rootElementName[ElementPlotData::CT_TRANSFORMER] = _("Transformer");
116  rootElementName[ElementPlotData::CT_TEST] = _("Test");
117 
118  wxTreeItemId rootItemID[ElementPlotData::NUM_ELEMENTS];
119 
120  for(auto it = m_epdList.begin(), itEnd = m_epdList.end(); it != itEnd; ++it) {
121  ElementPlotData data = *it;
122  ElementPlotData::CurveType curveType = data.GetCurveType();
123 
124  if(firstElement[curveType]) {
125  rootItemID[curveType] = m_treeCtrl->AppendItem(rootID, rootElementName[curveType]);
126  firstElement[curveType] = false;
127  }
128  wxTreeItemId itemID = m_treeCtrl->AppendItem(rootItemID[curveType], data.GetName());
129  for(int i = 0; i < data.GetElementDataNumber(); ++i) {
130  m_treeCtrl->AppendItem(itemID, data.GetDataName(i), -1, -1, data.GetPlotData(i));
131  }
132  }
133 }
134 
135 void ChartView::OnPropertyGridChange(wxPropertyGridEvent& event)
136 {
137  bool fit = false;
138 
139  if(m_treeCtrl->GetSelection()) {
140  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(m_treeCtrl->GetSelection()))) {
141  if(event.GetPropertyName() == _("Draw")) {
142  bool isPlotting = m_pgPropDraw->GetValue();
143  data->SetPlot(isPlotting);
144  if(isPlotting) {
145  wxColour colour = GetNextColour();
146  data->SetColour(colour);
147  m_pgPropColor->SetValue(static_cast<wxVariant>(colour));
148  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), true);
149  } else {
150  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
151  }
152  fit = true;
153  } else if(event.GetPropertyName() == _("Color")) {
154  wxColour colour;
155  colour << m_pgPropColor->GetValue();
156  data->SetColour(colour);
157  } else if(event.GetPropertyName() == _("Thickness")) {
158  data->SetThick(m_pgProplineThick->GetValue().GetInteger());
159  } else if(event.GetPropertyName() == _("Type")) {
160  data->SetPenType(static_cast<wxPenStyle>(m_pgProplineType->GetValue().GetInteger()));
161  } else if(event.GetPropertyName() == _("Axis")) {
162  int axis = m_pgProplineAxis->GetValue().GetInteger();
163  if(axis == 1) { // Y
164  // All lines to Y axis
165  AllToYAxis(m_treeCtrl->GetRootItem());
166  // curva selecionada para o eixo X
167  m_treeCtrl->SetItemTextColour(m_treeCtrl->GetSelection(), *wxRED);
168  m_xAxisValues = data->GetValues();
169  }
170  data->SetAxis(axis);
171  fit = true;
172  }
173  }
174  }
175 
176  if(event.GetPropertyName() == _("Margins")) {
177  m_mpWindow->SetMargins(m_pgPropMarginsUp->GetValue().GetLong(), m_pgPropMarginsRight->GetValue().GetLong(),
178  m_pgPropMarginsBot->GetValue().GetLong(), m_pgPropMarginsLeft->GetValue().GetLong());
179  m_mpWindow->UpdateAll();
180  }
181  if(event.GetPropertyName() == _("Axis limit")) {
182  m_mpWindow->Fit(m_pgPropXMin->GetValue().GetDouble(), m_pgPropXMax->GetValue().GetDouble(),
183  m_pgPropYMin->GetValue().GetDouble(), m_pgPropYMax->GetValue().GetDouble());
184  m_mpWindow->UpdateAll();
185  }
186  UpdatePlot(fit);
187 }
188 
189 void ChartView::OnMenuDarkThemeClick(wxCommandEvent& event)
190 {
191  m_darkTheme = event.IsChecked();
192  wxColour grey(96, 96, 96);
193 
194  if(m_darkTheme) {
195  m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
196  m_leg->SetBrush(*wxBLACK_BRUSH);
197  m_coords->SetBrush(*wxBLACK_BRUSH);
198  } else {
199  m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
200  m_leg->SetBrush(*wxWHITE_BRUSH);
201  m_coords->SetBrush(*wxWHITE_BRUSH);
202  }
203 
204  m_mpWindow->UpdateAll();
205 }
206 
207 void ChartView::OnMenuSaveImageClick(wxCommandEvent& event)
208 {
209  int x = m_mpWindow->GetScreenPosition().x;
210  int y = m_mpWindow->GetScreenPosition().y;
211  int width = m_mpWindow->GetSize().GetWidth();
212  int height = m_mpWindow->GetSize().GetHeight();
213 
214  wxScreenDC dcScreen;
215  wxBitmap screenshot(width, height);
216 
217  wxMemoryDC memDC;
218  memDC.SelectObject(screenshot);
219 
220  memDC.Blit(0, 0, width, height, &dcScreen, x, y);
221  memDC.SelectObject(wxNullBitmap);
222 
223  wxFileDialog saveFileDialog(
224  this, _("Save image"), "", "",
225  "PNG image file (*.png)|*.png|Bitmap image file (*.bmp)|*.bmp|JPEG image file (*.jpg)|*.jpg",
226  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
227  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
228 
229  wxFileName imagePath(saveFileDialog.GetPath());
230  wxBitmapType imageType = wxBITMAP_TYPE_BMP;
231 
232  if(imagePath.GetExt() == "png")
233  imageType = wxBITMAP_TYPE_PNG;
234  else if(imagePath.GetExt() == "jpg")
235  imageType = wxBITMAP_TYPE_JPEG;
236 
237  screenshot.SaveFile(imagePath.GetFullPath(), imageType);
238 }
239 
240 void ChartView::OnMenuSendClipClick(wxCommandEvent& event)
241 {
242  int x = m_mpWindow->GetScreenPosition().x;
243  int y = m_mpWindow->GetScreenPosition().y;
244  int width = m_mpWindow->GetSize().GetWidth();
245  int height = m_mpWindow->GetSize().GetHeight();
246 
247  wxScreenDC dcScreen;
248  wxBitmap screenshot(width, height);
249 
250  wxMemoryDC memDC;
251  memDC.SelectObject(screenshot);
252 
253  memDC.Blit(0, 0, width, height, &dcScreen, x, y);
254  memDC.SelectObject(wxNullBitmap);
255 
256  if(wxTheClipboard->Open()) {
257  wxTheClipboard->SetData(new wxBitmapDataObject(screenshot));
258  wxTheClipboard->Close();
259 
260  wxMessageDialog msgDialog(this, _("Chart send to clipboard"), _("Info"), wxOK | wxICON_INFORMATION,
261  wxDefaultPosition);
262  msgDialog.ShowModal();
263  } else {
264  wxMessageDialog msgDialog(this, _("It was not possible to send to clipboard"), _("Error"), wxOK | wxICON_ERROR,
265  wxDefaultPosition);
266  msgDialog.ShowModal();
267  }
268 }
269 
270 void ChartView::OnMenuShowCoordinatesClick(wxCommandEvent& event)
271 {
272  m_showCoords = event.IsChecked();
273  m_coords->SetVisible(m_showCoords);
274  m_mpWindow->UpdateAll();
275 }
276 
277 void ChartView::OnMenuShowGridClick(wxCommandEvent& event)
278 {
279  m_hideGrid = event.IsChecked() ? false : true;
280  m_xaxis->SetTicks(m_hideGrid);
281  m_yaxis->SetTicks(m_hideGrid);
282  m_mpWindow->UpdateAll();
283 }
284 
285 void ChartView::OnMenuShowLabelClick(wxCommandEvent& event)
286 {
287  m_showLeg = event.IsChecked();
288  m_leg->SetVisible(m_showLeg);
289  m_mpWindow->UpdateAll();
290 }
291 
292 void ChartView::Fit()
293 {
294  m_mpWindow->Fit();
295  double bBox[4];
296  m_mpWindow->GetBoundingBox(bBox);
297 
298  m_pgPropXMin->SetValue(bBox[0]);
299  m_pgPropXMax->SetValue(bBox[1]);
300  m_pgPropYMin->SetValue(bBox[2]);
301  m_pgPropYMax->SetValue(bBox[3]);
302 }
303 
304 void ChartView::UpdatePlot(bool fit)
305 {
306  wxRect legRect = m_leg->GetRectangle();
307  wxRect coordsRect = m_coords->GetRectangle();
308  m_mpWindow->DelAllLayers(true, false);
309 
310  // GoAllTrees(treeCtrl_ChartSelection->GetRootItem());
311  UpdateAllPlots(m_treeCtrl->GetRootItem());
312 
313  m_xaxis = new mpScaleX(m_pgPropXLabel->GetValueAsString(), mpALIGN_BOTTOM, true);
314  m_yaxis = new mpScaleY(m_pgPropYLabel->GetValueAsString(), mpALIGN_LEFT, true);
315  m_leg = new mpInfoLegend(legRect, wxWHITE_BRUSH);
316  m_coords = new mpInfoCoords(coordsRect, wxWHITE_BRUSH);
317 
318  m_xaxis->SetDrawOutsideMargins(false);
319  m_yaxis->SetDrawOutsideMargins(false);
320  m_xaxis->SetTicks(m_hideGrid);
321  m_yaxis->SetTicks(m_hideGrid);
322 
323  mpText* chartTitle = new mpText(m_pgPropChartTitle->GetValueAsString(), 50, 0);
324  wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
325  chartTitle->SetFont(chartTitleFont);
326 
327  m_mpWindow->AddLayer(m_xaxis);
328  m_mpWindow->AddLayer(m_yaxis);
329  m_mpWindow->AddLayer(m_leg);
330  m_mpWindow->AddLayer(m_coords);
331  m_mpWindow->AddLayer(chartTitle);
332 
333  m_leg->SetVisible(m_showLeg);
334  m_coords->SetVisible(m_showCoords);
335 
336  if(fit) Fit();
337 
338  wxColour grey(96, 96, 96);
339  if(m_darkTheme) {
340  m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
341  m_leg->SetBrush(*wxBLACK_BRUSH);
342  m_coords->SetBrush(*wxBLACK_BRUSH);
343  } else {
344  m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
345  m_leg->SetBrush(*wxWHITE_BRUSH);
346  m_coords->SetBrush(*wxWHITE_BRUSH);
347  }
348 }
349 
350 void ChartView::OnTreeItemActivated(wxTreeEvent& event)
351 {
352  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(event.GetItem()))) {
353  bool isPlotting = data->IsPlot() ? false : true;
354  data->SetPlot(isPlotting);
355  m_pgPropDraw->SetValue(data->IsPlot());
356  if(isPlotting) {
357  wxColour colour = GetNextColour();
358  data->SetColour(colour);
359  m_pgPropColor->SetValue(static_cast<wxVariant>(colour));
360  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), true);
361  } else {
362  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
363  }
364  UpdatePlot(true);
365  }
366 
367  if(event.GetItem() == m_treeTimeID) {
368  AllToYAxis(m_treeCtrl->GetRootItem());
369  m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
370  m_xAxisValues = m_time;
371  UpdatePlot(true);
372  }
373 
374  event.Skip();
375 }
376 
377 void ChartView::OnTreeItemSelectionChanged(wxTreeEvent& event)
378 {
379  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(event.GetItem()))) {
380  m_pgPropDraw->SetValue(data->IsPlot());
381  wxVariant colour;
382  colour << data->GetColour();
383  m_pgPropColor->SetValue(colour);
384  m_pgProplineThick->SetValue(data->GetThick());
385  m_pgProplineType->SetValue(data->GetPenType());
386  m_pgProplineAxis->SetValue(data->GetAxis());
387  }
388  event.Skip();
389 }
390 
391 void ChartView::BuildColourList()
392 {
393  m_colourList.push_back(wxColour(255, 0, 0));
394  m_colourList.push_back(wxColour(0, 0, 255));
395  m_colourList.push_back(wxColour(0, 255, 0));
396  m_colourList.push_back(wxColour(255, 128, 0));
397  m_colourList.push_back(wxColour(128, 0, 255));
398  m_colourList.push_back(wxColour(0, 255, 128));
399  m_colourList.push_back(wxColour(255, 255, 0));
400  m_colourList.push_back(wxColour(255, 0, 255));
401  m_colourList.push_back(wxColour(0, 255, 255));
402  m_colourList.push_back(wxColour(128, 255, 0));
403  m_colourList.push_back(wxColour(255, 0, 128));
404  m_colourList.push_back(wxColour(0, 128, 255));
405  m_colourList.push_back(wxColour(128, 128, 128));
406  m_colourList.push_back(*wxBLACK);
407  m_itColourList = --m_colourList.end();
408 }
409 
410 wxColour ChartView::GetNextColour()
411 {
412  if(*m_itColourList == *wxBLACK)
413  m_itColourList = m_colourList.begin();
414  else
415  ++m_itColourList;
416 
417  return *m_itColourList;
418 }
419 
420 wxTreeItemId ChartView::AllToYAxis(wxTreeItemId root)
421 {
422  wxTreeItemIdValue cookie;
423  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
424  wxTreeItemId child;
425 
426  while(item.IsOk()) {
427  m_treeCtrl->SetItemTextColour(item, *wxBLACK);
428  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) data->SetAxis(0); // X axis.
429 
430  if(m_treeCtrl->ItemHasChildren(item)) {
431  wxTreeItemId nextChild = AllToYAxis(item);
432  if(nextChild.IsOk()) return nextChild;
433  }
434  item = m_treeCtrl->GetNextChild(root, cookie);
435  }
436 
437  wxTreeItemId dummyID;
438  return dummyID;
439 }
440 
441 wxTreeItemId ChartView::UpdateAllPlots(wxTreeItemId root)
442 {
443  wxTreeItemIdValue cookie;
444  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
445  wxTreeItemId child;
446 
447  while(item.IsOk()) {
448  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) {
449  if(data->IsPlot()) {
450  wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
451  mpFXYVector* newLayer = new mpFXYVector(data->GetName() + " (" + parentName + ")");
452  newLayer->SetData(m_xAxisValues, data->GetValues());
453  newLayer->SetContinuity(true);
454  wxPen layerPen(data->GetColour(), data->GetThick(), data->GetPenType());
455  newLayer->SetPen(layerPen);
456  newLayer->SetDrawOutsideMargins(false);
457  newLayer->ShowName(false);
458 
459  m_mpWindow->AddLayer(newLayer);
460  }
461  }
462 
463  if(m_treeCtrl->ItemHasChildren(item)) {
464  wxTreeItemId nextChild = UpdateAllPlots(item);
465  if(nextChild.IsOk()) return nextChild;
466  }
467  item = m_treeCtrl->GetNextChild(root, cookie);
468  }
469 
470  wxTreeItemId dummyID;
471  return dummyID;
472 }
473 
474 void ChartView::OnMenuExpCSVClick(wxCommandEvent& event)
475 {
476  wxFileDialog saveFileDialog(this, _("Save CSV file"), "", "", "CSV file (*.csv)|*.csv",
477  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
478  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
479 
480  wxTextFile csvFile(saveFileDialog.GetPath());
481  if(!csvFile.Create()) {
482  if(!csvFile.Open()) {
483  wxMessageDialog msgDialog(this, _("It was not possible to open or create the selected file."), _("Error"),
484  wxOK | wxCENTRE | wxICON_ERROR);
485  msgDialog.ShowModal();
486  }
487  } else
488  csvFile.Open();
489  if(csvFile.IsOpened()) {
490  csvFile.Clear();
491  csvFile.AddLine(GetActiveCurvesCSV());
492  csvFile.Write();
493  csvFile.Close();
494  }
495 }
496 
497 wxString ChartView::GetActiveCurvesCSV()
498 {
499  std::vector<PlotData*> activePlotDataList;
500  GetActivePlotData(m_treeCtrl->GetRootItem(), activePlotDataList);
501 
502  std::vector<double> xValues;
503  wxString xName = "";
504 
505  // Find X axis curve, if none is found, X is the m_time.
506  bool foundXAxis = false;
507  for(auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
508  PlotData* data = *it;
509  if(data->GetAxis() == 1) {
510  xValues = data->GetValues();
511  xName = data->GetName();
512  foundXAxis = true;
513  activePlotDataList.erase(it);
514  delete data;
515  break;
516  }
517  }
518  if(!foundXAxis) {
519  xValues = m_time;
520  xName = _("Time");
521  }
522 
523  // Build CSV text.
524  wxString csvText = xName + ";";
525  // Header
526  for(auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
527  PlotData* data = *it;
528  csvText += data->GetName() + ";";
529  }
530  csvText[csvText.length() - 1] = '\n';
531  // Values
532  for(unsigned int i = 0; i < xValues.size(); ++i) {
533  csvText += wxString::FromCDouble(xValues[i], 13) + ";";
534  for(unsigned int j = 0; j < activePlotDataList.size(); ++j) {
535  double value = 0.0;
536  if(i < activePlotDataList[j]->GetValues().size()) {
537  value = activePlotDataList[j]->GetValues()[i];
538  }
539  csvText += wxString::FromCDouble(value, 13) + ";";
540  }
541  csvText[csvText.length() - 1] = '\n';
542  }
543 
544  // Clear active plot data vector.
545  for(auto it = activePlotDataList.begin(); it != activePlotDataList.end(); ++it) {
546  delete(*it);
547  }
548  activePlotDataList.clear();
549 
550  return csvText;
551 }
552 
553 wxTreeItemId ChartView::GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList)
554 {
555  wxTreeItemIdValue cookie;
556  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
557  wxTreeItemId child;
558 
559  while(item.IsOk()) {
560  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) {
561  if(data->IsPlot() || data->GetAxis() == 1) {
562  wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
563 
564  PlotData* dataCopy = new PlotData();
565  *dataCopy = *data;
566  dataCopy->SetName(data->GetName() + " (" + parentName + ")");
567  plotDataList.push_back(dataCopy);
568  }
569  }
570 
571  if(m_treeCtrl->ItemHasChildren(item)) {
572  wxTreeItemId nextChild = GetActivePlotData(item, plotDataList);
573  if(nextChild.IsOk()) return nextChild;
574  }
575  item = m_treeCtrl->GetNextChild(root, cookie);
576  }
577 
578  wxTreeItemId dummyID;
579  return dummyID;
580 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ChartView.h"
19 #include "ElementPlotData.h"
20 
21 ChartView::ChartView(wxWindow* parent, std::vector<ElementPlotData> epdList, std::vector<double> time)
22  : ChartViewBase(parent)
23 {
24  m_epdList = epdList;
25  m_time = time;
26  m_xAxisValues = time;
27 
28  m_menuItemShowGrid->Check(m_hideGrid ? false : true);
29  m_menuItemShowLabel->Check(m_showLeg);
30  m_menuItemShowCoordinates->Check(m_showCoords);
31  m_menuItemDarkTheme->Check(m_darkTheme);
32 
33  // Create color property.
34  m_pgPropColor = m_pgMgr->Insert(m_pgPropLineProp, 1, new wxColourProperty(_("Color")));
35  m_pgPropColor->SetEditor(wxT("ChoiceAndButton"));
36  m_pgPropColor->SetValue(static_cast<wxVariant>(*wxBLACK));
37 
38  // Set margins and axis limit to composed mode.
39  m_pgPropMargins->SetValue(wxT("<composed>"));
40  m_pgMgr->Collapse(m_pgPropMargins);
41  m_pgPropAxisLimit->SetValue(wxT("<composed>"));
42  m_pgMgr->Collapse(m_pgPropAxisLimit);
43 
44  // Add line type choices
45  m_pgProplineType->AddChoice(_("Solid"), wxPENSTYLE_SOLID);
46  m_pgProplineType->AddChoice(_("Dot"), wxPENSTYLE_DOT);
47  m_pgProplineType->AddChoice(_("Dash"), wxPENSTYLE_SHORT_DASH);
48  m_pgProplineType->AddChoice(_("Dot and dash"), wxPENSTYLE_DOT_DASH);
49  m_pgProplineType->AddChoice(_("Cross"), wxPENSTYLE_CROSS_HATCH);
50  m_pgProplineType->AddChoice(_("Driagonal cross"), wxPENSTYLE_CROSSDIAG_HATCH);
51 
52  SetMPWindow();
53  GetSizer()->Add(m_mpWindow, 1, wxEXPAND, WXC_FROM_DIP(5));
54  SetTreectrl();
55  Layout();
56  SetInitialSize();
57 
58  BuildColourList();
59 }
60 
61 ChartView::~ChartView() {}
62 void ChartView::SetMPWindow()
63 {
64  m_mpWindow = new mpWindow(this, wxID_ANY);
65 
66  m_mpWindow->SetDoubleBuffered(true);
67 
68  m_mpWindow->SetMargins(20, 10, 40, 60);
69  m_xaxis = new mpScaleX("", mpALIGN_BOTTOM, true);
70  m_yaxis = new mpScaleY("", mpALIGN_LEFT, true);
71  m_xaxis->SetDrawOutsideMargins(false);
72  m_yaxis->SetDrawOutsideMargins(false);
73  m_xaxis->SetTicks(m_hideGrid);
74  m_yaxis->SetTicks(m_hideGrid);
75 
76  m_leg = new mpInfoLegend(wxRect(200, 20, 40, 40), wxWHITE_BRUSH);
77  m_coords = new mpInfoCoords(wxRect(0, 0, 0, 0), wxWHITE_BRUSH);
78 
79  m_chartTitle = new mpText("", 50, 0);
80  wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
81  m_chartTitle->SetFont(chartTitleFont);
82 
83  m_mpWindow->AddLayer(m_xaxis);
84  m_mpWindow->AddLayer(m_yaxis);
85  m_mpWindow->AddLayer(m_leg);
86  m_mpWindow->AddLayer(m_coords);
87  m_mpWindow->AddLayer(m_chartTitle);
88 
89  m_leg->SetVisible(m_showLeg);
90  m_coords->SetVisible(m_showCoords);
91 
92  m_mpWindow->EnableDoubleBuffer(true);
93  m_mpWindow->LockAspect(false);
94  Fit();
95 }
96 
97 void ChartView::SetTreectrl()
98 {
99  wxTreeItemId rootID = m_treeCtrl->AddRoot(wxT("root"));
100  m_treeTimeID = m_treeCtrl->AppendItem(rootID, _("Time"));
101  m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
102 
103  bool firstElement[ElementPlotData::NUM_ELEMENTS];
104  for(int i = 0; i < ElementPlotData::NUM_ELEMENTS; ++i) firstElement[i] = true;
105 
106  wxString rootElementName[ElementPlotData::NUM_ELEMENTS];
107  rootElementName[ElementPlotData::CT_BUS] = _("Bus");
108  rootElementName[ElementPlotData::CT_IND_MOTOR] = _("Induction motor");
109  rootElementName[ElementPlotData::CT_LINE] = _("Line");
110  rootElementName[ElementPlotData::CT_LOAD] = _("Load");
111  rootElementName[ElementPlotData::CT_SHUNT_CAPACITOR] = _("Capacitor");
112  rootElementName[ElementPlotData::CT_SHUNT_INDUCTOR] = _("Inductor");
113  rootElementName[ElementPlotData::CT_SYNC_COMPENSATOR] = _("Synchronous compensator");
114  rootElementName[ElementPlotData::CT_SYNC_GENERATOR] = _("Synchronous generator");
115  rootElementName[ElementPlotData::CT_TRANSFORMER] = _("Transformer");
116  rootElementName[ElementPlotData::CT_TEST] = _("Test");
117 
118  wxTreeItemId rootItemID[ElementPlotData::NUM_ELEMENTS];
119 
120  for(auto it = m_epdList.begin(), itEnd = m_epdList.end(); it != itEnd; ++it) {
121  ElementPlotData data = *it;
122  ElementPlotData::CurveType curveType = data.GetCurveType();
123 
124  if(firstElement[curveType]) {
125  rootItemID[curveType] = m_treeCtrl->AppendItem(rootID, rootElementName[curveType]);
126  firstElement[curveType] = false;
127  }
128  wxTreeItemId itemID = m_treeCtrl->AppendItem(rootItemID[curveType], data.GetName());
129  for(int i = 0; i < data.GetElementDataNumber(); ++i) {
130  m_treeCtrl->AppendItem(itemID, data.GetDataName(i), -1, -1, data.GetPlotData(i));
131  }
132  }
133 }
134 
135 void ChartView::OnPropertyGridChange(wxPropertyGridEvent& event)
136 {
137  bool fit = false;
138 
139  if(m_treeCtrl->GetSelection()) {
140  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(m_treeCtrl->GetSelection()))) {
141  if(event.GetPropertyName() == _("Draw")) {
142  bool isPlotting = m_pgPropDraw->GetValue();
143  data->SetPlot(isPlotting);
144  if(isPlotting) {
145  wxColour colour = GetNextColour();
146  data->SetColour(colour);
147  m_pgPropColor->SetValue(static_cast<wxVariant>(colour));
148  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), true);
149  } else {
150  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
151  }
152  fit = true;
153  } else if(event.GetPropertyName() == _("Color")) {
154  wxColour colour;
155  colour << m_pgPropColor->GetValue();
156  data->SetColour(colour);
157  } else if(event.GetPropertyName() == _("Thickness")) {
158  data->SetThick(m_pgProplineThick->GetValue().GetInteger());
159  } else if(event.GetPropertyName() == _("Type")) {
160  data->SetPenType(static_cast<wxPenStyle>(m_pgProplineType->GetValue().GetInteger()));
161  } else if(event.GetPropertyName() == _("Axis")) {
162  int axis = m_pgProplineAxis->GetValue().GetInteger();
163  if(axis == 1) { // Y
164  // All lines to Y axis
165  AllToYAxis(m_treeCtrl->GetRootItem());
166  // curva selecionada para o eixo X
167  m_treeCtrl->SetItemTextColour(m_treeCtrl->GetSelection(), *wxRED);
168  m_xAxisValues = data->GetValues();
169  }
170  data->SetAxis(axis);
171  fit = true;
172  }
173  }
174  }
175 
176  if(event.GetPropertyName() == _("Margins")) {
177  m_mpWindow->SetMargins(m_pgPropMarginsUp->GetValue().GetLong(), m_pgPropMarginsRight->GetValue().GetLong(),
178  m_pgPropMarginsBot->GetValue().GetLong(), m_pgPropMarginsLeft->GetValue().GetLong());
179  m_mpWindow->UpdateAll();
180  }
181  if(event.GetPropertyName() == _("Axis limit")) {
182  m_mpWindow->Fit(m_pgPropXMin->GetValue().GetDouble(), m_pgPropXMax->GetValue().GetDouble(),
183  m_pgPropYMin->GetValue().GetDouble(), m_pgPropYMax->GetValue().GetDouble());
184  m_mpWindow->UpdateAll();
185  }
186  UpdatePlot(fit);
187 }
188 
189 void ChartView::OnMenuDarkThemeClick(wxCommandEvent& event)
190 {
191  m_darkTheme = event.IsChecked();
192  wxColour grey(96, 96, 96);
193 
194  if(m_darkTheme) {
195  m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
196  m_leg->SetBrush(*wxBLACK_BRUSH);
197  m_coords->SetBrush(*wxBLACK_BRUSH);
198  } else {
199  m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
200  m_leg->SetBrush(*wxWHITE_BRUSH);
201  m_coords->SetBrush(*wxWHITE_BRUSH);
202  }
203 
204  m_mpWindow->UpdateAll();
205 }
206 
207 void ChartView::OnMenuSaveImageClick(wxCommandEvent& event)
208 {
209  int x = m_mpWindow->GetScreenPosition().x;
210  int y = m_mpWindow->GetScreenPosition().y;
211  int width = m_mpWindow->GetSize().GetWidth();
212  int height = m_mpWindow->GetSize().GetHeight();
213 
214  wxScreenDC dcScreen;
215  wxBitmap screenshot(width, height);
216 
217  wxMemoryDC memDC;
218  memDC.SelectObject(screenshot);
219 
220  memDC.Blit(0, 0, width, height, &dcScreen, x, y);
221  memDC.SelectObject(wxNullBitmap);
222 
223  wxFileDialog saveFileDialog(
224  this, _("Save image"), "", "",
225  "PNG image file (*.png)|*.png|Bitmap image file (*.bmp)|*.bmp|JPEG image file (*.jpg)|*.jpg",
226  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
227  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
228 
229  wxFileName imagePath(saveFileDialog.GetPath());
230  wxBitmapType imageType = wxBITMAP_TYPE_BMP;
231 
232  if(imagePath.GetExt() == "png")
233  imageType = wxBITMAP_TYPE_PNG;
234  else if(imagePath.GetExt() == "jpg")
235  imageType = wxBITMAP_TYPE_JPEG;
236 
237  screenshot.SaveFile(imagePath.GetFullPath(), imageType);
238 }
239 
240 void ChartView::OnMenuSendClipClick(wxCommandEvent& event)
241 {
242  int x = m_mpWindow->GetScreenPosition().x;
243  int y = m_mpWindow->GetScreenPosition().y;
244  int width = m_mpWindow->GetSize().GetWidth();
245  int height = m_mpWindow->GetSize().GetHeight();
246 
247  wxScreenDC dcScreen;
248  wxBitmap screenshot(width, height);
249 
250  wxMemoryDC memDC;
251  memDC.SelectObject(screenshot);
252 
253  memDC.Blit(0, 0, width, height, &dcScreen, x, y);
254  memDC.SelectObject(wxNullBitmap);
255 
256  if(wxTheClipboard->Open()) {
257  wxTheClipboard->SetData(new wxBitmapDataObject(screenshot));
258  wxTheClipboard->Close();
259 
260  wxMessageDialog msgDialog(this, _("Chart send to clipboard"), _("Info"), wxOK | wxICON_INFORMATION,
261  wxDefaultPosition);
262  msgDialog.ShowModal();
263  } else {
264  wxMessageDialog msgDialog(this, _("It was not possible to send to clipboard"), _("Error"), wxOK | wxICON_ERROR,
265  wxDefaultPosition);
266  msgDialog.ShowModal();
267  }
268 }
269 
270 void ChartView::OnMenuShowCoordinatesClick(wxCommandEvent& event)
271 {
272  m_showCoords = event.IsChecked();
273  m_coords->SetVisible(m_showCoords);
274  m_mpWindow->UpdateAll();
275 }
276 
277 void ChartView::OnMenuShowGridClick(wxCommandEvent& event)
278 {
279  m_hideGrid = event.IsChecked() ? false : true;
280  m_xaxis->SetTicks(m_hideGrid);
281  m_yaxis->SetTicks(m_hideGrid);
282  m_mpWindow->UpdateAll();
283 }
284 
285 void ChartView::OnMenuShowLabelClick(wxCommandEvent& event)
286 {
287  m_showLeg = event.IsChecked();
288  m_leg->SetVisible(m_showLeg);
289  m_mpWindow->UpdateAll();
290 }
291 
292 void ChartView::Fit()
293 {
294  m_mpWindow->Fit();
295  double bBox[4];
296  m_mpWindow->GetBoundingBox(bBox);
297 
298  m_pgPropXMin->SetValue(bBox[0]);
299  m_pgPropXMax->SetValue(bBox[1]);
300  m_pgPropYMin->SetValue(bBox[2]);
301  m_pgPropYMax->SetValue(bBox[3]);
302 }
303 
304 void ChartView::UpdatePlot(bool fit)
305 {
306  wxRect legRect = m_leg->GetRectangle();
307  wxRect coordsRect = m_coords->GetRectangle();
308  m_mpWindow->DelAllLayers(true, false);
309 
310  // GoAllTrees(treeCtrl_ChartSelection->GetRootItem());
311  UpdateAllPlots(m_treeCtrl->GetRootItem());
312 
313  m_xaxis = new mpScaleX(m_pgPropXLabel->GetValueAsString(), mpALIGN_BOTTOM, true);
314  m_yaxis = new mpScaleY(m_pgPropYLabel->GetValueAsString(), mpALIGN_LEFT, true);
315  m_leg = new mpInfoLegend(legRect, wxWHITE_BRUSH);
316  m_coords = new mpInfoCoords(coordsRect, wxWHITE_BRUSH);
317 
318  m_xaxis->SetDrawOutsideMargins(false);
319  m_yaxis->SetDrawOutsideMargins(false);
320  m_xaxis->SetTicks(m_hideGrid);
321  m_yaxis->SetTicks(m_hideGrid);
322 
323  mpText* chartTitle = new mpText(m_pgPropChartTitle->GetValueAsString(), 50, 0);
324  wxFont chartTitleFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
325  chartTitle->SetFont(chartTitleFont);
326 
327  m_mpWindow->AddLayer(m_xaxis);
328  m_mpWindow->AddLayer(m_yaxis);
329  m_mpWindow->AddLayer(m_leg);
330  m_mpWindow->AddLayer(m_coords);
331  m_mpWindow->AddLayer(chartTitle);
332 
333  m_leg->SetVisible(m_showLeg);
334  m_coords->SetVisible(m_showCoords);
335 
336  if(fit) Fit();
337 
338  wxColour grey(96, 96, 96);
339  if(m_darkTheme) {
340  m_mpWindow->SetColourTheme(*wxBLACK, *wxWHITE, grey);
341  m_leg->SetBrush(*wxBLACK_BRUSH);
342  m_coords->SetBrush(*wxBLACK_BRUSH);
343  } else {
344  m_mpWindow->SetColourTheme(*wxWHITE, *wxBLACK, grey);
345  m_leg->SetBrush(*wxWHITE_BRUSH);
346  m_coords->SetBrush(*wxWHITE_BRUSH);
347  }
348 }
349 
350 void ChartView::OnTreeItemActivated(wxTreeEvent& event)
351 {
352  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(event.GetItem()))) {
353  bool isPlotting = data->IsPlot() ? false : true;
354  data->SetPlot(isPlotting);
355  m_pgPropDraw->SetValue(data->IsPlot());
356  if(isPlotting) {
357  wxColour colour = GetNextColour();
358  data->SetColour(colour);
359  m_pgPropColor->SetValue(static_cast<wxVariant>(colour));
360  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), true);
361  } else {
362  m_treeCtrl->SetItemBold(m_treeCtrl->GetSelection(), false);
363  }
364  UpdatePlot(true);
365  }
366 
367  if(event.GetItem() == m_treeTimeID) {
368  AllToYAxis(m_treeCtrl->GetRootItem());
369  m_treeCtrl->SetItemTextColour(m_treeTimeID, *wxRED);
370  m_xAxisValues = m_time;
371  UpdatePlot(true);
372  }
373 
374  event.Skip();
375 }
376 
377 void ChartView::OnTreeItemSelectionChanged(wxTreeEvent& event)
378 {
379  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(event.GetItem()))) {
380  m_pgPropDraw->SetValue(data->IsPlot());
381  wxVariant colour;
382  colour << data->GetColour();
383  m_pgPropColor->SetValue(colour);
384  m_pgProplineThick->SetValue(data->GetThick());
385  m_pgProplineType->SetValue(data->GetPenType());
386  m_pgProplineAxis->SetValue(data->GetAxis());
387  }
388  event.Skip();
389 }
390 
391 void ChartView::BuildColourList()
392 {
393  m_colourList.push_back(wxColour(255, 0, 0));
394  m_colourList.push_back(wxColour(0, 0, 255));
395  m_colourList.push_back(wxColour(0, 255, 0));
396  m_colourList.push_back(wxColour(255, 128, 0));
397  m_colourList.push_back(wxColour(128, 0, 255));
398  m_colourList.push_back(wxColour(0, 255, 128));
399  m_colourList.push_back(wxColour(255, 255, 0));
400  m_colourList.push_back(wxColour(255, 0, 255));
401  m_colourList.push_back(wxColour(0, 255, 255));
402  m_colourList.push_back(wxColour(128, 255, 0));
403  m_colourList.push_back(wxColour(255, 0, 128));
404  m_colourList.push_back(wxColour(0, 128, 255));
405  m_colourList.push_back(wxColour(128, 128, 128));
406  m_colourList.push_back(*wxBLACK);
407  m_itColourList = --m_colourList.end();
408 }
409 
410 wxColour ChartView::GetNextColour()
411 {
412  if(*m_itColourList == *wxBLACK)
413  m_itColourList = m_colourList.begin();
414  else
415  ++m_itColourList;
416 
417  return *m_itColourList;
418 }
419 
420 wxTreeItemId ChartView::AllToYAxis(wxTreeItemId root)
421 {
422  wxTreeItemIdValue cookie;
423  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
424  wxTreeItemId child;
425 
426  while(item.IsOk()) {
427  m_treeCtrl->SetItemTextColour(item, *wxBLACK);
428  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) data->SetAxis(0); // X axis.
429 
430  if(m_treeCtrl->ItemHasChildren(item)) {
431  wxTreeItemId nextChild = AllToYAxis(item);
432  if(nextChild.IsOk()) return nextChild;
433  }
434  item = m_treeCtrl->GetNextChild(root, cookie);
435  }
436 
437  wxTreeItemId dummyID;
438  return dummyID;
439 }
440 
441 wxTreeItemId ChartView::UpdateAllPlots(wxTreeItemId root)
442 {
443  wxTreeItemIdValue cookie;
444  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
445  wxTreeItemId child;
446 
447  while(item.IsOk()) {
448  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) {
449  if(data->IsPlot()) {
450  wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
451  mpFXYVector* newLayer = new mpFXYVector(data->GetName() + " (" + parentName + ")");
452  newLayer->SetData(m_xAxisValues, data->GetValues());
453  newLayer->SetContinuity(true);
454  wxPen layerPen(data->GetColour(), data->GetThick(), data->GetPenType());
455  newLayer->SetPen(layerPen);
456  newLayer->SetDrawOutsideMargins(false);
457  newLayer->ShowName(false);
458 
459  m_mpWindow->AddLayer(newLayer);
460  }
461  }
462 
463  if(m_treeCtrl->ItemHasChildren(item)) {
464  wxTreeItemId nextChild = UpdateAllPlots(item);
465  if(nextChild.IsOk()) return nextChild;
466  }
467  item = m_treeCtrl->GetNextChild(root, cookie);
468  }
469 
470  wxTreeItemId dummyID;
471  return dummyID;
472 }
473 
474 void ChartView::OnMenuExpCSVClick(wxCommandEvent& event)
475 {
476  wxFileDialog saveFileDialog(this, _("Save CSV file"), "", "", "CSV file (*.csv)|*.csv",
477  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
478  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
479 
480  wxTextFile csvFile(saveFileDialog.GetPath());
481  if(!csvFile.Create()) {
482  if(!csvFile.Open()) {
483  wxMessageDialog msgDialog(this, _("It was not possible to open or create the selected file."), _("Error"),
484  wxOK | wxCENTRE | wxICON_ERROR);
485  msgDialog.ShowModal();
486  }
487  } else
488  csvFile.Open();
489  if(csvFile.IsOpened()) {
490  csvFile.Clear();
491  csvFile.AddLine(GetActiveCurvesCSV());
492  csvFile.Write();
493  csvFile.Close();
494  }
495 }
496 
497 wxString ChartView::GetActiveCurvesCSV()
498 {
499  std::vector<PlotData*> activePlotDataList;
500  GetActivePlotData(m_treeCtrl->GetRootItem(), activePlotDataList);
501 
502  std::vector<double> xValues;
503  wxString xName = "";
504 
505  // Find X axis curve, if none is found, X is the m_time.
506  bool foundXAxis = false;
507  for(auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
508  PlotData* data = *it;
509  if(data->GetAxis() == 1) {
510  xValues = data->GetValues();
511  xName = data->GetName();
512  foundXAxis = true;
513  activePlotDataList.erase(it);
514  delete data;
515  break;
516  }
517  }
518  if(!foundXAxis) {
519  xValues = m_time;
520  xName = _("Time");
521  }
522 
523  // Build CSV text.
524  wxString csvText = xName + ";";
525  // Header
526  for(auto it = activePlotDataList.begin(), itEnd = activePlotDataList.end(); it != itEnd; ++it) {
527  PlotData* data = *it;
528  csvText += data->GetName() + ";";
529  }
530  csvText[csvText.length() - 1] = '\n';
531  // Values
532  for(unsigned int i = 0; i < xValues.size(); ++i) {
533  csvText += wxString::FromCDouble(xValues[i], 13) + ";";
534  for(unsigned int j = 0; j < activePlotDataList.size(); ++j) {
535  double value = 0.0;
536  if(i < activePlotDataList[j]->GetValues().size()) {
537  value = activePlotDataList[j]->GetValues()[i];
538  }
539  csvText += wxString::FromCDouble(value, 13) + ";";
540  }
541  csvText[csvText.length() - 1] = '\n';
542  }
543 
544  // Clear active plot data vector.
545  for(auto it = activePlotDataList.begin(); it != activePlotDataList.end(); ++it) {
546  delete(*it);
547  }
548  activePlotDataList.clear();
549 
550  return csvText;
551 }
552 
553 wxTreeItemId ChartView::GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList)
554 {
555  wxTreeItemIdValue cookie;
556  wxTreeItemId item = m_treeCtrl->GetFirstChild(root, cookie);
557  wxTreeItemId child;
558 
559  while(item.IsOk()) {
560  if(PlotData* data = dynamic_cast<PlotData*>(m_treeCtrl->GetItemData(item))) {
561  if(data->IsPlot() || data->GetAxis() == 1) {
562  wxString parentName = m_treeCtrl->GetItemText(m_treeCtrl->GetItemParent(item));
563 
564  PlotData* dataCopy = new PlotData();
565  *dataCopy = *data;
566  dataCopy->SetName(data->GetName() + " (" + parentName + ")");
567  plotDataList.push_back(dataCopy);
568  }
569  }
570 
571  if(m_treeCtrl->ItemHasChildren(item)) {
572  wxTreeItemId nextChild = GetActivePlotData(item, plotDataList);
573  if(nextChild.IsOk()) return nextChild;
574  }
575  item = m_treeCtrl->GetNextChild(root, cookie);
576  }
577 
578  wxTreeItemId dummyID;
579  return dummyID;
580 }
- - + + +
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...
diff --git a/docs/doxygen/html/_chart_view_8h_source.html b/docs/doxygen/html/_chart_view_8h_source.html index 45a3f99..f861742 100644 --- a/docs/doxygen/html/_chart_view_8h_source.html +++ b/docs/doxygen/html/_chart_view_8h_source.html @@ -89,9 +89,9 @@ $(document).ready(function(){initNavTree('_chart_view_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CHARTVIEW_H
19 #define CHARTVIEW_H
20 #include "ChartViewBase.h"
21 #include "wxMathPlot/mathplot.h"
22 
23 #include <wx/msgdlg.h>
24 #include <wx/clipbrd.h>
25 #include <wx/bitmap.h>
26 #include <wx/dcscreen.h>
27 #include <wx/filedlg.h>
28 #include <wx/textfile.h>
29 
30 class PlotData;
31 class ElementPlotData;
32 
40 class ChartView : public ChartViewBase
41 {
42  public:
43  ChartView(wxWindow* parent, std::vector<ElementPlotData> epdList, std::vector<double> time);
44  virtual ~ChartView();
45 
46  void Fit();
47  void UpdatePlot(bool fit = true);
48 
49  protected:
50  virtual void OnMenuExpCSVClick(wxCommandEvent& event);
51  virtual void OnTreeItemActivated(wxTreeEvent& event);
52  virtual void OnTreeItemSelectionChanged(wxTreeEvent& event);
53  virtual void OnMenuDarkThemeClick(wxCommandEvent& event);
54  virtual void OnMenuExitClick(wxCommandEvent& event) { Close(); }
55  virtual void OnMenuFitClick(wxCommandEvent& event) { Fit(); }
56  virtual void OnMenuSaveImageClick(wxCommandEvent& event);
57  virtual void OnMenuSendClipClick(wxCommandEvent& event);
58  virtual void OnMenuShowCoordinatesClick(wxCommandEvent& event);
59  virtual void OnMenuShowGridClick(wxCommandEvent& event);
60  virtual void OnMenuShowLabelClick(wxCommandEvent& event);
61  virtual void OnPropertyGridChange(wxPropertyGridEvent& event);
62  virtual void SetMPWindow();
63  virtual void SetTreectrl();
64  virtual void BuildColourList();
65  virtual wxColour GetNextColour();
66  virtual wxTreeItemId AllToYAxis(wxTreeItemId root);
67  virtual wxTreeItemId UpdateAllPlots(wxTreeItemId root);
68  virtual wxString GetActiveCurvesCSV();
69  virtual wxTreeItemId GetActivePlotData(wxTreeItemId root, std::vector<PlotData*>& plotDataList);
70 
71  wxPGProperty* m_pgPropColor = NULL;
72 
73  wxTreeItemId m_treeTimeID;
74 
75  std::vector<ElementPlotData> m_epdList;
76  std::vector<double> m_time;
77  std::vector<double> m_xAxisValues;
78 
79  mpWindow* m_mpWindow = NULL;
80  mpScaleX* m_xaxis = NULL;
81  mpScaleY* m_yaxis = NULL;
82  mpText* m_chartTitle = NULL;
83  mpInfoCoords* m_coords = NULL;
84  mpInfoLegend* m_leg = NULL;
85 
86  bool m_hideGrid = true;
87  bool m_showLeg = true;
88  bool m_showCoords = false;
89  bool m_darkTheme = false;
90 
91  std::vector<wxColour> m_colourList;
92  std::vector<wxColour>::iterator m_itColourList;
93 };
94 #endif // CHARTVIEW_H
- +
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
- +
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...
diff --git a/docs/doxygen/html/_connection_line_8cpp_source.html b/docs/doxygen/html/_connection_line_8cpp_source.html index e9e19ff..01771a2 100644 --- a/docs/doxygen/html/_connection_line_8cpp_source.html +++ b/docs/doxygen/html/_connection_line_8cpp_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_connection_line_8cpp_source.html','')
ConnectionLine.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ConnectionLine.h"
19 
20 ConnectionLine::ConnectionLine() : ControlElement(-1) {}
21 ConnectionLine::ConnectionLine(Node* firstNode, int id) : ControlElement(id)
22 {
23  wxPoint2DDouble pt = firstNode->GetPosition();
24  m_tmpSndPt = pt;
25  for(int i = 0; i < 6; i++) {
26  m_pointList.push_back(pt);
27  }
28  m_nodeList.push_back(firstNode);
29  firstNode->SetConnected();
30 }
31 
32 ConnectionLine::~ConnectionLine() {}
33 void ConnectionLine::Draw(wxPoint2DDouble translation, double scale) const
34 {
35  // Line selected (Layer 1).
36  if(m_selected) {
37  glLineWidth(1.5 + m_borderSize * 2.0);
38  glColor4dv(m_selectionColour.GetRGBA());
39  DrawLine(m_pointList);
40  }
41 
42  // Draw line (Layer 2)
43  glLineWidth(1.5);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawLine(m_pointList);
46 
47  if(m_type == ELEMENT_LINE) {
48  glColor4d(0.0, 0.0, 0.0, 1.0);
49  DrawCircle(m_pointList[5], 3, 10, GL_POLYGON);
50  }
51 }
52 
53 bool ConnectionLine::Contains(wxPoint2DDouble position) const
54 {
55  if(PointToLineDistance(position) < 5.0) {
56  return true;
57  }
58  return false;
59 }
60 
61 bool ConnectionLine::Intersects(wxRect2DDouble rect) const
62 {
63  for(auto it = m_pointList.begin(); it != m_pointList.end(); ++it) {
64  if(rect.Contains(*it)) return true;
65  }
66  return false;
67 }
68 
69 void ConnectionLine::UpdatePoints()
70 {
71  if(m_type == ELEMENT_ELEMENT) {
72  bool hasOneNode = true;
73  wxPoint2DDouble pt1 = m_nodeList[0]->GetPosition();
74  wxPoint2DDouble pt2;
75  if(m_nodeList.size() == 1)
76  pt2 = m_tmpSndPt;
77  else {
78  pt2 = m_nodeList[1]->GetPosition();
79  hasOneNode = false;
80  }
81  wxPoint2DDouble midPt = (pt1 + pt2) / 2.0 + wxPoint2DDouble(0.0, m_lineOffset);
82 
83  m_pointList[0] = pt1;
84  if(m_nodeList[0]->GetAngle() == 0.0)
85  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(-10, 0);
86  else if(m_nodeList[0]->GetAngle() == 90.0)
87  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, -10);
88  else if(m_nodeList[0]->GetAngle() == 180.0)
89  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(10, 0);
90  else if(m_nodeList[0]->GetAngle() == 270.0)
91  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, 10);
92 
93  m_pointList[2] = m_pointList[1] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[1].m_y);
94 
95  m_pointList[5] = pt2;
96  if(hasOneNode)
97  m_pointList[4] = pt2;
98  else {
99  if(m_nodeList[1]->GetAngle() == 0.0)
100  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(-10, 0);
101  else if(m_nodeList[1]->GetAngle() == 90.0)
102  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, -10);
103  else if(m_nodeList[1]->GetAngle() == 180.0)
104  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(10, 0);
105  else if(m_nodeList[1]->GetAngle() == 270.0)
106  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, 10);
107  }
108 
109  m_pointList[3] = m_pointList[4] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[4].m_y);
110  } else if(m_type == ELEMENT_LINE) {
111  wxPoint2DDouble pt1 = m_nodeList[0]->GetPosition();
112  wxPoint2DDouble pt2 = m_parentLine->GetMidPoint();
113  wxPoint2DDouble midPt = (pt1 + pt2) / 2.0 + wxPoint2DDouble(0.0, m_lineOffset);
114 
115  m_pointList[0] = pt1;
116  if(m_nodeList[0]->GetAngle() == 0.0)
117  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(-10, 0);
118  else if(m_nodeList[0]->GetAngle() == 90.0)
119  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, -10);
120  else if(m_nodeList[0]->GetAngle() == 180.0)
121  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(10, 0);
122  else if(m_nodeList[0]->GetAngle() == 270.0)
123  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, 10);
124 
125  m_pointList[2] = m_pointList[1] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[1].m_y);
126 
127  m_pointList[5] = pt2;
128  if(m_pointList[2].m_y > pt2.m_y) {
129  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, 10);
130  } else {
131  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, -10);
132  }
133 
134  m_pointList[3] = m_pointList[4] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[4].m_y);
135  }
136  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
137  ConnectionLine* child = static_cast<ConnectionLine*>(*it);
138  child->UpdatePoints();
139  }
140 }
141 
142 bool ConnectionLine::AppendNode(Node* node, ControlElement* parent)
143 {
144  if(m_nodeList.size() != 1) return false;
145  if(m_nodeList[0] == node) return false;
146  if(m_nodeList[0]->GetNodeType() == node->GetNodeType()) return false;
147  auto nodeList = parent->GetNodeList();
148  for(auto it = nodeList.begin(), itEnd = nodeList.end(); it != itEnd; ++it) {
149  Node* parentNode = *it;
150  if(parentNode == m_nodeList[0]) return false;
151  }
152 
153  m_nodeList.push_back(node);
154  node->SetConnected();
155  return true;
156 }
157 
158 void ConnectionLine::Move(wxPoint2DDouble position)
159 {
160  m_lineOffset = m_moveStartOffset + position.m_y - m_moveStartPtY;
161  UpdatePoints();
162 }
163 
164 void ConnectionLine::StartMove(wxPoint2DDouble position)
165 {
166  m_moveStartPtY = position.m_y;
167  m_moveStartOffset = m_lineOffset;
168 }
169 
170 wxPoint2DDouble ConnectionLine::GetMidPoint() const { return ((m_pointList[2] + m_pointList[3]) / 2.0); }
171 bool ConnectionLine::SetParentLine(ConnectionLine* parent)
172 {
173  if(m_nodeList[0]->GetNodeType() != Node::NODE_IN) return false;
174  if(!parent) return false;
175 
176  m_type = ELEMENT_LINE;
177  m_parentLine = parent;
178  return true;
179 }
180 
181 std::vector<ConnectionLine*> ConnectionLine::GetLineChildList() const
182 {
183  std::vector<ConnectionLine*> childList;
184  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
185  ConnectionLine* child = static_cast<ConnectionLine*>(*it);
186  childList.push_back(child);
187  }
188  return childList;
189 }
190 
192 {
193  for(auto it = m_parentList.begin(); it != m_parentList.end(); ++it) {
194  Element* element = *it;
195  if(element == parent) m_parentList.erase(it--);
196  }
197 }
198 
200 {
201  ConnectionLine* copy = new ConnectionLine();
202  *copy = *this;
203  return copy;
204 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ConnectionLine.h"
19 
20 ConnectionLine::ConnectionLine() : ControlElement(-1) {}
21 ConnectionLine::ConnectionLine(Node* firstNode, int id) : ControlElement(id)
22 {
23  wxPoint2DDouble pt = firstNode->GetPosition();
24  m_tmpSndPt = pt;
25  for(int i = 0; i < 6; i++) {
26  m_pointList.push_back(pt);
27  }
28  m_nodeList.push_back(firstNode);
29  firstNode->SetConnected();
30 }
31 
32 ConnectionLine::~ConnectionLine() {}
33 void ConnectionLine::Draw(wxPoint2DDouble translation, double scale) const
34 {
35  // Line selected (Layer 1).
36  if(m_selected) {
37  glLineWidth(1.5 + m_borderSize * 2.0);
38  glColor4dv(m_selectionColour.GetRGBA());
39  DrawLine(m_pointList);
40  }
41 
42  // Draw line (Layer 2)
43  glLineWidth(1.5);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawLine(m_pointList);
46 
47  if(m_type == ELEMENT_LINE) {
48  glColor4d(0.0, 0.0, 0.0, 1.0);
49  DrawCircle(m_pointList[5], 3, 10, GL_POLYGON);
50  }
51 }
52 
53 bool ConnectionLine::Contains(wxPoint2DDouble position) const
54 {
55  if(PointToLineDistance(position) < 5.0) {
56  return true;
57  }
58  return false;
59 }
60 
61 bool ConnectionLine::Intersects(wxRect2DDouble rect) const
62 {
63  for(auto it = m_pointList.begin(); it != m_pointList.end(); ++it) {
64  if(rect.Contains(*it)) return true;
65  }
66  return false;
67 }
68 
69 void ConnectionLine::UpdatePoints()
70 {
71  if(m_type == ELEMENT_ELEMENT) {
72  bool hasOneNode = true;
73  wxPoint2DDouble pt1 = m_nodeList[0]->GetPosition();
74  wxPoint2DDouble pt2;
75  if(m_nodeList.size() == 1)
76  pt2 = m_tmpSndPt;
77  else {
78  pt2 = m_nodeList[1]->GetPosition();
79  hasOneNode = false;
80  }
81  wxPoint2DDouble midPt = (pt1 + pt2) / 2.0 + wxPoint2DDouble(0.0, m_lineOffset);
82 
83  m_pointList[0] = pt1;
84  if(m_nodeList[0]->GetAngle() == 0.0)
85  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(-10, 0);
86  else if(m_nodeList[0]->GetAngle() == 90.0)
87  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, -10);
88  else if(m_nodeList[0]->GetAngle() == 180.0)
89  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(10, 0);
90  else if(m_nodeList[0]->GetAngle() == 270.0)
91  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, 10);
92 
93  m_pointList[2] = m_pointList[1] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[1].m_y);
94 
95  m_pointList[5] = pt2;
96  if(hasOneNode)
97  m_pointList[4] = pt2;
98  else {
99  if(m_nodeList[1]->GetAngle() == 0.0)
100  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(-10, 0);
101  else if(m_nodeList[1]->GetAngle() == 90.0)
102  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, -10);
103  else if(m_nodeList[1]->GetAngle() == 180.0)
104  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(10, 0);
105  else if(m_nodeList[1]->GetAngle() == 270.0)
106  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, 10);
107  }
108 
109  m_pointList[3] = m_pointList[4] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[4].m_y);
110  } else if(m_type == ELEMENT_LINE) {
111  wxPoint2DDouble pt1 = m_nodeList[0]->GetPosition();
112  wxPoint2DDouble pt2 = m_parentLine->GetMidPoint();
113  wxPoint2DDouble midPt = (pt1 + pt2) / 2.0 + wxPoint2DDouble(0.0, m_lineOffset);
114 
115  m_pointList[0] = pt1;
116  if(m_nodeList[0]->GetAngle() == 0.0)
117  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(-10, 0);
118  else if(m_nodeList[0]->GetAngle() == 90.0)
119  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, -10);
120  else if(m_nodeList[0]->GetAngle() == 180.0)
121  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(10, 0);
122  else if(m_nodeList[0]->GetAngle() == 270.0)
123  m_pointList[1] = m_pointList[0] + wxPoint2DDouble(0, 10);
124 
125  m_pointList[2] = m_pointList[1] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[1].m_y);
126 
127  m_pointList[5] = pt2;
128  if(m_pointList[2].m_y > pt2.m_y) {
129  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, 10);
130  } else {
131  m_pointList[4] = m_pointList[5] + wxPoint2DDouble(0, -10);
132  }
133 
134  m_pointList[3] = m_pointList[4] + wxPoint2DDouble(0.0, midPt.m_y - m_pointList[4].m_y);
135  }
136  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
137  ConnectionLine* child = static_cast<ConnectionLine*>(*it);
138  child->UpdatePoints();
139  }
140 }
141 
142 bool ConnectionLine::AppendNode(Node* node, ControlElement* parent)
143 {
144  if(m_nodeList.size() != 1) return false;
145  if(m_nodeList[0] == node) return false;
146  if(m_nodeList[0]->GetNodeType() == node->GetNodeType()) return false;
147  auto nodeList = parent->GetNodeList();
148  for(auto it = nodeList.begin(), itEnd = nodeList.end(); it != itEnd; ++it) {
149  Node* parentNode = *it;
150  if(parentNode == m_nodeList[0]) return false;
151  }
152 
153  m_nodeList.push_back(node);
154  node->SetConnected();
155  return true;
156 }
157 
158 void ConnectionLine::Move(wxPoint2DDouble position)
159 {
160  m_lineOffset = m_moveStartOffset + position.m_y - m_moveStartPtY;
161  UpdatePoints();
162 }
163 
164 void ConnectionLine::StartMove(wxPoint2DDouble position)
165 {
166  m_moveStartPtY = position.m_y;
167  m_moveStartOffset = m_lineOffset;
168 }
169 
170 wxPoint2DDouble ConnectionLine::GetMidPoint() const { return ((m_pointList[2] + m_pointList[3]) / 2.0); }
171 bool ConnectionLine::SetParentLine(ConnectionLine* parent)
172 {
173  if(m_nodeList[0]->GetNodeType() != Node::NODE_IN) return false;
174  if(!parent) return false;
175 
176  m_type = ELEMENT_LINE;
177  m_parentLine = parent;
178  return true;
179 }
180 
181 std::vector<ConnectionLine*> ConnectionLine::GetLineChildList() const
182 {
183  std::vector<ConnectionLine*> childList;
184  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
185  ConnectionLine* child = static_cast<ConnectionLine*>(*it);
186  childList.push_back(child);
187  }
188  return childList;
189 }
190 
192 {
193  for(auto it = m_parentList.begin(); it != m_parentList.end(); ++it) {
194  Element* element = *it;
195  if(element == parent) m_parentList.erase(it--);
196  }
197 }
198 
200 {
201  ConnectionLine* copy = new ConnectionLine();
202  *copy = *this;
203  return copy;
204 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Node of a control element. This class manages the user interaction with the connection and control el...
Element * GetCopy()
Get a the element copy.
diff --git a/docs/doxygen/html/_connection_line_8h_source.html b/docs/doxygen/html/_connection_line_8h_source.html index 5705bd2..0c1688b 100644 --- a/docs/doxygen/html/_connection_line_8h_source.html +++ b/docs/doxygen/html/_connection_line_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_connection_line_8h_source.html','');}
ConnectionLine.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONNECTIONLINE_H
19 #define CONNECTIONLINE_H
20 
21 #include "ControlElement.h"
22 
31 {
32  public:
33  enum ConnectionLineType { ELEMENT_ELEMENT = 0, ELEMENT_LINE };
35  ConnectionLine(Node* firstNode, int id);
36  ~ConnectionLine();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const;
40  virtual bool Intersects(wxRect2DDouble rect) const;
41  virtual void RemoveParent(Element* parent);
42  virtual void StartMove(wxPoint2DDouble position);
43  virtual void Move(wxPoint2DDouble position);
44  virtual bool AppendNode(Node* node, ControlElement* parent);
45  virtual void UpdatePoints();
46  virtual void SetTemporarySecondPoint(wxPoint2DDouble point) { m_tmpSndPt = point; }
47  virtual wxPoint2DDouble GetMidPoint() const;
48  virtual double GetOffset() const { return m_lineOffset; }
49  virtual void SetOffset(double offset) { m_lineOffset = offset; }
50  virtual ConnectionLineType GetType() const { return m_type; }
51  virtual void SetType(ConnectionLineType newType) { m_type = newType; }
52  virtual ConnectionLine* GetParentLine() const { return m_parentLine; }
53  virtual bool SetParentLine(ConnectionLine* parent);
54 
55  virtual std::vector<ConnectionLine*> GetLineChildList() const;
56 
57  virtual double GetValue() const { return m_value; }
58  virtual void SetValue(double value) { m_value = value; }
59  Element* GetCopy();
60 
61  protected:
62  double m_lineOffset = 0.0;
63  double m_moveStartPtY = 0.0;
64  double m_moveStartOffset = 0.0;
65  wxPoint2DDouble m_tmpSndPt;
66 
67  ConnectionLineType m_type = ELEMENT_ELEMENT;
68  ConnectionLine* m_parentLine = NULL;
69 
70  double m_value;
71 };
72 
73 #endif // CONNECTIONLINE_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONNECTIONLINE_H
19 #define CONNECTIONLINE_H
20 
21 #include "ControlElement.h"
22 
31 {
32  public:
33  enum ConnectionLineType { ELEMENT_ELEMENT = 0, ELEMENT_LINE };
35  ConnectionLine(Node* firstNode, int id);
36  ~ConnectionLine();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const;
40  virtual bool Intersects(wxRect2DDouble rect) const;
41  virtual void RemoveParent(Element* parent);
42  virtual void StartMove(wxPoint2DDouble position);
43  virtual void Move(wxPoint2DDouble position);
44  virtual bool AppendNode(Node* node, ControlElement* parent);
45  virtual void UpdatePoints();
46  virtual void SetTemporarySecondPoint(wxPoint2DDouble point) { m_tmpSndPt = point; }
47  virtual wxPoint2DDouble GetMidPoint() const;
48  virtual double GetOffset() const { return m_lineOffset; }
49  virtual void SetOffset(double offset) { m_lineOffset = offset; }
50  virtual ConnectionLineType GetType() const { return m_type; }
51  virtual void SetType(ConnectionLineType newType) { m_type = newType; }
52  virtual ConnectionLine* GetParentLine() const { return m_parentLine; }
53  virtual bool SetParentLine(ConnectionLine* parent);
54 
55  virtual std::vector<ConnectionLine*> GetLineChildList() const;
56 
57  virtual double GetValue() const { return m_value; }
58  virtual void SetValue(double value) { m_value = value; }
59  Element* GetCopy();
60 
61  protected:
62  double m_lineOffset = 0.0;
63  double m_moveStartPtY = 0.0;
64  double m_moveStartOffset = 0.0;
65  wxPoint2DDouble m_tmpSndPt;
66 
67  ConnectionLineType m_type = ELEMENT_ELEMENT;
68  ConnectionLine* m_parentLine = NULL;
69 
70  double m_value;
71 };
72 
73 #endif // CONNECTIONLINE_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Node of a control element. This class manages the user interaction with the connection and control el...
Element * GetCopy()
Get a the element copy.
diff --git a/docs/doxygen/html/_constant_8cpp_source.html b/docs/doxygen/html/_constant_8cpp_source.html index 0a18ef1..2329458 100644 --- a/docs/doxygen/html/_constant_8cpp_source.html +++ b/docs/doxygen/html/_constant_8cpp_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_constant_8cpp_source.html','');});
Constant.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Constant.h"
19 #include "ConstantForm.h"
20 
21 Constant::Constant(int id) : ControlElement(id)
22 {
23  SetValue(m_value);
24  m_angle = 180.0;
25  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
26  nodeOut->SetAngle(180.0);
27  nodeOut->StartMove(m_position);
28  m_nodeList.push_back(nodeOut);
29 }
30 
31 Constant::~Constant() {}
32 void Constant::Draw(wxPoint2DDouble translation, double scale) const
33 {
34  glLineWidth(1.0);
35  if(m_selected) {
36  glColor4dv(m_selectionColour.GetRGBA());
37  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
38  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
39  }
40  glColor4d(1.0, 1.0, 1.0, 1.0);
41  DrawRectangle(m_position, m_width, m_height);
42  glColor4d(0.0, 0.0, 0.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
44 
45  // Plot number.
46  glEnable(GL_TEXTURE_2D);
47  glColor4d(0.0, 0.0, 0.0, 1.0);
48  m_glStringValue->bind();
49  m_glStringValue->render(m_position.m_x, m_position.m_y);
50  glDisable(GL_TEXTURE_2D);
51 
52  glColor4d(0.0, 0.0, 0.0, 1.0);
53  DrawNodes();
54 }
55 
56 bool Constant::ShowForm(wxWindow* parent, Element* element)
57 {
58  ConstantForm* form = new ConstantForm(parent, this);
59  if(form->ShowModal() == wxID_OK) {
60  form->Destroy();
61  return true;
62  }
63  form->Destroy();
64  return false;
65 }
66 
67 void Constant::Rotate(bool clockwise)
68 {
69  if(clockwise)
70  m_angle += 90.0;
71  else
72  m_angle -= 90.0;
73  if(m_angle >= 360.0)
74  m_angle = 0.0;
75  else if(m_angle < 0)
76  m_angle = 270.0;
77 
78  UpdatePoints();
79 
80  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
81  Node* node = *it;
82  node->Rotate(clockwise);
83  }
84 }
85 
86 void Constant::UpdatePoints()
87 {
88  if(m_nodeList.size() != 0) {
89  if(m_angle == 0.0) {
90  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
91  } else if(m_angle == 90.0) {
92  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
93  } else if(m_angle == 180.0) {
94  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
95  } else if(m_angle == 270.0) {
96  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
97  }
98  }
99 }
100 
101 void Constant::SetValue(double value)
102 {
103  m_value = value;
104  wxString text = StringFromDouble(m_value);
105 
106  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
107  wxScreenDC dc;
108 
109  if(m_glStringValue) {
110  delete m_glStringValue;
111  m_glStringValue = NULL;
112  }
113  m_glStringValue = new wxGLString(text);
114  m_glStringValue->setFont(font);
115  m_glStringValue->consolidate(&dc);
116 
117  m_width = m_glStringValue->getWidth() + 6 + 2 * m_borderSize;
118  m_height = m_glStringValue->getheight() + 6 + 2 * m_borderSize;
119 
120  UpdatePoints();
121 }
122 
124 {
125  Constant* copy = new Constant(m_elementID);
126  *copy = *this;
127  m_glStringValue = NULL;
128  SetValue(m_value);
129  return copy;
130 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Constant.h"
19 #include "ConstantForm.h"
20 
21 Constant::Constant(int id) : ControlElement(id)
22 {
23  SetValue(m_value);
24  m_angle = 180.0;
25  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
26  nodeOut->SetAngle(180.0);
27  nodeOut->StartMove(m_position);
28  m_nodeList.push_back(nodeOut);
29 }
30 
31 Constant::~Constant() {}
32 void Constant::Draw(wxPoint2DDouble translation, double scale) const
33 {
34  glLineWidth(1.0);
35  if(m_selected) {
36  glColor4dv(m_selectionColour.GetRGBA());
37  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
38  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
39  }
40  glColor4d(1.0, 1.0, 1.0, 1.0);
41  DrawRectangle(m_position, m_width, m_height);
42  glColor4d(0.0, 0.0, 0.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
44 
45  // Plot number.
46  glEnable(GL_TEXTURE_2D);
47  glColor4d(0.0, 0.0, 0.0, 1.0);
48  m_glStringValue->bind();
49  m_glStringValue->render(m_position.m_x, m_position.m_y);
50  glDisable(GL_TEXTURE_2D);
51 
52  glColor4d(0.0, 0.0, 0.0, 1.0);
53  DrawNodes();
54 }
55 
56 bool Constant::ShowForm(wxWindow* parent, Element* element)
57 {
58  ConstantForm* form = new ConstantForm(parent, this);
59  if(form->ShowModal() == wxID_OK) {
60  form->Destroy();
61  return true;
62  }
63  form->Destroy();
64  return false;
65 }
66 
67 void Constant::Rotate(bool clockwise)
68 {
69  if(clockwise)
70  m_angle += 90.0;
71  else
72  m_angle -= 90.0;
73  if(m_angle >= 360.0)
74  m_angle = 0.0;
75  else if(m_angle < 0)
76  m_angle = 270.0;
77 
78  UpdatePoints();
79 
80  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
81  Node* node = *it;
82  node->Rotate(clockwise);
83  }
84 }
85 
86 void Constant::UpdatePoints()
87 {
88  if(m_nodeList.size() != 0) {
89  if(m_angle == 0.0) {
90  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
91  } else if(m_angle == 90.0) {
92  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
93  } else if(m_angle == 180.0) {
94  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
95  } else if(m_angle == 270.0) {
96  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
97  }
98  }
99 }
100 
101 void Constant::SetValue(double value)
102 {
103  m_value = value;
104  wxString text = StringFromDouble(m_value);
105 
106  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
107  wxScreenDC dc;
108 
109  if(m_glStringValue) {
110  delete m_glStringValue;
111  m_glStringValue = NULL;
112  }
113  m_glStringValue = new wxGLString(text);
114  m_glStringValue->setFont(font);
115  m_glStringValue->consolidate(&dc);
116 
117  m_width = m_glStringValue->getWidth() + 6 + 2 * m_borderSize;
118  m_height = m_glStringValue->getheight() + 6 + 2 * m_borderSize;
119 
120  UpdatePoints();
121 }
122 
124 {
125  Constant* copy = new Constant(m_elementID);
126  *copy = *this;
127  m_glStringValue = NULL;
128  SetValue(m_value);
129  return copy;
130 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Node of a control element. This class manages the user interaction with the connection and control el...
virtual Element * GetCopy()
Get a the element copy.
Definition: Constant.cpp:123
virtual void DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode=GL_QUADS) const
Draw rectangle.
Definition: Element.cpp:69
diff --git a/docs/doxygen/html/_constant_8h_source.html b/docs/doxygen/html/_constant_8h_source.html index d698df6..53dc0fa 100644 --- a/docs/doxygen/html/_constant_8h_source.html +++ b/docs/doxygen/html/_constant_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_constant_8h_source.html','');});
Constant.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONSTANT_H
19 #define CONSTANT_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class ConstantForm;
27 
35 class Constant : public ControlElement
36 {
37  public:
38  Constant(int id);
39  ~Constant();
40 
41  virtual void Draw(wxPoint2DDouble translation, double scale) const;
42  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
43  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
44  virtual bool ShowForm(wxWindow* parent, Element* element);
45  virtual void Rotate(bool clockwise = true);
46  virtual void UpdateText() { SetValue(m_value); }
47  virtual void SetValue(double value);
48  virtual double GetValue() const { return m_value; }
49  virtual void UpdatePoints();
50 
51  virtual Element* GetCopy();
52 
53  protected:
54  double m_value = 1.0;
55 
56  wxGLString* m_glStringValue = NULL;
57  int m_fontSize = 10;
58 };
59 
60 #endif // CONSTANT_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONSTANT_H
19 #define CONSTANT_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class ConstantForm;
27 
35 class Constant : public ControlElement
36 {
37  public:
38  Constant(int id);
39  ~Constant();
40 
41  virtual void Draw(wxPoint2DDouble translation, double scale) const;
42  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
43  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
44  virtual bool ShowForm(wxWindow* parent, Element* element);
45  virtual void Rotate(bool clockwise = true);
46  virtual void UpdateText() { SetValue(m_value); }
47  virtual void SetValue(double value);
48  virtual double GetValue() const { return m_value; }
49  virtual void UpdatePoints();
50 
51  virtual Element* GetCopy();
52 
53  protected:
54  double m_value = 1.0;
55 
56  wxGLString* m_glStringValue = NULL;
57  int m_fontSize = 10;
58 };
59 
60 #endif // CONSTANT_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Constant.h:42
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Constant.h:43
virtual Element * GetCopy()
Get a the element copy.
Definition: Constant.cpp:123
diff --git a/docs/doxygen/html/_control_editor_8cpp_source.html b/docs/doxygen/html/_control_editor_8cpp_source.html index db69d94..a71cf1d 100644 --- a/docs/doxygen/html/_control_editor_8cpp_source.html +++ b/docs/doxygen/html/_control_editor_8cpp_source.html @@ -88,14 +88,14 @@ $(document).ready(function(){initNavTree('_control_editor_8cpp_source.html','');
ControlEditor.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlEditor.h"
19 
20 #ifdef USING_WX_3_0_X
21 #include "DegreesAndRadians.h"
22 #endif
23 #include "FileHanding.h"
24 #include "Camera.h"
25 #include "ControlElement.h"
26 #include "TransferFunction.h"
27 #include "ConnectionLine.h"
28 #include "Sum.h"
29 #include "Multiplier.h"
30 #include "Limiter.h"
31 #include "RateLimiter.h"
32 #include "Exponential.h"
33 #include "Constant.h"
34 #include "Gain.h"
35 
36 #include "ControlElementSolver.h"
38 
39 #include "ChartView.h"
40 #include "ElementPlotData.h"
41 
42 ControlElementButton::ControlElementButton(wxWindow* parent, wxString label, wxImage image, wxWindowID id)
43  : wxWindow(parent, id)
44 {
45  SetBackgroundColour(*wxWHITE);
46  // m_font = wxFont(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
47  m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
48  m_label = label;
49  m_image = image;
50  m_imageSize = wxSize(image.GetWidth(), image.GetHeight());
51 
52  // Calculate label size.
53  wxScreenDC dc;
54  dc.SetFont(m_font);
55  wxSize textSize = dc.GetTextExtent(label);
56 
57  int buttonWidth = 0;
58  if(textSize.GetWidth() > m_imageSize.GetWidth()) {
59  buttonWidth = textSize.GetWidth();
60  m_imagePosition = wxPoint((buttonWidth - m_imageSize.GetWidth()) / 2 + m_borderSize, m_borderSize);
61  m_labelPosition = wxPoint(m_borderSize, m_imageSize.GetHeight() + m_borderSize);
62  } else {
63  buttonWidth = m_imageSize.GetWidth();
64  m_imagePosition = wxPoint(m_borderSize, m_borderSize);
65  m_labelPosition =
66  wxPoint((buttonWidth - textSize.GetWidth()) / 2 + m_borderSize, m_imageSize.GetHeight() + m_borderSize);
67  }
68  m_buttonSize =
69  wxSize(buttonWidth + 2 * m_borderSize, textSize.GetHeight() + m_imageSize.GetHeight() + 2 * m_borderSize);
70  SetMinSize(m_buttonSize + wxSize(m_borderSize, m_borderSize));
71 
72  // Events.
73  Bind(wxEVT_PAINT, &ControlElementButton::OnPaint, this);
74  Bind(wxEVT_ENTER_WINDOW, &ControlElementButton::OnMouseEnter, this);
75  Bind(wxEVT_LEAVE_WINDOW, &ControlElementButton::OnMouseLeave, this);
76  Bind(wxEVT_LEFT_DOWN, &ControlElementButton::OnLeftClickDown, this);
77  Bind(wxEVT_LEFT_UP, &ControlElementButton::OnLeftClickUp, this);
78 }
79 
80 ControlElementButton::~ControlElementButton() {}
81 void ControlElementButton::OnPaint(wxPaintEvent& event)
82 {
83  wxPaintDC dc(this);
84  wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
85  if(gc) {
86  if(m_mouseAbove) {
87  if(m_selected) {
88  gc->SetPen(wxPen(wxColour(0, 125, 255, 255), m_borderSize - 1));
89  gc->SetBrush(wxBrush(wxColour(0, 125, 255, 100)));
90  } else {
91  gc->SetPen(*wxTRANSPARENT_PEN);
92  gc->SetBrush(wxBrush(wxColour(0, 125, 255, 70)));
93  }
94  gc->DrawRectangle(m_borderSize / 2, m_borderSize / 2, m_buttonSize.GetWidth(), m_buttonSize.GetHeight());
95  }
96  gc->DrawBitmap(gc->CreateBitmapFromImage(m_image), m_imagePosition.x, m_imagePosition.y, m_imageSize.GetWidth(),
97  m_imageSize.GetHeight());
98  gc->SetFont(m_font, *wxBLACK);
99  gc->DrawText(m_label, m_labelPosition.x, m_labelPosition.y);
100  delete gc;
101  }
102 }
103 
104 void ControlElementButton::OnMouseEnter(wxMouseEvent& event)
105 {
106  m_mouseAbove = true;
107  Refresh();
108  event.Skip();
109 }
110 
111 void ControlElementButton::OnMouseLeave(wxMouseEvent& event)
112 {
113  m_mouseAbove = false;
114  Refresh();
115  event.Skip();
116 }
117 
118 void ControlElementButton::OnLeftClickDown(wxMouseEvent& event)
119 {
120  m_selected = true;
121  Refresh();
122  event.Skip();
123 }
124 
125 void ControlElementButton::OnLeftClickUp(wxMouseEvent& event)
126 {
127  m_selected = false;
128  Refresh();
129  event.Skip();
130 }
131 
132 ControlEditor::ControlEditor(wxWindow* parent, int ioflags) : ControlEditorBase(parent)
133 {
134  BuildControlElementPanel();
135  m_glContext = new wxGLContext(m_glCanvas);
136  m_camera = new Camera();
137  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
138  // m_camera->SetScale(1.2);
139  m_ioFlags = ioflags;
140 }
141 ControlEditor::~ControlEditor()
142 {
143  // m_tfButton->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ControlEditor::LeftClickDown), m_tfButton, this);
144 }
145 
146 void ControlEditor::BuildControlElementPanel()
147 {
148  m_panelControlElements->SetDoubleBuffered(true);
149  wxWrapSizer* wrapSizer = new wxWrapSizer();
150  m_panelControlElements->SetSizer(wrapSizer);
151 
152  wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
153  wxString exePath = exeFileName.GetPath();
154 
156  m_panelControlElements, _("In/Out"), wxImage(exePath + "\\..\\data\\images\\control\\io.png"), ID_IO);
157  wrapSizer->Add(ioButton, 0, wxALL, 5);
158  ioButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
159 
160  ControlElementButton* tfButton =
161  new ControlElementButton(m_panelControlElements, _("Transfer fcn"),
162  wxImage(exePath + "\\..\\data\\images\\control\\transferFunc.png"), ID_TF);
163  wrapSizer->Add(tfButton, 0, wxALL, 5);
164  tfButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
165 
167  m_panelControlElements, _("Sum"), wxImage(exePath + "\\..\\data\\images\\control\\sum.png"), ID_SUM);
168  wrapSizer->Add(sumButton, 0, wxALL, 5);
169  sumButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
170 
171  ControlElementButton* constButton = new ControlElementButton(
172  m_panelControlElements, _("Constant"), wxImage(exePath + "\\..\\data\\images\\control\\value.png"), ID_CONST);
173  wrapSizer->Add(constButton, 0, wxALL, 5);
174  constButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
175 
176  ControlElementButton* limButton =
177  new ControlElementButton(m_panelControlElements, _("Limiter"),
178  wxImage(exePath + "\\..\\data\\images\\control\\limiter.png"), ID_LIMITER);
179  wrapSizer->Add(limButton, 0, wxALL, 5);
180  limButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
181 
182  ControlElementButton* gainButton = new ControlElementButton(
183  m_panelControlElements, _("Gain"), wxImage(exePath + "\\..\\data\\images\\control\\gain.png"), ID_GAIN);
184  wrapSizer->Add(gainButton, 0, wxALL, 5);
185  gainButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
186 
187  ControlElementButton* multButton = new ControlElementButton(
188  m_panelControlElements, _("Multiplier"), wxImage(exePath + "\\..\\data\\images\\control\\mult.png"), ID_MULT);
189  wrapSizer->Add(multButton, 0, wxALL, 5);
190  multButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
191 
193  m_panelControlElements, _("Exponential"), wxImage(exePath + "\\..\\data\\images\\control\\sat.png"), ID_EXP);
194  wrapSizer->Add(satButton, 0, wxALL, 5);
195  satButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
196 
197  ControlElementButton* rateLimButton =
198  new ControlElementButton(m_panelControlElements, _("Rate limiter"),
199  wxImage(exePath + "\\..\\data\\images\\control\\rateLimiter.png"), ID_RATELIM);
200  wrapSizer->Add(rateLimButton, 0, wxALL, 5);
201  rateLimButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
202 }
203 
204 void ControlEditor::LeftClickDown(wxMouseEvent& event)
205 {
206  AddElement(static_cast<ControlElementButtonID>(event.GetId()));
207  event.Skip();
208 }
209 
210 void ControlEditor::SetViewport()
211 {
212  glClearColor(1.0, 1.0, 1.0, 1.0); // White background.
213  glClear(GL_COLOR_BUFFER_BIT);
214  glDisable(GL_DEPTH_TEST);
215  glDisable(GL_TEXTURE_2D);
216  glEnable(GL_COLOR_MATERIAL);
217  glEnable(GL_BLEND);
218  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
219  glEnable(GL_LINE_SMOOTH);
220 
221  double width = m_glCanvas->GetSize().x - 1;
222  double height = m_glCanvas->GetSize().y - 1;
223 
224  // Viewport fit the screen.
225  glViewport(0, 0, width, height);
226 
227  glMatrixMode(GL_PROJECTION);
228  glLoadIdentity();
229  gluOrtho2D(0.0, width, height, 0.0);
230 
231  glMatrixMode(GL_MODELVIEW);
232  glLoadIdentity();
233 }
234 
235 void ControlEditor::AddElement(ControlElementButtonID id)
236 {
237  switch(id) {
238  case ID_IO: {
239  m_mode = MODE_INSERT;
240  IOControl* io = new IOControl(m_ioFlags, m_lastElementID);
241  m_elementList.push_back(io);
242  } break;
243  case ID_TF: {
244  m_mode = MODE_INSERT;
245  TransferFunction* tf = new TransferFunction(m_lastElementID);
246  m_elementList.push_back(tf);
247  } break;
248  case ID_SUM: {
249  m_mode = MODE_INSERT;
250  Sum* sum = new Sum(m_lastElementID);
251  m_elementList.push_back(sum);
252  } break;
253  case ID_CONST: {
254  m_mode = MODE_INSERT;
255  Constant* constant = new Constant(m_lastElementID);
256  m_elementList.push_back(constant);
257  } break;
258  case ID_LIMITER: {
259  m_mode = MODE_INSERT;
260  Limiter* limiter = new Limiter(m_lastElementID);
261  m_elementList.push_back(limiter);
262  } break;
263  case ID_GAIN: {
264  m_mode = MODE_INSERT;
265  Gain* gain = new Gain(m_lastElementID);
266  m_elementList.push_back(gain);
267  } break;
268  case ID_MULT: {
269  m_mode = MODE_INSERT;
270  Multiplier* mult = new Multiplier(m_lastElementID);
271  m_elementList.push_back(mult);
272  } break;
273  case ID_EXP: {
274  m_mode = MODE_INSERT;
275  Exponential* exp = new Exponential(m_lastElementID);
276  m_elementList.push_back(exp);
277  } break;
278  case ID_RATELIM: {
279  m_mode = MODE_INSERT;
280  RateLimiter* rateLim = new RateLimiter(m_lastElementID);
281  m_elementList.push_back(rateLim);
282  } break;
283  }
284  m_lastElementID++;
285 }
286 
287 void ControlEditor::OnPaint(wxPaintEvent& event)
288 {
289  wxPaintDC dc(m_glCanvas);
290  m_glContext->SetCurrent(*m_glCanvas);
291  SetViewport();
292 
293  // Set GLCanvas scale and translation.
294  glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale
295  glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation
296 
297  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
298  ConnectionLine* line = *it;
299  line->Draw(m_camera->GetTranslation(), m_camera->GetScale());
300  }
301 
302  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
303  Element* element = *it;
304  element->Draw(m_camera->GetTranslation(), m_camera->GetScale());
305  }
306 
307  // Selection rectangle
308  glLineWidth(1.0);
309  glColor4d(0.0, 0.5, 1.0, 1.0);
310  glBegin(GL_LINE_LOOP);
311  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
312  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
313  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
314  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
315  glEnd();
316  glColor4d(0.0, 0.5, 1.0, 0.3);
317  glBegin(GL_QUADS);
318  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
319  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
320  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
321  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
322  glEnd();
323 
324  glFlush(); // Sends all pending information directly to the GPU.
325  m_glCanvas->SwapBuffers();
326  event.Skip();
327 }
328 
329 void ControlEditor::OnDoubleClick(wxMouseEvent& event)
330 {
331  wxPoint2DDouble clickPoint = event.GetPosition();
332  bool redraw = false;
333 
334  if(m_mode == MODE_EDIT) {
335  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
336  Element* element = *it;
337  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
338  element->ShowForm(this, element);
339  CheckConnections();
340  auto childList = element->GetChildList();
341  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
342  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
343  line->UpdatePoints();
344  }
345  redraw = true;
346  }
347  }
348  }
349 
350  if(redraw) Redraw();
351 }
352 
353 void ControlEditor::OnLeftClickDown(wxMouseEvent& event)
354 {
355  wxPoint2DDouble clickPoint = event.GetPosition();
356  bool foundElement = false;
357 
358  if(m_mode == MODE_INSERT) {
359  m_mode = MODE_EDIT;
360  } else {
361  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
362  ControlElement* element = *it;
363  bool foundNode = false;
364  auto nodeList = element->GetNodeList();
365  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
366  Node* node = *itN;
367  if(node->Contains(m_camera->ScreenToWorld(clickPoint))) {
368  m_mode = MODE_INSERT_LINE;
369  ConnectionLine* line = new ConnectionLine(node, m_lastElementID);
370  m_lastElementID++;
371  m_connectionList.push_back(line);
372  element->AddChild(line);
373  line->AddParent(element);
374  foundElement = true;
375  foundNode = true;
376  }
377  }
378 
379  if(!foundNode) {
380  // Set movement initial position (not necessarily will be moved).
381  element->StartMove(m_camera->ScreenToWorld(clickPoint));
382 
383  // Click in an element.
384  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
385  if(!foundElement) {
386  element->SetSelected();
387  foundElement = true;
388  }
389  m_mode = MODE_MOVE_ELEMENT;
390  }
391  }
392  }
393  if(m_mode != MODE_INSERT_LINE) {
394  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
395  ConnectionLine* line = *it;
396  line->StartMove(m_camera->ScreenToWorld(clickPoint));
397  if(line->Contains(m_camera->ScreenToWorld(clickPoint))) {
398  line->SetSelected();
399  foundElement = true;
400  m_mode = MODE_MOVE_LINE;
401  }
402  }
403  }
404  }
405 
406  if(!foundElement) {
407  m_mode = MODE_SELECTION_RECT;
408  m_startSelRect = m_camera->ScreenToWorld(clickPoint);
409  }
410 
411  Redraw();
412  event.Skip();
413 }
414 
415 void ControlEditor::OnLeftClickUp(wxMouseEvent& event)
416 {
417  bool foundNode = false;
418  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
419  ControlElement* element = *it;
420  if(m_mode == MODE_INSERT_LINE) {
421  auto nodeList = element->GetNodeList();
422  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
423  Node* node = *itN;
424  if(node->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
425  ConnectionLine* line = *(m_connectionList.end() - 1);
426  if(line->AppendNode(node, element)) {
427  line->AddParent(element);
428  element->AddChild(line);
429  line->UpdatePoints();
430  m_mode = MODE_EDIT;
431  foundNode = true;
432  }
433  }
434  }
435  } else if(m_mode == MODE_SELECTION_RECT) {
436  if(element->Intersects(m_selectionRect)) {
437  element->SetSelected();
438  } else if(!event.ControlDown()) {
439  element->SetSelected(false);
440  }
441  } else if(!event.ControlDown()) {
442  if(!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
443  element->SetSelected(false);
444  }
445  }
446  }
447  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
448  ConnectionLine* cLine = *it;
449  if(m_mode == MODE_INSERT_LINE && !foundNode && it != (itEnd - 1)) {
450  if(cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
451  ConnectionLine* iLine = *(m_connectionList.end() - 1);
452  if(iLine->SetParentLine(cLine)) {
453  cLine->AddChild(iLine);
454  iLine->UpdatePoints();
455  m_mode = MODE_EDIT;
456  foundNode = true;
457  }
458  }
459  } else if(m_mode == MODE_SELECTION_RECT) {
460  if(cLine->Intersects(m_selectionRect)) {
461  cLine->SetSelected();
462  } else if(!event.ControlDown()) {
463  cLine->SetSelected(false);
464  }
465  } else if(!event.ControlDown()) {
466  if(!cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
467  cLine->SetSelected(false);
468  }
469  }
470  }
471 
472  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
473 
474  if(m_mode == MODE_INSERT_LINE && !foundNode) {
475  ConnectionLine* cLine = *(m_connectionList.end() - 1);
476  // Free nodes
477  auto nodeList = cLine->GetNodeList();
478  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
479  Node* node = *itN;
480  node->SetConnected(false);
481  }
482  // Remove the associated child from parents.
483  auto parentList = cLine->GetParentList();
484  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
485  Element* element = *it;
486  element->RemoveChild(cLine);
487  }
488  m_connectionList.pop_back();
489  if(cLine) delete cLine;
490  m_mode = MODE_EDIT;
491  } else if(m_mode != MODE_INSERT) {
492  m_mode = MODE_EDIT;
493  }
494 
495  Redraw();
496  event.Skip();
497 }
498 
499 void ControlEditor::OnMiddleDown(wxMouseEvent& event)
500 {
501  // Set to drag mode.
502  switch(m_mode) {
503  case MODE_INSERT: {
504  m_mode = MODE_DRAG_INSERT;
505  } break;
506  case MODE_PASTE: {
507  m_mode = MODE_DRAG_PASTE;
508  } break;
509  default: {
510  m_mode = MODE_DRAG;
511  } break;
512  }
513  m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
514 }
515 
516 void ControlEditor::OnMiddleUp(wxMouseEvent& event)
517 {
518  switch(m_mode) {
519  case MODE_DRAG_INSERT: {
520  m_mode = MODE_INSERT;
521  } break;
522  case MODE_DRAG_PASTE: {
523  m_mode = MODE_PASTE;
524  } break;
525  case MODE_INSERT:
526  case MODE_PASTE: {
527  // Does nothing.
528  } break;
529  default: {
530  m_mode = MODE_EDIT;
531  } break;
532  }
533 }
534 
535 void ControlEditor::OnMouseMotion(wxMouseEvent& event)
536 {
537  wxPoint2DDouble clickPoint = event.GetPosition();
538  bool redraw = false;
539 
540  switch(m_mode) {
541  case MODE_INSERT: {
542  Element* newElement = *(m_elementList.end() - 1); // Get the last element in the list.
543  newElement->Move(m_camera->ScreenToWorld(clickPoint));
544  redraw = true;
545  } break;
546  case MODE_INSERT_LINE: {
547  ConnectionLine* line = *(m_connectionList.end() - 1);
548  line->SetTemporarySecondPoint(m_camera->ScreenToWorld(clickPoint));
549  line->UpdatePoints();
550  redraw = true;
551  } break;
552  case MODE_DRAG:
553  case MODE_DRAG_INSERT:
554  case MODE_DRAG_PASTE: {
555  m_camera->SetTranslation(clickPoint);
556  redraw = true;
557  } break;
558  case MODE_MOVE_ELEMENT: {
559  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
560  Element* element = *it;
561  if(element->IsSelected()) {
562  element->Move(m_camera->ScreenToWorld(clickPoint));
563  auto childList = element->GetChildList();
564  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
565  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
566  line->UpdatePoints();
567  }
568  redraw = true;
569  }
570  }
571  } break;
572  case MODE_MOVE_LINE: {
573  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; it++) {
574  ConnectionLine* line = *it;
575  if(line->IsSelected()) {
576  line->Move(m_camera->ScreenToWorld(clickPoint));
577  redraw = true;
578  }
579  }
580  } break;
581  case MODE_SELECTION_RECT: {
582  wxPoint2DDouble currentPos = m_camera->ScreenToWorld(clickPoint);
583  double x, y, w, h;
584  if(currentPos.m_x < m_startSelRect.m_x) {
585  x = currentPos.m_x;
586  w = m_startSelRect.m_x - currentPos.m_x;
587  } else {
588  x = m_startSelRect.m_x;
589  w = currentPos.m_x - m_startSelRect.m_x;
590  }
591  if(currentPos.m_y < m_startSelRect.m_y) {
592  y = currentPos.m_y;
593  h = m_startSelRect.m_y - currentPos.m_y;
594  } else {
595  y = m_startSelRect.m_y;
596  h = currentPos.m_y - m_startSelRect.m_y;
597  }
598 
599  m_selectionRect = wxRect2DDouble(x, y, w, h);
600  redraw = true;
601  } break;
602  default:
603  break;
604  }
605 
606  if(redraw) Redraw();
607  event.Skip();
608 }
609 
610 void ControlEditor::OnScroll(wxMouseEvent& event)
611 {
612  if(event.GetWheelRotation() > 0)
613  m_camera->SetScale(event.GetPosition(), +0.05);
614  else
615  m_camera->SetScale(event.GetPosition(), -0.05);
616 
617  Redraw();
618 }
619 
620 void ControlEditor::OnIdle(wxIdleEvent& event) { ConsolidateTexts(); }
621 void ControlEditor::OnKeyDown(wxKeyEvent& event)
622 {
623  char key = event.GetUnicodeKey();
624  if(key != WXK_NONE) {
625  switch(key) {
626  case WXK_DELETE: // Delete selected elements.
627  {
628  DeleteSelectedElements();
629  } break;
630  case 'R': // Rotate the selected elements.
631  {
632  RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
633  } break;
634  case 'L': {
635  // tests
636  } break;
637  }
638  }
639 }
640 
641 void ControlEditor::RotateSelectedElements(bool clockwise)
642 {
643  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
644  Element* element = *it;
645  if(element->IsSelected()) {
646  element->Rotate(clockwise);
647  auto childList = element->GetChildList();
648  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
649  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
650  line->UpdatePoints();
651  }
652  }
653  }
654  Redraw();
655 }
656 
657 void ControlEditor::DeleteSelectedElements()
658 {
659  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
660  Element* element = *it;
661  if(element->IsSelected()) {
662  // Remove child/parent.
663  auto childList = element->GetChildList();
664  for(auto itC = childList.begin(), itEnd = childList.end(); itC != itEnd; ++itC) {
665  // The child is always a connection line.
666  ConnectionLine* child = static_cast<ConnectionLine*>(*itC);
667  // Delete the connection line.
668  for(auto itCo = m_connectionList.begin(); itCo != m_connectionList.end(); ++itCo) {
669  ConnectionLine* line = *itCo;
670  if(line == child) {
671  itCo = DeleteLineFromList(itCo);
672  break;
673  }
674  }
675  }
676  m_elementList.erase(it--);
677  if(element) delete element;
678  }
679  }
680 
681  for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
682  ConnectionLine* line = *it;
683  if(line->IsSelected()) {
684  it = DeleteLineFromList(it);
685  }
686  }
687  Redraw();
688 }
689 
690 std::vector<ConnectionLine*>::iterator ControlEditor::DeleteLineFromList(std::vector<ConnectionLine*>::iterator& it)
691 {
692  ConnectionLine* cLine = *it;
693  auto childList = cLine->GetLineChildList();
694  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
695  ConnectionLine* child = *itC;
696  for(auto itL = m_connectionList.begin(); itL != m_connectionList.end(); ++itL) {
697  ConnectionLine* childOnList = *itL;
698  if(childOnList == child) {
699  itL = DeleteLineFromList(itL);
700  }
701  }
702  }
703  // Remove
704  auto parentList = cLine->GetParentList();
705  for(auto itP = parentList.begin(), itEnd = parentList.end(); itP != itEnd; ++itP) {
706  Element* parent = *itP;
707  if(parent) parent->RemoveChild(cLine);
708  }
709  if(cLine->GetParentLine()) cLine->GetParentLine()->RemoveChild(cLine);
710  // Free nodes
711  auto nodeList = cLine->GetNodeList();
712  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
713  Node* node = *itN;
714  node->SetConnected(false);
715  }
716  m_connectionList.erase(it--);
717  if(cLine) delete cLine;
718  return it;
719 }
720 
721 void ControlEditor::CheckConnections()
722 {
723  for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
724  ConnectionLine* cLine = *it;
725  if(cLine->GetType() == ConnectionLine::ELEMENT_ELEMENT) {
726  if(cLine->GetParentList().size() < 2) {
727  it = DeleteLineFromList(it);
728  }
729  }
730  }
731 }
732 
733 void ControlEditor::OnExportClick(wxCommandEvent& event)
734 {
735  FileHanding fileHandling(this);
736 
737  wxFileDialog saveFileDialog(this, _("Save CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
738  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
739  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
740 
741  fileHandling.SaveControl(saveFileDialog.GetPath());
742  wxFileName fileName(saveFileDialog.GetPath());
743  event.Skip();
744 }
745 
746 void ControlEditor::OnImportClick(wxCommandEvent& event)
747 {
748  wxFileDialog openFileDialog(this, _("Open CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
749  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
750  if(openFileDialog.ShowModal() == wxID_CANCEL) return;
751 
752  wxFileName fileName(openFileDialog.GetPath());
753 
754  FileHanding fileHandling(this);
755  if(!fileHandling.OpenControl(fileName, m_elementList, m_connectionList)) {
756  wxMessageDialog msgDialog(this, _("It was not possible to open the selected file."), _("Error"),
757  wxOK | wxCENTRE | wxICON_ERROR);
758  msgDialog.ShowModal();
759  }
760 
761  SetLastElementID();
762  Redraw();
763  event.Skip();
764 }
765 
766 void ControlEditor::OnTestClick(wxCommandEvent& event)
767 {
768  ControlSystemTest csTest(this, &m_inputType, &m_startTime, &m_slope, &m_timeStep, &m_simTime);
769  if(csTest.ShowModal() == wxID_OK) {
770  double printStep = 1e-3;
771  double pdbStep = 1e-1;
772 
773  wxProgressDialog pbd(_("Test"), _("Initializing..."), 100, this,
774  wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_SMOOTH);
775  ControlElementSolver solver(this, m_timeStep, 1e-5);
776  if(solver.IsOK()) {
777  bool simStopped = false;
778  double currentTime = 0.0;
779  double printTime = 0.0;
780  double pdbTime = 0.0;
781  std::vector<double> time;
782  std::vector<double> solution;
783  std::vector<double> inputV;
784  while(currentTime <= m_simTime) {
785  double input = 0.0;
786  if(currentTime >= m_startTime) {
787  switch(m_inputType) {
788  case 0: {
789  input = m_slope;
790  } break;
791  case 1: {
792  input = m_slope * (currentTime - m_startTime);
793  } break;
794  case 2: {
795  input = m_slope * std::pow(currentTime - m_startTime, 2);
796  } break;
797  default: {
798  input = 0.0;
799  break;
800  }
801  }
802  }
803 
804  solver.SolveNextStep(input);
805 
806  if(printTime >= printStep) {
807  time.push_back(currentTime);
808  solution.push_back(solver.GetLastSolution());
809  inputV.push_back(input);
810  printTime = 0.0;
811  }
812 
813  if(pdbTime > pdbStep) {
814  if(!pbd.Update((currentTime / m_simTime) * 100, wxString::Format("Time = %.2fs", currentTime))) {
815  pbd.Update(100);
816  simStopped = true;
817  currentTime = m_simTime;
818  }
819  pdbTime = 0.0;
820  }
821 
822  printTime += m_timeStep;
823  currentTime += m_timeStep;
824  pdbTime += m_timeStep;
825  }
826  if(!simStopped) {
827  std::vector<ElementPlotData> epdList;
828  ElementPlotData curveData(_("I/O"), ElementPlotData::CT_TEST);
829  curveData.AddData(inputV, _("Input"));
830  curveData.AddData(solution, _("Output"));
831 
832  curveData.SetPlot(0);
833  curveData.SetColour(0, *wxRED);
834  curveData.SetPlot(1);
835  curveData.SetColour(1, *wxBLUE);
836 
837  epdList.push_back(curveData);
838 
839  ChartView* cView = new ChartView(this, epdList, time);
840  cView->Show();
841  cView->UpdatePlot();
842  }
843  } else {
844  wxMessageDialog msgDialog(this, _("It was not possible to solve the control system"), _("Error"),
845  wxOK | wxCENTRE | wxICON_ERROR);
846  msgDialog.ShowModal();
847  }
848  }
849 }
850 
851 void ControlEditor::OnClose(wxCloseEvent& event)
852 {
853  if(m_ctrlContainer) {
854  m_ctrlContainer->FillContainer(this);
855  }
856  event.Skip();
857 }
858 
859 void ControlEditor::ConsolidateTexts()
860 {
861  // Solve wxGLString bug.
862  if(m_firstDraw) {
863  TransferFunction* tf = new TransferFunction(0);
864  m_elementList.push_back(tf);
865  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
866  ControlElement* element = *it;
867  element->UpdateText();
868  }
869  Redraw();
870  m_elementList.pop_back();
871  delete tf;
872  m_firstDraw = false;
873  }
874 }
875 
876 void ControlEditor::SetLastElementID()
877 {
878  int id = 0;
879  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
880  int elementID = (*it)->GetID();
881  if(id < elementID) id = elementID;
882  }
883  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
884  int elementID = (*it)->GetID();
885  if(id < elementID) id = elementID;
886  }
887  m_lastElementID = ++id;
888 }
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Element.cpp:123
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlEditor.h"
19 
20 #ifdef USING_WX_3_0_X
21 #include "DegreesAndRadians.h"
22 #endif
23 #include "FileHanding.h"
24 #include "Camera.h"
25 #include "ControlElement.h"
26 #include "TransferFunction.h"
27 #include "ConnectionLine.h"
28 #include "Sum.h"
29 #include "Multiplier.h"
30 #include "Limiter.h"
31 #include "RateLimiter.h"
32 #include "Exponential.h"
33 #include "Constant.h"
34 #include "Gain.h"
35 
36 #include "ControlElementSolver.h"
38 
39 #include "ChartView.h"
40 #include "ElementPlotData.h"
41 
42 ControlElementButton::ControlElementButton(wxWindow* parent, wxString label, wxImage image, wxWindowID id)
43  : wxWindow(parent, id)
44 {
45  SetBackgroundColour(*wxWHITE);
46  // m_font = wxFont(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
47  m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
48  m_label = label;
49  m_image = image;
50  m_imageSize = wxSize(image.GetWidth(), image.GetHeight());
51 
52  // Calculate label size.
53  wxScreenDC dc;
54  dc.SetFont(m_font);
55  wxSize textSize = dc.GetTextExtent(label);
56 
57  int buttonWidth = 0;
58  if(textSize.GetWidth() > m_imageSize.GetWidth()) {
59  buttonWidth = textSize.GetWidth();
60  m_imagePosition = wxPoint((buttonWidth - m_imageSize.GetWidth()) / 2 + m_borderSize, m_borderSize);
61  m_labelPosition = wxPoint(m_borderSize, m_imageSize.GetHeight() + m_borderSize);
62  } else {
63  buttonWidth = m_imageSize.GetWidth();
64  m_imagePosition = wxPoint(m_borderSize, m_borderSize);
65  m_labelPosition =
66  wxPoint((buttonWidth - textSize.GetWidth()) / 2 + m_borderSize, m_imageSize.GetHeight() + m_borderSize);
67  }
68  m_buttonSize =
69  wxSize(buttonWidth + 2 * m_borderSize, textSize.GetHeight() + m_imageSize.GetHeight() + 2 * m_borderSize);
70  SetMinSize(m_buttonSize + wxSize(m_borderSize, m_borderSize));
71 
72  // Events.
73  Bind(wxEVT_PAINT, &ControlElementButton::OnPaint, this);
74  Bind(wxEVT_ENTER_WINDOW, &ControlElementButton::OnMouseEnter, this);
75  Bind(wxEVT_LEAVE_WINDOW, &ControlElementButton::OnMouseLeave, this);
76  Bind(wxEVT_LEFT_DOWN, &ControlElementButton::OnLeftClickDown, this);
77  Bind(wxEVT_LEFT_UP, &ControlElementButton::OnLeftClickUp, this);
78 }
79 
80 ControlElementButton::~ControlElementButton() {}
81 void ControlElementButton::OnPaint(wxPaintEvent& event)
82 {
83  wxPaintDC dc(this);
84  wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
85  if(gc) {
86  if(m_mouseAbove) {
87  if(m_selected) {
88  gc->SetPen(wxPen(wxColour(0, 125, 255, 255), m_borderSize - 1));
89  gc->SetBrush(wxBrush(wxColour(0, 125, 255, 100)));
90  } else {
91  gc->SetPen(*wxTRANSPARENT_PEN);
92  gc->SetBrush(wxBrush(wxColour(0, 125, 255, 70)));
93  }
94  gc->DrawRectangle(m_borderSize / 2, m_borderSize / 2, m_buttonSize.GetWidth(), m_buttonSize.GetHeight());
95  }
96  gc->DrawBitmap(gc->CreateBitmapFromImage(m_image), m_imagePosition.x, m_imagePosition.y, m_imageSize.GetWidth(),
97  m_imageSize.GetHeight());
98  gc->SetFont(m_font, *wxBLACK);
99  gc->DrawText(m_label, m_labelPosition.x, m_labelPosition.y);
100  delete gc;
101  }
102 }
103 
104 void ControlElementButton::OnMouseEnter(wxMouseEvent& event)
105 {
106  m_mouseAbove = true;
107  Refresh();
108  event.Skip();
109 }
110 
111 void ControlElementButton::OnMouseLeave(wxMouseEvent& event)
112 {
113  m_mouseAbove = false;
114  Refresh();
115  event.Skip();
116 }
117 
118 void ControlElementButton::OnLeftClickDown(wxMouseEvent& event)
119 {
120  m_selected = true;
121  Refresh();
122  event.Skip();
123 }
124 
125 void ControlElementButton::OnLeftClickUp(wxMouseEvent& event)
126 {
127  m_selected = false;
128  Refresh();
129  event.Skip();
130 }
131 
132 ControlEditor::ControlEditor(wxWindow* parent, int ioflags) : ControlEditorBase(parent)
133 {
134  BuildControlElementPanel();
135  m_glContext = new wxGLContext(m_glCanvas);
136  m_camera = new Camera();
137  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
138  // m_camera->SetScale(1.2);
139  m_ioFlags = ioflags;
140 }
141 ControlEditor::~ControlEditor()
142 {
143  // m_tfButton->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ControlEditor::LeftClickDown), m_tfButton, this);
144 }
145 
146 void ControlEditor::BuildControlElementPanel()
147 {
148  m_panelControlElements->SetDoubleBuffered(true);
149  wxWrapSizer* wrapSizer = new wxWrapSizer();
150  m_panelControlElements->SetSizer(wrapSizer);
151 
152  wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
153  wxString exePath = exeFileName.GetPath();
154 
156  m_panelControlElements, _("In/Out"), wxImage(exePath + "\\..\\data\\images\\control\\io.png"), ID_IO);
157  wrapSizer->Add(ioButton, 0, wxALL, 5);
158  ioButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
159 
160  ControlElementButton* tfButton =
161  new ControlElementButton(m_panelControlElements, _("Transfer fcn"),
162  wxImage(exePath + "\\..\\data\\images\\control\\transferFunc.png"), ID_TF);
163  wrapSizer->Add(tfButton, 0, wxALL, 5);
164  tfButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
165 
167  m_panelControlElements, _("Sum"), wxImage(exePath + "\\..\\data\\images\\control\\sum.png"), ID_SUM);
168  wrapSizer->Add(sumButton, 0, wxALL, 5);
169  sumButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
170 
171  ControlElementButton* constButton = new ControlElementButton(
172  m_panelControlElements, _("Constant"), wxImage(exePath + "\\..\\data\\images\\control\\value.png"), ID_CONST);
173  wrapSizer->Add(constButton, 0, wxALL, 5);
174  constButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
175 
176  ControlElementButton* limButton =
177  new ControlElementButton(m_panelControlElements, _("Limiter"),
178  wxImage(exePath + "\\..\\data\\images\\control\\limiter.png"), ID_LIMITER);
179  wrapSizer->Add(limButton, 0, wxALL, 5);
180  limButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
181 
182  ControlElementButton* gainButton = new ControlElementButton(
183  m_panelControlElements, _("Gain"), wxImage(exePath + "\\..\\data\\images\\control\\gain.png"), ID_GAIN);
184  wrapSizer->Add(gainButton, 0, wxALL, 5);
185  gainButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
186 
187  ControlElementButton* multButton = new ControlElementButton(
188  m_panelControlElements, _("Multiplier"), wxImage(exePath + "\\..\\data\\images\\control\\mult.png"), ID_MULT);
189  wrapSizer->Add(multButton, 0, wxALL, 5);
190  multButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
191 
193  m_panelControlElements, _("Exponential"), wxImage(exePath + "\\..\\data\\images\\control\\sat.png"), ID_EXP);
194  wrapSizer->Add(satButton, 0, wxALL, 5);
195  satButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
196 
197  ControlElementButton* rateLimButton =
198  new ControlElementButton(m_panelControlElements, _("Rate limiter"),
199  wxImage(exePath + "\\..\\data\\images\\control\\rateLimiter.png"), ID_RATELIM);
200  wrapSizer->Add(rateLimButton, 0, wxALL, 5);
201  rateLimButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
202 }
203 
204 void ControlEditor::LeftClickDown(wxMouseEvent& event)
205 {
206  AddElement(static_cast<ControlElementButtonID>(event.GetId()));
207  event.Skip();
208 }
209 
210 void ControlEditor::SetViewport()
211 {
212  glClearColor(1.0, 1.0, 1.0, 1.0); // White background.
213  glClear(GL_COLOR_BUFFER_BIT);
214  glDisable(GL_DEPTH_TEST);
215  glDisable(GL_TEXTURE_2D);
216  glEnable(GL_COLOR_MATERIAL);
217  glEnable(GL_BLEND);
218  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
219  glEnable(GL_LINE_SMOOTH);
220 
221  double width = m_glCanvas->GetSize().x - 1;
222  double height = m_glCanvas->GetSize().y - 1;
223 
224  // Viewport fit the screen.
225  glViewport(0, 0, width, height);
226 
227  glMatrixMode(GL_PROJECTION);
228  glLoadIdentity();
229  gluOrtho2D(0.0, width, height, 0.0);
230 
231  glMatrixMode(GL_MODELVIEW);
232  glLoadIdentity();
233 }
234 
235 void ControlEditor::AddElement(ControlElementButtonID id)
236 {
237  switch(id) {
238  case ID_IO: {
239  m_mode = MODE_INSERT;
240  IOControl* io = new IOControl(m_ioFlags, m_lastElementID);
241  m_elementList.push_back(io);
242  } break;
243  case ID_TF: {
244  m_mode = MODE_INSERT;
245  TransferFunction* tf = new TransferFunction(m_lastElementID);
246  m_elementList.push_back(tf);
247  } break;
248  case ID_SUM: {
249  m_mode = MODE_INSERT;
250  Sum* sum = new Sum(m_lastElementID);
251  m_elementList.push_back(sum);
252  } break;
253  case ID_CONST: {
254  m_mode = MODE_INSERT;
255  Constant* constant = new Constant(m_lastElementID);
256  m_elementList.push_back(constant);
257  } break;
258  case ID_LIMITER: {
259  m_mode = MODE_INSERT;
260  Limiter* limiter = new Limiter(m_lastElementID);
261  m_elementList.push_back(limiter);
262  } break;
263  case ID_GAIN: {
264  m_mode = MODE_INSERT;
265  Gain* gain = new Gain(m_lastElementID);
266  m_elementList.push_back(gain);
267  } break;
268  case ID_MULT: {
269  m_mode = MODE_INSERT;
270  Multiplier* mult = new Multiplier(m_lastElementID);
271  m_elementList.push_back(mult);
272  } break;
273  case ID_EXP: {
274  m_mode = MODE_INSERT;
275  Exponential* exp = new Exponential(m_lastElementID);
276  m_elementList.push_back(exp);
277  } break;
278  case ID_RATELIM: {
279  m_mode = MODE_INSERT;
280  RateLimiter* rateLim = new RateLimiter(m_lastElementID);
281  m_elementList.push_back(rateLim);
282  } break;
283  }
284  m_lastElementID++;
285 }
286 
287 void ControlEditor::OnPaint(wxPaintEvent& event)
288 {
289  wxPaintDC dc(m_glCanvas);
290  m_glContext->SetCurrent(*m_glCanvas);
291  SetViewport();
292 
293  // Set GLCanvas scale and translation.
294  glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale
295  glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation
296 
297  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
298  ConnectionLine* line = *it;
299  line->Draw(m_camera->GetTranslation(), m_camera->GetScale());
300  }
301 
302  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
303  Element* element = *it;
304  element->Draw(m_camera->GetTranslation(), m_camera->GetScale());
305  }
306 
307  // Selection rectangle
308  glLineWidth(1.0);
309  glColor4d(0.0, 0.5, 1.0, 1.0);
310  glBegin(GL_LINE_LOOP);
311  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
312  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
313  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
314  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
315  glEnd();
316  glColor4d(0.0, 0.5, 1.0, 0.3);
317  glBegin(GL_QUADS);
318  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
319  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
320  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
321  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
322  glEnd();
323 
324  glFlush(); // Sends all pending information directly to the GPU.
325  m_glCanvas->SwapBuffers();
326  event.Skip();
327 }
328 
329 void ControlEditor::OnDoubleClick(wxMouseEvent& event)
330 {
331  wxPoint2DDouble clickPoint = event.GetPosition();
332  bool redraw = false;
333 
334  if(m_mode == MODE_EDIT) {
335  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
336  Element* element = *it;
337  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
338  element->ShowForm(this, element);
339  CheckConnections();
340  auto childList = element->GetChildList();
341  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
342  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
343  line->UpdatePoints();
344  }
345  redraw = true;
346  }
347  }
348  }
349 
350  if(redraw) Redraw();
351 }
352 
353 void ControlEditor::OnLeftClickDown(wxMouseEvent& event)
354 {
355  wxPoint2DDouble clickPoint = event.GetPosition();
356  bool foundElement = false;
357 
358  if(m_mode == MODE_INSERT) {
359  m_mode = MODE_EDIT;
360  } else {
361  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
362  ControlElement* element = *it;
363  bool foundNode = false;
364  auto nodeList = element->GetNodeList();
365  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
366  Node* node = *itN;
367  if(node->Contains(m_camera->ScreenToWorld(clickPoint))) {
368  m_mode = MODE_INSERT_LINE;
369  ConnectionLine* line = new ConnectionLine(node, m_lastElementID);
370  m_lastElementID++;
371  m_connectionList.push_back(line);
372  element->AddChild(line);
373  line->AddParent(element);
374  foundElement = true;
375  foundNode = true;
376  }
377  }
378 
379  if(!foundNode) {
380  // Set movement initial position (not necessarily will be moved).
381  element->StartMove(m_camera->ScreenToWorld(clickPoint));
382 
383  // Click in an element.
384  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
385  if(!foundElement) {
386  element->SetSelected();
387  foundElement = true;
388  }
389  m_mode = MODE_MOVE_ELEMENT;
390  }
391  }
392  }
393  if(m_mode != MODE_INSERT_LINE) {
394  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
395  ConnectionLine* line = *it;
396  line->StartMove(m_camera->ScreenToWorld(clickPoint));
397  if(line->Contains(m_camera->ScreenToWorld(clickPoint))) {
398  line->SetSelected();
399  foundElement = true;
400  m_mode = MODE_MOVE_LINE;
401  }
402  }
403  }
404  }
405 
406  if(!foundElement) {
407  m_mode = MODE_SELECTION_RECT;
408  m_startSelRect = m_camera->ScreenToWorld(clickPoint);
409  }
410 
411  Redraw();
412  event.Skip();
413 }
414 
415 void ControlEditor::OnLeftClickUp(wxMouseEvent& event)
416 {
417  bool foundNode = false;
418  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
419  ControlElement* element = *it;
420  if(m_mode == MODE_INSERT_LINE) {
421  auto nodeList = element->GetNodeList();
422  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
423  Node* node = *itN;
424  if(node->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
425  ConnectionLine* line = *(m_connectionList.end() - 1);
426  if(line->AppendNode(node, element)) {
427  line->AddParent(element);
428  element->AddChild(line);
429  line->UpdatePoints();
430  m_mode = MODE_EDIT;
431  foundNode = true;
432  }
433  }
434  }
435  } else if(m_mode == MODE_SELECTION_RECT) {
436  if(element->Intersects(m_selectionRect)) {
437  element->SetSelected();
438  } else if(!event.ControlDown()) {
439  element->SetSelected(false);
440  }
441  } else if(!event.ControlDown()) {
442  if(!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
443  element->SetSelected(false);
444  }
445  }
446  }
447  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
448  ConnectionLine* cLine = *it;
449  if(m_mode == MODE_INSERT_LINE && !foundNode && it != (itEnd - 1)) {
450  if(cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
451  ConnectionLine* iLine = *(m_connectionList.end() - 1);
452  if(iLine->SetParentLine(cLine)) {
453  cLine->AddChild(iLine);
454  iLine->UpdatePoints();
455  m_mode = MODE_EDIT;
456  foundNode = true;
457  }
458  }
459  } else if(m_mode == MODE_SELECTION_RECT) {
460  if(cLine->Intersects(m_selectionRect)) {
461  cLine->SetSelected();
462  } else if(!event.ControlDown()) {
463  cLine->SetSelected(false);
464  }
465  } else if(!event.ControlDown()) {
466  if(!cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
467  cLine->SetSelected(false);
468  }
469  }
470  }
471 
472  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
473 
474  if(m_mode == MODE_INSERT_LINE && !foundNode) {
475  ConnectionLine* cLine = *(m_connectionList.end() - 1);
476  // Free nodes
477  auto nodeList = cLine->GetNodeList();
478  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
479  Node* node = *itN;
480  node->SetConnected(false);
481  }
482  // Remove the associated child from parents.
483  auto parentList = cLine->GetParentList();
484  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
485  Element* element = *it;
486  element->RemoveChild(cLine);
487  }
488  m_connectionList.pop_back();
489  if(cLine) delete cLine;
490  m_mode = MODE_EDIT;
491  } else if(m_mode != MODE_INSERT) {
492  m_mode = MODE_EDIT;
493  }
494 
495  Redraw();
496  event.Skip();
497 }
498 
499 void ControlEditor::OnMiddleDown(wxMouseEvent& event)
500 {
501  // Set to drag mode.
502  switch(m_mode) {
503  case MODE_INSERT: {
504  m_mode = MODE_DRAG_INSERT;
505  } break;
506  case MODE_PASTE: {
507  m_mode = MODE_DRAG_PASTE;
508  } break;
509  default: {
510  m_mode = MODE_DRAG;
511  } break;
512  }
513  m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
514 }
515 
516 void ControlEditor::OnMiddleUp(wxMouseEvent& event)
517 {
518  switch(m_mode) {
519  case MODE_DRAG_INSERT: {
520  m_mode = MODE_INSERT;
521  } break;
522  case MODE_DRAG_PASTE: {
523  m_mode = MODE_PASTE;
524  } break;
525  case MODE_INSERT:
526  case MODE_PASTE: {
527  // Does nothing.
528  } break;
529  default: {
530  m_mode = MODE_EDIT;
531  } break;
532  }
533 }
534 
535 void ControlEditor::OnMouseMotion(wxMouseEvent& event)
536 {
537  wxPoint2DDouble clickPoint = event.GetPosition();
538  bool redraw = false;
539 
540  switch(m_mode) {
541  case MODE_INSERT: {
542  Element* newElement = *(m_elementList.end() - 1); // Get the last element in the list.
543  newElement->Move(m_camera->ScreenToWorld(clickPoint));
544  redraw = true;
545  } break;
546  case MODE_INSERT_LINE: {
547  ConnectionLine* line = *(m_connectionList.end() - 1);
548  line->SetTemporarySecondPoint(m_camera->ScreenToWorld(clickPoint));
549  line->UpdatePoints();
550  redraw = true;
551  } break;
552  case MODE_DRAG:
553  case MODE_DRAG_INSERT:
554  case MODE_DRAG_PASTE: {
555  m_camera->SetTranslation(clickPoint);
556  redraw = true;
557  } break;
558  case MODE_MOVE_ELEMENT: {
559  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
560  Element* element = *it;
561  if(element->IsSelected()) {
562  element->Move(m_camera->ScreenToWorld(clickPoint));
563  auto childList = element->GetChildList();
564  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
565  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
566  line->UpdatePoints();
567  }
568  redraw = true;
569  }
570  }
571  } break;
572  case MODE_MOVE_LINE: {
573  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; it++) {
574  ConnectionLine* line = *it;
575  if(line->IsSelected()) {
576  line->Move(m_camera->ScreenToWorld(clickPoint));
577  redraw = true;
578  }
579  }
580  } break;
581  case MODE_SELECTION_RECT: {
582  wxPoint2DDouble currentPos = m_camera->ScreenToWorld(clickPoint);
583  double x, y, w, h;
584  if(currentPos.m_x < m_startSelRect.m_x) {
585  x = currentPos.m_x;
586  w = m_startSelRect.m_x - currentPos.m_x;
587  } else {
588  x = m_startSelRect.m_x;
589  w = currentPos.m_x - m_startSelRect.m_x;
590  }
591  if(currentPos.m_y < m_startSelRect.m_y) {
592  y = currentPos.m_y;
593  h = m_startSelRect.m_y - currentPos.m_y;
594  } else {
595  y = m_startSelRect.m_y;
596  h = currentPos.m_y - m_startSelRect.m_y;
597  }
598 
599  m_selectionRect = wxRect2DDouble(x, y, w, h);
600  redraw = true;
601  } break;
602  default:
603  break;
604  }
605 
606  if(redraw) Redraw();
607  event.Skip();
608 }
609 
610 void ControlEditor::OnScroll(wxMouseEvent& event)
611 {
612  if(event.GetWheelRotation() > 0)
613  m_camera->SetScale(event.GetPosition(), +0.05);
614  else
615  m_camera->SetScale(event.GetPosition(), -0.05);
616 
617  Redraw();
618 }
619 
620 void ControlEditor::OnIdle(wxIdleEvent& event) { ConsolidateTexts(); }
621 void ControlEditor::OnKeyDown(wxKeyEvent& event)
622 {
623  char key = event.GetUnicodeKey();
624  if(key != WXK_NONE) {
625  switch(key) {
626  case WXK_DELETE: // Delete selected elements.
627  {
628  DeleteSelectedElements();
629  } break;
630  case 'R': // Rotate the selected elements.
631  {
632  RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
633  } break;
634  case 'L': {
635  // tests
636  } break;
637  }
638  }
639 }
640 
641 void ControlEditor::RotateSelectedElements(bool clockwise)
642 {
643  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
644  Element* element = *it;
645  if(element->IsSelected()) {
646  element->Rotate(clockwise);
647  auto childList = element->GetChildList();
648  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
649  ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
650  line->UpdatePoints();
651  }
652  }
653  }
654  Redraw();
655 }
656 
657 void ControlEditor::DeleteSelectedElements()
658 {
659  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
660  Element* element = *it;
661  if(element->IsSelected()) {
662  // Remove child/parent.
663  auto childList = element->GetChildList();
664  for(auto itC = childList.begin(), itEnd = childList.end(); itC != itEnd; ++itC) {
665  // The child is always a connection line.
666  ConnectionLine* child = static_cast<ConnectionLine*>(*itC);
667  // Delete the connection line.
668  for(auto itCo = m_connectionList.begin(); itCo != m_connectionList.end(); ++itCo) {
669  ConnectionLine* line = *itCo;
670  if(line == child) {
671  itCo = DeleteLineFromList(itCo);
672  break;
673  }
674  }
675  }
676  m_elementList.erase(it--);
677  if(element) delete element;
678  }
679  }
680 
681  for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
682  ConnectionLine* line = *it;
683  if(line->IsSelected()) {
684  it = DeleteLineFromList(it);
685  }
686  }
687  Redraw();
688 }
689 
690 std::vector<ConnectionLine*>::iterator ControlEditor::DeleteLineFromList(std::vector<ConnectionLine*>::iterator& it)
691 {
692  ConnectionLine* cLine = *it;
693  auto childList = cLine->GetLineChildList();
694  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
695  ConnectionLine* child = *itC;
696  for(auto itL = m_connectionList.begin(); itL != m_connectionList.end(); ++itL) {
697  ConnectionLine* childOnList = *itL;
698  if(childOnList == child) {
699  itL = DeleteLineFromList(itL);
700  }
701  }
702  }
703  // Remove
704  auto parentList = cLine->GetParentList();
705  for(auto itP = parentList.begin(), itEnd = parentList.end(); itP != itEnd; ++itP) {
706  Element* parent = *itP;
707  if(parent) parent->RemoveChild(cLine);
708  }
709  if(cLine->GetParentLine()) cLine->GetParentLine()->RemoveChild(cLine);
710  // Free nodes
711  auto nodeList = cLine->GetNodeList();
712  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
713  Node* node = *itN;
714  node->SetConnected(false);
715  }
716  m_connectionList.erase(it--);
717  if(cLine) delete cLine;
718  return it;
719 }
720 
721 void ControlEditor::CheckConnections()
722 {
723  for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
724  ConnectionLine* cLine = *it;
725  if(cLine->GetType() == ConnectionLine::ELEMENT_ELEMENT) {
726  if(cLine->GetParentList().size() < 2) {
727  it = DeleteLineFromList(it);
728  }
729  }
730  }
731 }
732 
733 void ControlEditor::OnExportClick(wxCommandEvent& event)
734 {
735  FileHanding fileHandling(this);
736 
737  wxFileDialog saveFileDialog(this, _("Save CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
738  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
739  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
740 
741  fileHandling.SaveControl(saveFileDialog.GetPath());
742  wxFileName fileName(saveFileDialog.GetPath());
743  event.Skip();
744 }
745 
746 void ControlEditor::OnImportClick(wxCommandEvent& event)
747 {
748  wxFileDialog openFileDialog(this, _("Open CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
749  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
750  if(openFileDialog.ShowModal() == wxID_CANCEL) return;
751 
752  wxFileName fileName(openFileDialog.GetPath());
753 
754  FileHanding fileHandling(this);
755  if(!fileHandling.OpenControl(fileName, m_elementList, m_connectionList)) {
756  wxMessageDialog msgDialog(this, _("It was not possible to open the selected file."), _("Error"),
757  wxOK | wxCENTRE | wxICON_ERROR);
758  msgDialog.ShowModal();
759  }
760 
761  SetLastElementID();
762  Redraw();
763  event.Skip();
764 }
765 
766 void ControlEditor::OnTestClick(wxCommandEvent& event)
767 {
768  ControlSystemTest csTest(this, &m_inputType, &m_startTime, &m_slope, &m_timeStep, &m_simTime);
769  if(csTest.ShowModal() == wxID_OK) {
770  double printStep = 1e-3;
771  double pdbStep = 1e-1;
772 
773  wxProgressDialog pbd(_("Test"), _("Initializing..."), 100, this,
774  wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_SMOOTH);
775  ControlElementSolver solver(this, m_timeStep, 1e-5);
776  if(solver.IsOK()) {
777  bool simStopped = false;
778  double currentTime = 0.0;
779  double printTime = 0.0;
780  double pdbTime = 0.0;
781  std::vector<double> time;
782  std::vector<double> solution;
783  std::vector<double> inputV;
784  while(currentTime <= m_simTime) {
785  double input = 0.0;
786  if(currentTime >= m_startTime) {
787  switch(m_inputType) {
788  case 0: {
789  input = m_slope;
790  } break;
791  case 1: {
792  input = m_slope * (currentTime - m_startTime);
793  } break;
794  case 2: {
795  input = m_slope * std::pow(currentTime - m_startTime, 2);
796  } break;
797  default: {
798  input = 0.0;
799  break;
800  }
801  }
802  }
803 
804  solver.SolveNextStep(input);
805 
806  if(printTime >= printStep) {
807  time.push_back(currentTime);
808  solution.push_back(solver.GetLastSolution());
809  inputV.push_back(input);
810  printTime = 0.0;
811  }
812 
813  if(pdbTime > pdbStep) {
814  if(!pbd.Update((currentTime / m_simTime) * 100, wxString::Format("Time = %.2fs", currentTime))) {
815  pbd.Update(100);
816  simStopped = true;
817  currentTime = m_simTime;
818  }
819  pdbTime = 0.0;
820  }
821 
822  printTime += m_timeStep;
823  currentTime += m_timeStep;
824  pdbTime += m_timeStep;
825  }
826  if(!simStopped) {
827  std::vector<ElementPlotData> epdList;
828  ElementPlotData curveData(_("I/O"), ElementPlotData::CT_TEST);
829  curveData.AddData(inputV, _("Input"));
830  curveData.AddData(solution, _("Output"));
831 
832  curveData.SetPlot(0);
833  curveData.SetColour(0, *wxRED);
834  curveData.SetPlot(1);
835  curveData.SetColour(1, *wxBLUE);
836 
837  epdList.push_back(curveData);
838 
839  ChartView* cView = new ChartView(this, epdList, time);
840  cView->Show();
841  cView->UpdatePlot();
842  }
843  } else {
844  wxMessageDialog msgDialog(this, _("It was not possible to solve the control system"), _("Error"),
845  wxOK | wxCENTRE | wxICON_ERROR);
846  msgDialog.ShowModal();
847  }
848  }
849 }
850 
851 void ControlEditor::OnClose(wxCloseEvent& event)
852 {
853  if(m_ctrlContainer) {
854  m_ctrlContainer->FillContainer(this);
855  }
856  event.Skip();
857 }
858 
859 void ControlEditor::ConsolidateTexts()
860 {
861  // Solve wxGLString bug.
862  if(m_firstDraw) {
863  TransferFunction* tf = new TransferFunction(0);
864  m_elementList.push_back(tf);
865  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
866  ControlElement* element = *it;
867  element->UpdateText();
868  }
869  Redraw();
870  m_elementList.pop_back();
871  delete tf;
872  m_firstDraw = false;
873  }
874 }
875 
876 void ControlEditor::SetLastElementID()
877 {
878  int id = 0;
879  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
880  int elementID = (*it)->GetID();
881  if(id < elementID) id = elementID;
882  }
883  for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
884  int elementID = (*it)->GetID();
885  if(id < elementID) id = elementID;
886  }
887  m_lastElementID = ++id;
888 }
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Element.cpp:123
Multiplies two inputs.
Definition: Multiplier.h:32
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
void SetSelected(bool selected=true)
Set element selection.
Definition: Element.h:146
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
-
Definition: Sum.h:26
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
virtual void Move(wxPoint2DDouble position)
Move the element other position.
virtual std::vector< Element * > GetChildList() const
Get the Child list.
Definition: Element.h:511
Node of a control element. This class manages the user interaction with the connection and control el...
@@ -115,19 +115,21 @@ $(document).ready(function(){initNavTree('_control_editor_8cpp_source.html','');
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Element.h:240
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Element.h:302
- -
Generates an output following an exponential function. .
Definition: Exponential.h:33
+ +
Generates an output following an exponential function.
Definition: Exponential.h:32
+
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Element.h:307
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Element.h:534
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Connection between two control elements or other connection line and an element.
- +
Calculates the time response by a frequency domain transfer function.
bool IsSelected() const
Checks if the element is selected.
Definition: Element.h:202
@@ -140,6 +142,7 @@ $(document).ready(function(){initNavTree('_control_editor_8cpp_source.html','');
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
A control element that provides a constant value.
Definition: Constant.h:35
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Form to edit properties to test the control system created.
diff --git a/docs/doxygen/html/_control_editor_8h_source.html b/docs/doxygen/html/_control_editor_8h_source.html index 02a1e13..f8bfc03 100644 --- a/docs/doxygen/html/_control_editor_8h_source.html +++ b/docs/doxygen/html/_control_editor_8h_source.html @@ -89,23 +89,23 @@ $(document).ready(function(){initNavTree('_control_editor_8h_source.html','');})
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLEDITOR_H
19 #define CONTROLEDITOR_H
20 
21 #include "ControlEditorBase.h"
22 #include <wx/wrapsizer.h>
23 #include <wx/dcclient.h>
24 #include <wx/dcscreen.h>
25 #include <wx/graphics.h>
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28 
29 #include <wx/progdlg.h>
30 
31 #include "IOControl.h"
32 #include "ControlSystemTest.h"
33 
34 class FileHanding;
35 class Camera;
36 class Element;
37 class ControlElement;
38 class TransferFunction;
39 class ConnectionLine;
40 class Sum;
41 class Multiplier;
42 class Limiter;
43 class RateLimiter;
44 class Exponential;
45 class Constant;
46 class Gain;
47 
50 
51 class ChartView;
52 class ElementDataObject;
53 
54 enum ControlElementButtonID { ID_IO = 0, ID_TF, ID_SUM, ID_CONST, ID_LIMITER, ID_GAIN, ID_MULT, ID_EXP, ID_RATELIM };
55 
63 class ControlElementButton : public wxWindow
64 {
65  public:
66  ControlElementButton(wxWindow* parent, wxString label, wxImage image, wxWindowID id = wxID_ANY);
68 
69  protected:
70  virtual void OnPaint(wxPaintEvent& event);
71  virtual void OnMouseEnter(wxMouseEvent& event);
72  virtual void OnMouseLeave(wxMouseEvent& event);
73  virtual void OnLeftClickDown(wxMouseEvent& event);
74  virtual void OnLeftClickUp(wxMouseEvent& event);
75 
76  wxString m_label;
77  wxFont m_font;
78  wxPoint m_labelPosition;
79 
80  wxImage m_image;
81  wxSize m_imageSize;
82  wxPoint m_imagePosition;
83 
84  int m_borderSize = 2;
85  bool m_mouseAbove = false;
86  bool m_selected = false;
87 
88  wxSize m_buttonSize;
89 };
90 
92 {
93  public:
94  enum ControlEditorMode {
95  MODE_EDIT = 0,
96  MODE_MOVE_ELEMENT,
97  MODE_MOVE_LINE,
98  MODE_DRAG,
99  MODE_DRAG_INSERT,
100  MODE_INSERT,
101  MODE_INSERT_LINE,
102  MODE_SELECTION_RECT,
103  MODE_PASTE,
104  MODE_DRAG_PASTE
105  };
106 
107  ControlEditor(wxWindow* parent,
108  int ioflags = IOControl::IN_TERMINAL_VOLTAGE | IOControl::IN_VELOCITY | IOControl::OUT_FIELD_VOLTAGE |
109  IOControl::OUT_MEC_POWER);
110  virtual ~ControlEditor();
111 
112  virtual void AddElement(ControlElementButtonID id);
113  virtual void Redraw() { m_glCanvas->Refresh(); }
114  virtual void RotateSelectedElements(bool clockwise);
115  virtual void DeleteSelectedElements();
116  virtual void CheckConnections();
117  virtual std::vector<ConnectionLine*> GetConnectionLineList() const { return m_connectionList; }
118  virtual std::vector<ControlElement*> GetControlElementList() const { return m_elementList; }
119  virtual void SetElementsList(std::vector<ControlElement*> elementList) { m_elementList = elementList; }
120  virtual void SetConnectionsList(std::vector<ConnectionLine*> connectionList) { m_connectionList = connectionList; }
121  virtual void SetControlContainer(ControlElementContainer* ctrlContainer) { m_ctrlContainer = ctrlContainer; }
122  protected:
123  virtual void OnClose(wxCloseEvent& event);
124  virtual void OnTestClick(wxCommandEvent& event);
125  virtual void OnButtonOKClick(wxCommandEvent& event) { Close(); }
126  virtual void OnImportClick(wxCommandEvent& event);
127  virtual void OnExportClick(wxCommandEvent& event);
128  virtual void OnKeyDown(wxKeyEvent& event);
129  virtual void OnIdle(wxIdleEvent& event);
130  virtual void OnScroll(wxMouseEvent& event);
131  virtual void OnDoubleClick(wxMouseEvent& event);
132  virtual void OnLeftClickDown(wxMouseEvent& event);
133  virtual void OnLeftClickUp(wxMouseEvent& event);
134  virtual void OnMiddleDown(wxMouseEvent& event);
135  virtual void OnMiddleUp(wxMouseEvent& event);
136  virtual void OnMouseMotion(wxMouseEvent& event);
137  virtual void OnPaint(wxPaintEvent& event);
138  virtual void LeftClickDown(wxMouseEvent& event);
139 
140  void BuildControlElementPanel();
141  void SetViewport();
142  void ConsolidateTexts();
143  void SetLastElementID();
144 
145  std::vector<ConnectionLine*>::iterator DeleteLineFromList(std::vector<ConnectionLine*>::iterator& it);
146 
147  wxGLContext* m_glContext = NULL;
148  Camera* m_camera = NULL;
149 
150  ControlEditorMode m_mode = MODE_EDIT;
151 
152  wxRect2DDouble m_selectionRect;
153  wxPoint2DDouble m_startSelRect;
154 
155  std::vector<ControlElement*> m_elementList;
156  std::vector<ConnectionLine*> m_connectionList;
157 
158  ControlElementContainer* m_ctrlContainer = NULL;
159 
160  bool m_firstDraw = true;
161  int m_ioFlags;
162 
163  int m_lastElementID = 0;
164 
165  int m_inputType = 0;
166  double m_startTime = 1.0;
167  double m_slope = 1.0;
168  double m_timeStep = 1e-4;
169  double m_simTime = 10.0;
170 };
171 #endif // CONTROLEDITOR_H
Multiplies two inputs.
Definition: Multiplier.h:32
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
-
Definition: Sum.h:26
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
Save and opens the projects created on disk.
Definition: FileHanding.h:43
Limits the input value by superior and inferior values.
Definition: Limiter.h:32
Class responsible for the correct visualization of the elements on screen.
Definition: Camera.h:30
This class is responsible to handle the user interaction with control elements.
Definition: ControlEditor.h:63
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
- +
Generates an output following an exponential function.
Definition: Exponential.h:32
+
Class to store the elements in the clipboard.
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
Connection between two control elements or other connection line and an element.
- +
Calculates the time response by a frequency domain transfer function.
diff --git a/docs/doxygen/html/_control_element_8cpp_source.html b/docs/doxygen/html/_control_element_8cpp_source.html index abf4a3c..66bd3f0 100644 --- a/docs/doxygen/html/_control_element_8cpp_source.html +++ b/docs/doxygen/html/_control_element_8cpp_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_control_element_8cpp_source.html','')
ControlElement.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlElement.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
23 Node::Node(wxPoint2DDouble position, NodeType nodeType, double borderSize)
24 {
25  double totalRadius = m_radius + borderSize;
26  m_rect = wxRect2DDouble(position.m_x - totalRadius, position.m_y - totalRadius, totalRadius * 2, totalRadius * 2);
27  m_nodeType = nodeType;
28 
29  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius));
30  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius));
31  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius + 1, 0));
32 }
33 
34 Node::~Node() {}
35 void Node::SetPosition(wxPoint2DDouble position)
36 {
37  m_rect = wxRect2DDouble(position.m_x - m_rect.m_width / 2, position.m_y - m_rect.m_height / 2, m_rect.m_width,
38  m_rect.m_height);
39  m_triPts[0] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius);
40  m_triPts[1] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius);
41  m_triPts[2] = GetPosition() + wxPoint2DDouble(-m_radius + 1, 0);
42 
43  // Rotate according to the angle (node rect center as reference)
44  if(m_angle != 0.0) RotateTriPt(m_angle);
45 }
46 
47 void Node::StartMove(wxPoint2DDouble position)
48 {
49  m_moveStartPt = position;
50  m_movePos = m_rect.GetPosition() - wxPoint2DDouble(-m_rect.m_width / 2, -m_rect.m_height / 2);
51 }
52 
53 void Node::Move(wxPoint2DDouble position) { SetPosition(m_movePos + position - m_moveStartPt); }
54 wxPoint2DDouble Node::GetPosition() const
55 {
56  return m_rect.GetPosition() + wxPoint2DDouble(m_rect.GetSize().GetWidth() / 2, m_rect.GetSize().GetHeight() / 2);
57 }
58 
59 void Node::RotateTriPt(double angle)
60 {
61  double radAngle = wxDegToRad(angle);
62  wxPoint2DDouble rectCenter =
63  m_rect.GetPosition() + wxPoint2DDouble(m_rect.GetSize().GetWidth() / 2.0, m_rect.GetSize().GetHeight() / 2.0);
64  m_triPts[0] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[0].m_x - rectCenter.m_x) -
65  std::sin(radAngle) * (m_triPts[0].m_y - rectCenter.m_y) + rectCenter.m_x,
66  std::sin(radAngle) * (m_triPts[0].m_x - rectCenter.m_x) +
67  std::cos(radAngle) * (m_triPts[0].m_y - rectCenter.m_y) + rectCenter.m_y);
68  m_triPts[1] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[1].m_x - rectCenter.m_x) -
69  std::sin(radAngle) * (m_triPts[1].m_y - rectCenter.m_y) + rectCenter.m_x,
70  std::sin(radAngle) * (m_triPts[1].m_x - rectCenter.m_x) +
71  std::cos(radAngle) * (m_triPts[1].m_y - rectCenter.m_y) + rectCenter.m_y);
72  m_triPts[2] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[2].m_x - rectCenter.m_x) -
73  std::sin(radAngle) * (m_triPts[2].m_y - rectCenter.m_y) + rectCenter.m_x,
74  std::sin(radAngle) * (m_triPts[2].m_x - rectCenter.m_x) +
75  std::cos(radAngle) * (m_triPts[2].m_y - rectCenter.m_y) + rectCenter.m_y);
76 }
77 
78 void Node::Rotate(bool clockwise)
79 {
80  if(clockwise)
81  m_angle += 90.0;
82  else
83  m_angle -= 90.0;
84  if(m_angle >= 360.0)
85  m_angle = 0.0;
86  else if(m_angle < 0)
87  m_angle = 270.0;
88 
89  // Update input triangle points.
90  m_triPts[0] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius);
91  m_triPts[1] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius);
92  m_triPts[2] = GetPosition() + wxPoint2DDouble(-m_radius + 1, 0);
93 
94  // Rotate according to the angle (node rect center as reference)
95  if(m_angle != 0.0) RotateTriPt(m_angle);
96 }
97 
98 bool Node::Contains(wxPoint2DDouble position) const
99 {
100  if(m_connected) return false;
101  return m_rect.Contains(position);
102 }
103 
104 ControlElement::ControlElement(int id) : Element() { m_elementID = id; }
105 ControlElement::~ControlElement() {}
106 void ControlElement::DrawNodes() const
107 {
108  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
109  Node* node = *it;
110  DrawCircle(node->GetPosition(), node->GetRadius(), 10, GL_POLYGON);
111  if(node->GetNodeType() == Node::NODE_IN) {
112  DrawTriangle(node->GetInTrianglePts());
113  }
114  }
115 }
116 
117 void ControlElement::StartMove(wxPoint2DDouble position)
118 {
119  m_moveStartPt = position;
120  m_movePos = m_position;
121  for(int i = 0; i < (int)m_nodeList.size(); ++i) {
122  m_nodeList[i]->StartMove(position);
123  }
124 }
125 
126 void ControlElement::Move(wxPoint2DDouble position)
127 {
128  SetPosition(m_movePos + position - m_moveStartPt);
129  for(int i = 0; i < (int)m_nodeList.size(); ++i) {
130  m_nodeList[i]->Move(position);
131  }
132 }
133 
134 bool ControlElement::Solve(double input, double timeStep)
135 {
136  m_output = input;
137  return true;
138 }
139 
140 void ControlElement::ReplaceNode(Node* oldNode, Node* newNode)
141 {
142  for(unsigned int i = 0; i < m_nodeList.size(); i++) {
143  if(m_nodeList[i] == oldNode) m_nodeList[i] = newNode;
144  }
145 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlElement.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
23 Node::Node(wxPoint2DDouble position, NodeType nodeType, double borderSize)
24 {
25  double totalRadius = m_radius + borderSize;
26  m_rect = wxRect2DDouble(position.m_x - totalRadius, position.m_y - totalRadius, totalRadius * 2, totalRadius * 2);
27  m_nodeType = nodeType;
28 
29  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius));
30  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius));
31  m_triPts.push_back(GetPosition() + wxPoint2DDouble(-m_radius + 1, 0));
32 }
33 
34 Node::~Node() {}
35 void Node::SetPosition(wxPoint2DDouble position)
36 {
37  m_rect = wxRect2DDouble(position.m_x - m_rect.m_width / 2, position.m_y - m_rect.m_height / 2, m_rect.m_width,
38  m_rect.m_height);
39  m_triPts[0] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius);
40  m_triPts[1] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius);
41  m_triPts[2] = GetPosition() + wxPoint2DDouble(-m_radius + 1, 0);
42 
43  // Rotate according to the angle (node rect center as reference)
44  if(m_angle != 0.0) RotateTriPt(m_angle);
45 }
46 
47 void Node::StartMove(wxPoint2DDouble position)
48 {
49  m_moveStartPt = position;
50  m_movePos = m_rect.GetPosition() - wxPoint2DDouble(-m_rect.m_width / 2, -m_rect.m_height / 2);
51 }
52 
53 void Node::Move(wxPoint2DDouble position) { SetPosition(m_movePos + position - m_moveStartPt); }
54 wxPoint2DDouble Node::GetPosition() const
55 {
56  return m_rect.GetPosition() + wxPoint2DDouble(m_rect.GetSize().GetWidth() / 2, m_rect.GetSize().GetHeight() / 2);
57 }
58 
59 void Node::RotateTriPt(double angle)
60 {
61  double radAngle = wxDegToRad(angle);
62  wxPoint2DDouble rectCenter =
63  m_rect.GetPosition() + wxPoint2DDouble(m_rect.GetSize().GetWidth() / 2.0, m_rect.GetSize().GetHeight() / 2.0);
64  m_triPts[0] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[0].m_x - rectCenter.m_x) -
65  std::sin(radAngle) * (m_triPts[0].m_y - rectCenter.m_y) + rectCenter.m_x,
66  std::sin(radAngle) * (m_triPts[0].m_x - rectCenter.m_x) +
67  std::cos(radAngle) * (m_triPts[0].m_y - rectCenter.m_y) + rectCenter.m_y);
68  m_triPts[1] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[1].m_x - rectCenter.m_x) -
69  std::sin(radAngle) * (m_triPts[1].m_y - rectCenter.m_y) + rectCenter.m_x,
70  std::sin(radAngle) * (m_triPts[1].m_x - rectCenter.m_x) +
71  std::cos(radAngle) * (m_triPts[1].m_y - rectCenter.m_y) + rectCenter.m_y);
72  m_triPts[2] = wxPoint2DDouble(std::cos(radAngle) * (m_triPts[2].m_x - rectCenter.m_x) -
73  std::sin(radAngle) * (m_triPts[2].m_y - rectCenter.m_y) + rectCenter.m_x,
74  std::sin(radAngle) * (m_triPts[2].m_x - rectCenter.m_x) +
75  std::cos(radAngle) * (m_triPts[2].m_y - rectCenter.m_y) + rectCenter.m_y);
76 }
77 
78 void Node::Rotate(bool clockwise)
79 {
80  if(clockwise)
81  m_angle += 90.0;
82  else
83  m_angle -= 90.0;
84  if(m_angle >= 360.0)
85  m_angle = 0.0;
86  else if(m_angle < 0)
87  m_angle = 270.0;
88 
89  // Update input triangle points.
90  m_triPts[0] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, m_radius);
91  m_triPts[1] = GetPosition() + wxPoint2DDouble(-m_radius - m_rect.GetSize().GetWidth() / 2, -m_radius);
92  m_triPts[2] = GetPosition() + wxPoint2DDouble(-m_radius + 1, 0);
93 
94  // Rotate according to the angle (node rect center as reference)
95  if(m_angle != 0.0) RotateTriPt(m_angle);
96 }
97 
98 bool Node::Contains(wxPoint2DDouble position) const
99 {
100  if(m_connected) return false;
101  return m_rect.Contains(position);
102 }
103 
104 ControlElement::ControlElement(int id) : Element() { m_elementID = id; }
105 ControlElement::~ControlElement() {}
106 void ControlElement::DrawNodes() const
107 {
108  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
109  Node* node = *it;
110  DrawCircle(node->GetPosition(), node->GetRadius(), 10, GL_POLYGON);
111  if(node->GetNodeType() == Node::NODE_IN) {
112  DrawTriangle(node->GetInTrianglePts());
113  }
114  }
115 }
116 
117 void ControlElement::StartMove(wxPoint2DDouble position)
118 {
119  m_moveStartPt = position;
120  m_movePos = m_position;
121  for(int i = 0; i < (int)m_nodeList.size(); ++i) {
122  m_nodeList[i]->StartMove(position);
123  }
124 }
125 
126 void ControlElement::Move(wxPoint2DDouble position)
127 {
128  SetPosition(m_movePos + position - m_moveStartPt);
129  for(int i = 0; i < (int)m_nodeList.size(); ++i) {
130  m_nodeList[i]->Move(position);
131  }
132 }
133 
134 bool ControlElement::Solve(double input, double timeStep)
135 {
136  m_output = input;
137  return true;
138 }
139 
140 void ControlElement::ReplaceNode(Node* oldNode, Node* newNode)
141 {
142  for(unsigned int i = 0; i < m_nodeList.size(); i++) {
143  if(m_nodeList[i] == oldNode) m_nodeList[i] = newNode;
144  }
145 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Node of a control element. This class manages the user interaction with the connection and control el...
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Base class of a control element. Provide general methods to other control classes.
diff --git a/docs/doxygen/html/_control_element_8h_source.html b/docs/doxygen/html/_control_element_8h_source.html index 2222b15..4e1c5d9 100644 --- a/docs/doxygen/html/_control_element_8h_source.html +++ b/docs/doxygen/html/_control_element_8h_source.html @@ -88,9 +88,9 @@ $(document).ready(function(){initNavTree('_control_element_8h_source.html','');}
ControlElement.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLELEMENT_H
19 #define CONTROLELEMENT_H
20 
21 #include "Element.h"
22 
30 class Node
31 {
32  public:
33  enum NodeType { NODE_IN = 0, NODE_OUT };
34 
35  Node(wxPoint2DDouble position = wxPoint2DDouble(0, 0), NodeType nodeType = NODE_IN, double borderSize = 0.0);
36  ~Node();
37 
38  wxRect2DDouble GetRect() const { return m_rect; }
39  void SetRect(wxRect2DDouble rect) { m_rect = rect; }
40  wxPoint2DDouble GetPosition() const;
41  void SetPosition(wxPoint2DDouble position);
42 
43  NodeType GetNodeType() const { return m_nodeType; }
44  void SetNodeType(NodeType nodeType) { m_nodeType = nodeType; }
45  double GetRadius() const { return m_radius; }
46  std::vector<wxPoint2DDouble> GetInTrianglePts() const { return m_triPts; }
47  double GetAngle() const { return m_angle; }
48  void SetAngle(double angle) { m_angle = angle; }
49  void Rotate(bool clockwise = true);
50 
51  void RotateTriPt(double angle);
52 
53  void StartMove(wxPoint2DDouble position);
54  void Move(wxPoint2DDouble position);
55  bool Contains(wxPoint2DDouble position) const;
56 
57  bool IsConnected() const { return m_connected; }
58  void SetConnected(bool connected = true) { m_connected = connected; }
59  int GetID() const { return m_id; }
60  void SetID(int id) { m_id = id; }
61  protected:
62  int m_id = -1;
63 
64  wxRect2DDouble m_rect;
65  NodeType m_nodeType;
66 
67  bool m_connected = false;
68 
69  wxPoint2DDouble m_moveStartPt;
70  wxPoint2DDouble m_movePos;
71 
72  double m_radius = 3.0;
73  std::vector<wxPoint2DDouble> m_triPts;
74  double m_angle = 0.0;
75 };
76 
84 class ControlElement : public Element
85 {
86  public:
87  ControlElement(int id);
88  ~ControlElement();
89 
90  virtual void StartMove(wxPoint2DDouble position);
91  virtual void Move(wxPoint2DDouble position);
92 
93  void SetNodeList(std::vector<Node*> nodeList) { m_nodeList = nodeList; }
94  std::vector<Node*> GetNodeList() const { return m_nodeList; }
95  virtual void DrawNodes() const;
96  virtual void ReplaceNode(Node* oldNode, Node* newNode);
97  virtual void UpdateText() {}
98  virtual bool IsSolved() const { return m_solved; }
99  virtual void SetSolved(bool solved = true) { m_solved = solved; }
100  virtual bool Solve(double input, double timeStep);
101  virtual double GetOutput() const { return m_output; }
102  virtual void SetOutput(double output) { m_output = output; }
103  protected:
104  std::vector<Node*> m_nodeList;
105  bool m_solved = false;
106  double m_output = 0.0;
107 };
108 
109 #endif // CONTROLELEMENT_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLELEMENT_H
19 #define CONTROLELEMENT_H
20 
21 #include "Element.h"
22 
30 class Node
31 {
32  public:
33  enum NodeType { NODE_IN = 0, NODE_OUT };
34 
35  Node(wxPoint2DDouble position = wxPoint2DDouble(0, 0), NodeType nodeType = NODE_IN, double borderSize = 0.0);
36  ~Node();
37 
38  wxRect2DDouble GetRect() const { return m_rect; }
39  void SetRect(wxRect2DDouble rect) { m_rect = rect; }
40  wxPoint2DDouble GetPosition() const;
41  void SetPosition(wxPoint2DDouble position);
42 
43  NodeType GetNodeType() const { return m_nodeType; }
44  void SetNodeType(NodeType nodeType) { m_nodeType = nodeType; }
45  double GetRadius() const { return m_radius; }
46  std::vector<wxPoint2DDouble> GetInTrianglePts() const { return m_triPts; }
47  double GetAngle() const { return m_angle; }
48  void SetAngle(double angle) { m_angle = angle; }
49  void Rotate(bool clockwise = true);
50 
51  void RotateTriPt(double angle);
52 
53  void StartMove(wxPoint2DDouble position);
54  void Move(wxPoint2DDouble position);
55  bool Contains(wxPoint2DDouble position) const;
56 
57  bool IsConnected() const { return m_connected; }
58  void SetConnected(bool connected = true) { m_connected = connected; }
59  int GetID() const { return m_id; }
60  void SetID(int id) { m_id = id; }
61  protected:
62  int m_id = -1;
63 
64  wxRect2DDouble m_rect;
65  NodeType m_nodeType;
66 
67  bool m_connected = false;
68 
69  wxPoint2DDouble m_moveStartPt;
70  wxPoint2DDouble m_movePos;
71 
72  double m_radius = 3.0;
73  std::vector<wxPoint2DDouble> m_triPts;
74  double m_angle = 0.0;
75 };
76 
84 class ControlElement : public Element
85 {
86  public:
87  ControlElement(int id);
88  ~ControlElement();
89 
90  virtual void StartMove(wxPoint2DDouble position);
91  virtual void Move(wxPoint2DDouble position);
92 
93  void SetNodeList(std::vector<Node*> nodeList) { m_nodeList = nodeList; }
94  std::vector<Node*> GetNodeList() const { return m_nodeList; }
95  virtual void DrawNodes() const;
96  virtual void ReplaceNode(Node* oldNode, Node* newNode);
97  virtual void UpdateText() {}
98  virtual bool IsSolved() const { return m_solved; }
99  virtual void SetSolved(bool solved = true) { m_solved = solved; }
100  virtual bool Solve(double input, double timeStep);
101  virtual double GetOutput() const { return m_output; }
102  virtual void SetOutput(double output) { m_output = output; }
103  protected:
104  std::vector<Node*> m_nodeList;
105  bool m_solved = false;
106  double m_output = 0.0;
107 };
108 
109 #endif // CONTROLELEMENT_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Node of a control element. This class manages the user interaction with the connection and control el...
-
Class to manage color of OpenGL.
+
diff --git a/docs/doxygen/html/_control_element_container_8cpp_source.html b/docs/doxygen/html/_control_element_container_8cpp_source.html index eb02b94..1e4bdf8 100644 --- a/docs/doxygen/html/_control_element_container_8cpp_source.html +++ b/docs/doxygen/html/_control_element_container_8cpp_source.html @@ -89,20 +89,20 @@ $(document).ready(function(){initNavTree('_control_element_container_8cpp_source
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "ControlEditor.h"
20 #include "ControlElement.h"
21 
22 ControlElementContainer::ControlElementContainer() { ClearContainer(); }
23 ControlElementContainer::~ControlElementContainer() {}
24 void ControlElementContainer::FillContainer(ControlEditor* editor)
25 {
26  ClearContainer();
27  m_ctrlElementsList = editor->GetControlElementList();
28  m_cLineList = editor->GetConnectionLineList();
29  auto cElementList = editor->GetControlElementList();
30  for(auto it = cElementList.begin(), itEnd = cElementList.end(); it != itEnd; ++it) {
31  if(Constant* constant = dynamic_cast<Constant*>(*it)) {
32  m_constantList.push_back(constant);
33  } else if(Exponential* exponential = dynamic_cast<Exponential*>(*it)) {
34  m_exponentialList.push_back(exponential);
35  } else if(Gain* gain = dynamic_cast<Gain*>(*it)) {
36  m_gainList.push_back(gain);
37  } else if(IOControl* ioControl = dynamic_cast<IOControl*>(*it)) {
38  m_ioControlList.push_back(ioControl);
39  } else if(Limiter* limiter = dynamic_cast<Limiter*>(*it)) {
40  m_limiterList.push_back(limiter);
41  } else if(Multiplier* multiplier = dynamic_cast<Multiplier*>(*it)) {
42  m_multiplierList.push_back(multiplier);
43  } else if(RateLimiter* rateLimiter = dynamic_cast<RateLimiter*>(*it)) {
44  m_rateLimiterList.push_back(rateLimiter);
45  } else if(Sum* sum = dynamic_cast<Sum*>(*it)) {
46  m_sumList.push_back(sum);
47  } else if(TransferFunction* tf = dynamic_cast<TransferFunction*>(*it)) {
48  m_tfList.push_back(tf);
49  }
50  }
51 }
52 
53 void ControlElementContainer::ClearContainer()
54 {
55  m_cLineList.clear();
56  m_constantList.clear();
57  m_exponentialList.clear();
58  m_gainList.clear();
59  m_ioControlList.clear();
60  m_limiterList.clear();
61  m_multiplierList.clear();
62  m_rateLimiterList.clear();
63  m_sumList.clear();
64  m_tfList.clear();
65 }
66 
67 void ControlElementContainer::FillContainer(std::vector<ControlElement*> controlElementList,
68  std::vector<ConnectionLine*> connectionLineList)
69 {
70  ClearContainer();
71  m_ctrlElementsList = controlElementList;
72  m_cLineList = connectionLineList;
73 
74  for(auto it = controlElementList.begin(), itEnd = controlElementList.end(); it != itEnd; ++it) {
75  if(Constant* constant = dynamic_cast<Constant*>(*it)) {
76  m_constantList.push_back(constant);
77  } else if(Exponential* exponential = dynamic_cast<Exponential*>(*it)) {
78  m_exponentialList.push_back(exponential);
79  } else if(Gain* gain = dynamic_cast<Gain*>(*it)) {
80  m_gainList.push_back(gain);
81  } else if(IOControl* ioControl = dynamic_cast<IOControl*>(*it)) {
82  m_ioControlList.push_back(ioControl);
83  } else if(Limiter* limiter = dynamic_cast<Limiter*>(*it)) {
84  m_limiterList.push_back(limiter);
85  } else if(Multiplier* multiplier = dynamic_cast<Multiplier*>(*it)) {
86  m_multiplierList.push_back(multiplier);
87  } else if(RateLimiter* rateLimiter = dynamic_cast<RateLimiter*>(*it)) {
88  m_rateLimiterList.push_back(rateLimiter);
89  } else if(Sum* sum = dynamic_cast<Sum*>(*it)) {
90  m_sumList.push_back(sum);
91  } else if(TransferFunction* tf = dynamic_cast<TransferFunction*>(*it)) {
92  m_tfList.push_back(tf);
93  }
94  }
95 }
96 
97 void ControlElementContainer::GetContainerCopy(std::vector<ControlElement*>& controlElementList,
98  std::vector<ConnectionLine*>& connectionLineList)
99 {
100  controlElementList.clear();
101  connectionLineList.clear();
102 
103  // Copy connection lines
104  for(auto it = m_cLineList.begin(), itEnd = m_cLineList.end(); it != itEnd; ++it) {
105  ConnectionLine* copy = static_cast<ConnectionLine*>((*it)->GetCopy());
106  connectionLineList.push_back(copy);
107  }
108 
109  // Copy elements (exept connection line).
110  int nodeID = 0;
111  for(auto it = m_ctrlElementsList.begin(), itEnd = m_ctrlElementsList.end(); it != itEnd; ++it) {
112  Element* oldElement = *it;
113  ControlElement* copy = static_cast<ControlElement*>(oldElement->GetCopy());
114  controlElementList.push_back(copy);
115  // Copy nodes.
116  std::vector<Node*> nodeList = copy->GetNodeList();
117  std::vector<Node*> nodeListCopy;
118  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
119  Node* node = *itN;
120  node->SetID(nodeID);
121  Node* copyNode = new Node();
122  *copyNode = *node;
123  nodeListCopy.push_back(copyNode);
124  nodeID++;
125  }
126  copy->SetNodeList(nodeListCopy);
127 
128  // Replace children to copies.
129  auto childList = copy->GetChildList();
130  for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
131  ConnectionLine* child = static_cast<ConnectionLine*>(*itC);
132  // Replace child's parent to copy.
133  for(auto itCL = connectionLineList.begin(), itEndCL = connectionLineList.end(); itCL != itEndCL; ++itCL) {
134  ConnectionLine* copyLine = *itCL;
135  if(copyLine->GetID() == child->GetID()) {
136  // Replace node.
137  nodeList = child->GetNodeList();
138  for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
139  Node* node = *itN;
140  for(auto itCN = nodeListCopy.begin(), itEndCN = nodeListCopy.end(); itCN != itEndCN; ++itCN) {
141  Node* nodeCopy = *itCN;
142  if(node->GetID() == nodeCopy->GetID()) {
143  copyLine->ReplaceNode(node, nodeCopy);
144  break;
145  }
146  }
147  }
148  copyLine->ReplaceParent(oldElement, copy);
149  copy->ReplaceChild(child, copyLine);
150  }
151  }
152  }
153  }
154 }
Multiplies two inputs.
Definition: Multiplier.h:32
- -
Definition: Sum.h:26
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
virtual std::vector< Element * > GetChildList() const
Get the Child list.
Definition: Element.h:511
Node of a control element. This class manages the user interaction with the connection and control el...
Limits the input value by superior and inferior values.
Definition: Limiter.h:32
Provides the communication with the power element.
Definition: IOControl.h:35
virtual void ReplaceChild(Element *oldChild, Element *newChild)
Replace a child from the list.
Definition: Element.cpp:362
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
Connection between two control elements or other connection line and an element.
- +
Calculates the time response by a frequency domain transfer function.
Base class of a control element. Provide general methods to other control classes.
virtual int GetID() const
Get the element ID.
Definition: Element.h:272
diff --git a/docs/doxygen/html/_control_element_container_8h.html b/docs/doxygen/html/_control_element_container_8h.html index 57f5343..1b8b197 100644 --- a/docs/doxygen/html/_control_element_container_8h.html +++ b/docs/doxygen/html/_control_element_container_8h.html @@ -99,8 +99,8 @@ $(document).ready(function(){initNavTree('_control_element_container_8h.html','' #include "Limiter.h"
#include "Multiplier.h"
#include "RateLimiter.h"
-#include "Sum.h"
-#include "TransferFunction.h"
+#include "Sum.h"
+#include "TransferFunction.h"

Go to the source code of this file.

diff --git a/docs/doxygen/html/_control_element_container_8h_source.html b/docs/doxygen/html/_control_element_container_8h_source.html index f0e83b3..c91c02d 100644 --- a/docs/doxygen/html/_control_element_container_8h_source.html +++ b/docs/doxygen/html/_control_element_container_8h_source.html @@ -88,9 +88,10 @@ $(document).ready(function(){initNavTree('_control_element_container_8h_source.h
ControlElementContainer.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLELEMENTCONTAINER_H
19 #define CONTROLELEMENTCONTAINER_H
20 
21 #include <vector>
22 
23 class ControlEditor;
24 class ControlElement;
25 
26 #include "ConnectionLine.h"
27 #include "Constant.h"
28 #include "Exponential.h"
29 #include "Gain.h"
30 #include "IOControl.h"
31 #include "Limiter.h"
32 #include "Multiplier.h"
33 #include "RateLimiter.h"
34 #include "Sum.h"
35 #include "TransferFunction.h"
36 
46 {
47  public:
50 
51  virtual void FillContainer(ControlEditor* editor);
52  virtual void FillContainer(std::vector<ControlElement*> controlElementList,
53  std::vector<ConnectionLine*> connectionLineList);
54  virtual void GetContainerCopy(std::vector<ControlElement*>& controlElementList,
55  std::vector<ConnectionLine*>& connectionLineList);
56  virtual void ClearContainer();
57 
58  std::vector<ControlElement*> GetControlElementsList() const { return m_ctrlElementsList; }
59  std::vector<ConnectionLine*> GetConnectionLineList() const { return m_cLineList; }
60  std::vector<Constant*> GetConstantList() const { return m_constantList; }
61  std::vector<Exponential*> GetExponentialList() const { return m_exponentialList; }
62  std::vector<Gain*> GetGainList() const { return m_gainList; }
63  std::vector<IOControl*> GetIOControlList() const { return m_ioControlList; }
64  std::vector<Limiter*> GetLimiterList() const { return m_limiterList; }
65  std::vector<Multiplier*> GetMultiplierList() const { return m_multiplierList; }
66  std::vector<RateLimiter*> GetRateLimiterList() const { return m_rateLimiterList; }
67  std::vector<Sum*> GetSumList() const { return m_sumList; }
68  std::vector<TransferFunction*> GetTFList() const { return m_tfList; }
69  protected:
70  std::vector<ControlElement*> m_ctrlElementsList;
71  std::vector<Constant*> m_constantList;
72 
73  std::vector<ConnectionLine*> m_cLineList;
74  std::vector<Exponential*> m_exponentialList;
75  std::vector<Gain*> m_gainList;
76  std::vector<IOControl*> m_ioControlList;
77  std::vector<Limiter*> m_limiterList;
78  std::vector<Multiplier*> m_multiplierList;
79  std::vector<RateLimiter*> m_rateLimiterList;
80  std::vector<Sum*> m_sumList;
81  std::vector<TransferFunction*> m_tfList;
82 };
83 
84 #endif // CONTROLELEMENTCONTAINER_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLELEMENTCONTAINER_H
19 #define CONTROLELEMENTCONTAINER_H
20 
21 #include <vector>
22 
23 class ControlEditor;
24 class ControlElement;
25 
26 #include "ConnectionLine.h"
27 #include "Constant.h"
28 #include "Exponential.h"
29 #include "Gain.h"
30 #include "IOControl.h"
31 #include "Limiter.h"
32 #include "Multiplier.h"
33 #include "RateLimiter.h"
34 #include "Sum.h"
35 #include "TransferFunction.h"
36 
46 {
47  public:
50 
51  virtual void FillContainer(ControlEditor* editor);
52  virtual void FillContainer(std::vector<ControlElement*> controlElementList,
53  std::vector<ConnectionLine*> connectionLineList);
54  virtual void GetContainerCopy(std::vector<ControlElement*>& controlElementList,
55  std::vector<ConnectionLine*>& connectionLineList);
56  virtual void ClearContainer();
57 
58  std::vector<ControlElement*> GetControlElementsList() const { return m_ctrlElementsList; }
59  std::vector<ConnectionLine*> GetConnectionLineList() const { return m_cLineList; }
60  std::vector<Constant*> GetConstantList() const { return m_constantList; }
61  std::vector<Exponential*> GetExponentialList() const { return m_exponentialList; }
62  std::vector<Gain*> GetGainList() const { return m_gainList; }
63  std::vector<IOControl*> GetIOControlList() const { return m_ioControlList; }
64  std::vector<Limiter*> GetLimiterList() const { return m_limiterList; }
65  std::vector<Multiplier*> GetMultiplierList() const { return m_multiplierList; }
66  std::vector<RateLimiter*> GetRateLimiterList() const { return m_rateLimiterList; }
67  std::vector<Sum*> GetSumList() const { return m_sumList; }
68  std::vector<TransferFunction*> GetTFList() const { return m_tfList; }
69  protected:
70  std::vector<ControlElement*> m_ctrlElementsList;
71  std::vector<Constant*> m_constantList;
72 
73  std::vector<ConnectionLine*> m_cLineList;
74  std::vector<Exponential*> m_exponentialList;
75  std::vector<Gain*> m_gainList;
76  std::vector<IOControl*> m_ioControlList;
77  std::vector<Limiter*> m_limiterList;
78  std::vector<Multiplier*> m_multiplierList;
79  std::vector<RateLimiter*> m_rateLimiterList;
80  std::vector<Sum*> m_sumList;
81  std::vector<TransferFunction*> m_tfList;
82 };
83 
84 #endif // CONTROLELEMENTCONTAINER_H
+
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
@@ -99,6 +100,7 @@ $(document).ready(function(){initNavTree('_control_element_container_8h_source.h +
diff --git a/docs/doxygen/html/_control_element_solver_8cpp_source.html b/docs/doxygen/html/_control_element_solver_8cpp_source.html index 7449d9b..a103734 100644 --- a/docs/doxygen/html/_control_element_solver_8cpp_source.html +++ b/docs/doxygen/html/_control_element_solver_8cpp_source.html @@ -88,18 +88,20 @@ $(document).ready(function(){initNavTree('_control_element_solver_8cpp_source.ht
ControlElementSolver.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlElementSolver.h"
19 
21 #include "ControlEditor.h"
22 #include "ConnectionLine.h"
23 #include "Constant.h"
24 #include "Exponential.h"
25 #include "Gain.h"
26 #include "IOControl.h"
27 #include "Limiter.h"
28 #include "Multiplier.h"
29 #include "RateLimiter.h"
30 #include "Sum.h"
31 #include "TransferFunction.h"
32 
33 ControlElementSolver::ControlElementSolver(ControlEditor* controlEditor,
34  double timeStep,
35  double integrationError,
36  bool startAllZero,
37  double input)
38 {
39  m_ctrlContainer = new ControlElementContainer();
40  m_ctrlContainer->FillContainer(controlEditor);
41  Initialize(controlEditor, timeStep, integrationError, startAllZero, input);
42 }
43 
44 ControlElementSolver::ControlElementSolver(ControlElementContainer* ctrlContainer,
45  double timeStep,
46  double integrationError,
47  bool startAllZero,
48  double input,
49  wxWindow* parent)
50 {
51  m_ctrlContainer = ctrlContainer;
52  Initialize(parent, timeStep, integrationError, startAllZero, input);
53 }
54 
55 void ControlElementSolver::Initialize(wxWindow* parent,
56  double timeStep,
57  double integrationError,
58  bool startAllZero,
59  double input)
60 {
61  // Check if the sistem have one input and one output
62  bool fail = false;
63  wxString failMessage = "";
64  auto ioList = m_ctrlContainer->GetIOControlList();
65  if(ioList.size() != 2) {
66  fail = true;
67  failMessage = _("The control system must have one input and one output.");
68  }
69  bool haveInput, haveOutput;
70  haveInput = haveOutput = false;
71  for(auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
72  IOControl* io = *it;
73  if(io->GetType() == Node::NODE_OUT) {
74  m_inputControl = io;
75  haveInput = true;
76  } else if(io->GetType() == Node::NODE_IN) {
77  m_outputControl = io;
78  haveOutput = true;
79  }
80  }
81  if(!fail && !haveInput) {
82  fail = true;
83  failMessage = _("There is no input in the control system.");
84  }
85  if(!fail && !haveOutput) {
86  fail = true;
87  failMessage = _("There is no output in the control system.");
88  }
89  if(!fail) {
90  if(m_inputControl->GetChildList().size() == 0) {
91  fail = true;
92  failMessage = _("Input not connected.");
93  }
94  }
95 
96  m_timeStep = timeStep;
97  m_integrationError = integrationError;
98  if(!fail) {
99  if(!InitializeValues(input, startAllZero)) {
100  fail = true;
101  failMessage = _("It was not possible to initialize the control system.");
102  }
103  }
104 
105  if(fail) {
106  wxMessageDialog msgDialog(parent, failMessage, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
107  msgDialog.ShowModal();
108  } else {
109  m_isOK = true;
110  }
111 }
112 
113 bool ControlElementSolver::InitializeValues(double input, bool startAllZero)
114 {
115  // Reset Elements values
116  auto elementList = m_ctrlContainer->GetControlElementsList();
117  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
118  ControlElement* element = *it;
119  element->SetSolved(false);
120  element->SetOutput(0.0);
121  }
122  auto tfList = m_ctrlContainer->GetTFList();
123  for(auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
124  TransferFunction* tf = *it;
125  tf->CalculateSpaceState(100, m_integrationError);
126  }
127  auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
128  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
129  ConnectionLine* cLine = *it;
130  cLine->SetSolved(false);
131  cLine->SetValue(0.0);
132  }
133 
134  if(!startAllZero) {
135  double origTimeStep = m_timeStep;
136  double minStep = m_timeStep / 10;
137  double maxStep = m_timeStep * 10;
138  // Calculate the steady-state results according to the input.
139  double minError = 1e-7 * m_timeStep;
140  int maxIteration = 100 / m_timeStep;
141 
142  double prevSol = 0.0;
143  double currentSol = 1.0;
144  double error = 1.0;
145  double prevError = 1.0;
146  int numIt = 0;
147  while(error > minError) {
148  prevSol = currentSol;
149  prevError = error;
150  SolveNextStep(input);
151  currentSol = GetLastSolution();
152  numIt++;
153  error = std::abs(prevSol - currentSol);
154  if(std::abs(error - prevError) < 1e-1) {
155  if(m_timeStep < maxStep) {
156  m_timeStep *= 1.5;
157  }
158  } else if(std::abs(error - prevError) > 10) {
159  if(m_timeStep > minStep) {
160  m_timeStep /= 1.5;
161  }
162  }
163  if(numIt >= maxIteration) return false;
164  }
165  m_timeStep = origTimeStep;
166  m_solutions.clear();
167  }
168 
169  return true;
170 }
171 
172 void ControlElementSolver::SolveNextStep(double input)
173 {
174  // Set all elements as not solved
175  auto elementList = m_ctrlContainer->GetControlElementsList();
176  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
177  ControlElement* element = *it;
178  element->SetSolved(false);
179  }
180  auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
181  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
182  ConnectionLine* cLine = *it;
183  cLine->SetSolved(false);
184  }
185 
186  // Get first node and set input value on connected lines
187  ConnectionLine* firstConn = static_cast<ConnectionLine*>(m_inputControl->GetChildList()[0]);
188  m_inputControl->SetSolved();
189  firstConn->SetValue(input);
190  firstConn->SetSolved();
191  FillAllConnectedChildren(firstConn);
192 
193  // Set value to the connected lines in constants
194  auto constantList = m_ctrlContainer->GetConstantList();
195  for(auto it = constantList.begin(), itEnd = constantList.end(); it != itEnd; ++it) {
196  Constant* constant = *it;
197  if(constant->GetChildList().size() == 1) {
198  constant->SetSolved();
199  ConnectionLine* child = static_cast<ConnectionLine*>(constant->GetChildList()[0]);
200  child->SetValue(constant->GetValue());
201  child->SetSolved();
202  FillAllConnectedChildren(child);
203  }
204  }
205 
206  ConnectionLine* currentLine = firstConn;
207  while(currentLine) {
208  currentLine = SolveNextElement(currentLine);
209  }
210 
211  bool haveUnsolvedElement = true;
212  while(haveUnsolvedElement) {
213  haveUnsolvedElement = false;
214  // Get the solved line connected with unsolved element (elements not connected in the main branch).
215  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
216  ConnectionLine* cLine = *it;
217  if(cLine->IsSolved()) {
218  auto parentList = cLine->GetParentList();
219  for(auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
220  ControlElement* parent = static_cast<ControlElement*>(*itP);
221  if(!parent->IsSolved()) {
222  haveUnsolvedElement = true;
223  // Solve secondary branch.
224  currentLine = cLine;
225  while(currentLine) {
226  currentLine = SolveNextElement(currentLine);
227  }
228  break;
229  }
230  }
231  }
232  if(haveUnsolvedElement) break;
233  }
234  }
235 
236  // Set the control system step output.
237  if(m_outputControl->GetChildList().size() == 1) {
238  ConnectionLine* cLine = static_cast<ConnectionLine*>(m_outputControl->GetChildList()[0]);
239  m_solutions.push_back(cLine->GetValue());
240  } else
241  m_solutions.push_back(0.0);
242 }
243 
244 void ControlElementSolver::FillAllConnectedChildren(ConnectionLine* parent)
245 {
246  auto childList = parent->GetLineChildList();
247  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
248  ConnectionLine* child = *it;
249  child->SetValue(parent->GetValue());
250  child->SetSolved();
251  FillAllConnectedChildren(child);
252  }
253 }
254 
255 ConnectionLine* ControlElementSolver::SolveNextElement(ConnectionLine* currentLine)
256 {
257  auto parentList = currentLine->GetParentList();
258  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
259  ControlElement* element = static_cast<ControlElement*>(*it);
260  // Solve the unsolved parent.
261  if(!element->IsSolved()) {
262  if(!element->Solve(currentLine->GetValue(), m_timeStep)) return NULL;
263  element->SetSolved();
264 
265  // Get the output node (must have one or will result NULL).
266  Node* outNode = NULL;
267  auto nodeList = element->GetNodeList();
268  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
269  Node* node = *itN;
270  if(node->GetNodeType() == Node::NODE_OUT) outNode = node;
271  }
272  if(!outNode) return NULL;
273 
274  // Set connection line value associated with the output node.
275  auto childList = element->GetChildList();
276  for(auto itC = childList.begin(), itCEnd = childList.end(); itC != itCEnd; ++itC) {
277  ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
278  if(!cLine->IsSolved()) { // Only check unsolved lines
279  // Check if the connection line have the output node on the list
280  auto lineNodeList = cLine->GetNodeList();
281  for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
282  Node* childNode = *itCN;
283  if(childNode == outNode) {
284  // Check if the line connect two elements, otherwise return NULL
285  if(cLine->GetType() != ConnectionLine::ELEMENT_ELEMENT) return NULL;
286 
287  // Set the connection line value and return it.
288  cLine->SetValue(element->GetOutput());
289  cLine->SetSolved();
290  FillAllConnectedChildren(cLine);
291  return cLine;
292  }
293  }
294  }
295  }
296  }
297  }
298  return NULL;
299 }
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ControlElementSolver.h"
19 
21 #include "ControlEditor.h"
22 #include "ConnectionLine.h"
23 #include "Constant.h"
24 #include "Exponential.h"
25 #include "Gain.h"
26 #include "IOControl.h"
27 #include "Limiter.h"
28 #include "Multiplier.h"
29 #include "RateLimiter.h"
30 #include "Sum.h"
31 #include "TransferFunction.h"
32 
33 ControlElementSolver::ControlElementSolver(ControlEditor* controlEditor,
34  double timeStep,
35  double integrationError,
36  bool startAllZero,
37  double input)
38 {
39  m_ctrlContainer = new ControlElementContainer();
40  m_ctrlContainer->FillContainer(controlEditor);
41  Initialize(controlEditor, timeStep, integrationError, startAllZero, input);
42 }
43 
44 ControlElementSolver::ControlElementSolver(ControlElementContainer* ctrlContainer,
45  double timeStep,
46  double integrationError,
47  bool startAllZero,
48  double input,
49  wxWindow* parent)
50 {
51  m_ctrlContainer = ctrlContainer;
52  Initialize(parent, timeStep, integrationError, startAllZero, input);
53 }
54 
55 void ControlElementSolver::Initialize(wxWindow* parent,
56  double timeStep,
57  double integrationError,
58  bool startAllZero,
59  double input)
60 {
61  // Check if the sistem have one input and one output
62  bool fail = false;
63  wxString failMessage = "";
64  auto ioList = m_ctrlContainer->GetIOControlList();
65  if(ioList.size() != 2) {
66  fail = true;
67  failMessage = _("The control system must have one input and one output.");
68  }
69  bool haveInput, haveOutput;
70  haveInput = haveOutput = false;
71  for(auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
72  IOControl* io = *it;
73  if(io->GetType() == Node::NODE_OUT) {
74  m_inputControl = io;
75  haveInput = true;
76  } else if(io->GetType() == Node::NODE_IN) {
77  m_outputControl = io;
78  haveOutput = true;
79  }
80  }
81  if(!fail && !haveInput) {
82  fail = true;
83  failMessage = _("There is no input in the control system.");
84  }
85  if(!fail && !haveOutput) {
86  fail = true;
87  failMessage = _("There is no output in the control system.");
88  }
89  if(!fail) {
90  if(m_inputControl->GetChildList().size() == 0) {
91  fail = true;
92  failMessage = _("Input not connected.");
93  }
94  }
95 
96  m_timeStep = timeStep;
97  m_integrationError = integrationError;
98  if(!fail) {
99  if(!InitializeValues(input, startAllZero)) {
100  fail = true;
101  failMessage = _("It was not possible to initialize the control system.");
102  }
103  }
104 
105  if(fail) {
106  wxMessageDialog msgDialog(parent, failMessage, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
107  msgDialog.ShowModal();
108  } else {
109  m_isOK = true;
110  }
111 }
112 
113 bool ControlElementSolver::InitializeValues(double input, bool startAllZero)
114 {
115  // Reset Elements values
116  auto elementList = m_ctrlContainer->GetControlElementsList();
117  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
118  ControlElement* element = *it;
119  element->SetSolved(false);
120  element->SetOutput(0.0);
121  }
122  auto tfList = m_ctrlContainer->GetTFList();
123  for(auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
124  TransferFunction* tf = *it;
125  tf->CalculateSpaceState(100, m_integrationError);
126  }
127  auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
128  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
129  ConnectionLine* cLine = *it;
130  cLine->SetSolved(false);
131  cLine->SetValue(0.0);
132  }
133 
134  if(!startAllZero) {
135  double origTimeStep = m_timeStep;
136  double minStep = m_timeStep / 10;
137  double maxStep = m_timeStep * 10;
138  // Calculate the steady-state results according to the input.
139  double minError = 1e-7 * m_timeStep;
140  int maxIteration = 100 / m_timeStep;
141 
142  double prevSol = 0.0;
143  double currentSol = 1.0;
144  double error = 1.0;
145  double prevError = 1.0;
146  int numIt = 0;
147  while(error > minError) {
148  prevSol = currentSol;
149  prevError = error;
150  SolveNextStep(input);
151  currentSol = GetLastSolution();
152  numIt++;
153  error = std::abs(prevSol - currentSol);
154  if(std::abs(error - prevError) < 1e-1) {
155  if(m_timeStep < maxStep) {
156  m_timeStep *= 1.5;
157  }
158  } else if(std::abs(error - prevError) > 10) {
159  if(m_timeStep > minStep) {
160  m_timeStep /= 1.5;
161  }
162  }
163  if(numIt >= maxIteration) return false;
164  }
165  m_timeStep = origTimeStep;
166  m_solutions.clear();
167  }
168 
169  return true;
170 }
171 
172 void ControlElementSolver::SolveNextStep(double input)
173 {
174  // Set all elements as not solved
175  auto elementList = m_ctrlContainer->GetControlElementsList();
176  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
177  ControlElement* element = *it;
178  element->SetSolved(false);
179  }
180  auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
181  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
182  ConnectionLine* cLine = *it;
183  cLine->SetSolved(false);
184  }
185 
186  // Get first node and set input value on connected lines
187  ConnectionLine* firstConn = static_cast<ConnectionLine*>(m_inputControl->GetChildList()[0]);
188  m_inputControl->SetSolved();
189  firstConn->SetValue(input);
190  firstConn->SetSolved();
191  FillAllConnectedChildren(firstConn);
192 
193  // Set value to the connected lines in constants
194  auto constantList = m_ctrlContainer->GetConstantList();
195  for(auto it = constantList.begin(), itEnd = constantList.end(); it != itEnd; ++it) {
196  Constant* constant = *it;
197  if(constant->GetChildList().size() == 1) {
198  constant->SetSolved();
199  ConnectionLine* child = static_cast<ConnectionLine*>(constant->GetChildList()[0]);
200  child->SetValue(constant->GetValue());
201  child->SetSolved();
202  FillAllConnectedChildren(child);
203  }
204  }
205 
206  ConnectionLine* currentLine = firstConn;
207  while(currentLine) {
208  currentLine = SolveNextElement(currentLine);
209  }
210 
211  bool haveUnsolvedElement = true;
212  while(haveUnsolvedElement) {
213  haveUnsolvedElement = false;
214  // Get the solved line connected with unsolved element (elements not connected in the main branch).
215  for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
216  ConnectionLine* cLine = *it;
217  if(cLine->IsSolved()) {
218  auto parentList = cLine->GetParentList();
219  for(auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
220  ControlElement* parent = static_cast<ControlElement*>(*itP);
221  if(!parent->IsSolved()) {
222  haveUnsolvedElement = true;
223  // Solve secondary branch.
224  currentLine = cLine;
225  while(currentLine) {
226  currentLine = SolveNextElement(currentLine);
227  }
228  break;
229  }
230  }
231  }
232  if(haveUnsolvedElement) break;
233  }
234  }
235 
236  // Set the control system step output.
237  if(m_outputControl->GetChildList().size() == 1) {
238  ConnectionLine* cLine = static_cast<ConnectionLine*>(m_outputControl->GetChildList()[0]);
239  m_solutions.push_back(cLine->GetValue());
240  } else
241  m_solutions.push_back(0.0);
242 }
243 
244 void ControlElementSolver::FillAllConnectedChildren(ConnectionLine* parent)
245 {
246  auto childList = parent->GetLineChildList();
247  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
248  ConnectionLine* child = *it;
249  child->SetValue(parent->GetValue());
250  child->SetSolved();
251  FillAllConnectedChildren(child);
252  }
253 }
254 
255 ConnectionLine* ControlElementSolver::SolveNextElement(ConnectionLine* currentLine)
256 {
257  auto parentList = currentLine->GetParentList();
258  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
259  ControlElement* element = static_cast<ControlElement*>(*it);
260  // Solve the unsolved parent.
261  if(!element->IsSolved()) {
262  if(!element->Solve(currentLine->GetValue(), m_timeStep)) return NULL;
263  element->SetSolved();
264 
265  // Get the output node (must have one or will result NULL).
266  Node* outNode = NULL;
267  auto nodeList = element->GetNodeList();
268  for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
269  Node* node = *itN;
270  if(node->GetNodeType() == Node::NODE_OUT) outNode = node;
271  }
272  if(!outNode) return NULL;
273 
274  // Set connection line value associated with the output node.
275  auto childList = element->GetChildList();
276  for(auto itC = childList.begin(), itCEnd = childList.end(); itC != itCEnd; ++itC) {
277  ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
278  if(!cLine->IsSolved()) { // Only check unsolved lines
279  // Check if the connection line have the output node on the list
280  auto lineNodeList = cLine->GetNodeList();
281  for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
282  Node* childNode = *itCN;
283  if(childNode == outNode) {
284  // Check if the line connect two elements, otherwise return NULL
285  if(cLine->GetType() != ConnectionLine::ELEMENT_ELEMENT) return NULL;
286 
287  // Set the connection line value and return it.
288  cLine->SetValue(element->GetOutput());
289  cLine->SetSolved();
290  FillAllConnectedChildren(cLine);
291  return cLine;
292  }
293  }
294  }
295  }
296  }
297  }
298  return NULL;
299 }
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
virtual std::vector< Element * > GetChildList() const
Get the Child list.
Definition: Element.h:511
Node of a control element. This class manages the user interaction with the connection and control el...
+
virtual void CalculateSpaceState(int maxIteration=100, double error=1e-3)
Convert the transfer function to space state on controllable canonical form (CCF).
Provides the communication with the power element.
Definition: IOControl.h:35
+
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
Connection between two control elements or other connection line and an element.
- +
Calculates the time response by a frequency domain transfer function.
@@ -109,6 +111,7 @@ $(document).ready(function(){initNavTree('_control_element_solver_8cpp_source.ht
A control element that provides a constant value.
Definition: Constant.h:35
+
diff --git a/docs/doxygen/html/_control_element_solver_8h_source.html b/docs/doxygen/html/_control_element_solver_8h_source.html index 5fb831f..1f88c74 100644 --- a/docs/doxygen/html/_control_element_solver_8h_source.html +++ b/docs/doxygen/html/_control_element_solver_8h_source.html @@ -90,15 +90,15 @@ $(document).ready(function(){initNavTree('_control_element_solver_8h_source.html
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef CONTROLELEMENTSOLVER_H
19 #define CONTROLELEMENTSOLVER_H
20 
21 #include <wx/window.h>
22 #include <vector>
23 
25 class ControlEditor;
26 class ConnectionLine;
27 class Constant;
28 class Exponential;
29 class Gain;
30 class IOControl;
31 class Limiter;
32 class Multiplier;
33 class RateLimiter;
34 class Sum;
35 class TransferFunction;
36 
46 {
47  public:
49  ControlElementSolver(ControlEditor* controlEditor,
50  double timeStep = 1e-3,
51  double integrationError = 1e-3,
52  bool startAllZero = true,
53  double input = 0.0);
55  double timeStep = 1e-3,
56  double integrationError = 1e-3,
57  bool startAllZero = true,
58  double input = 0.0,
59  wxWindow* parent = NULL);
60  virtual ~ControlElementSolver() {}
61  virtual bool InitializeValues(double input, bool startAllZero);
62  virtual void SolveNextStep(double input);
63  virtual std::vector<double> GetSolutions() { return m_solutions; }
64  virtual double GetLastSolution() { return m_solutions[m_solutions.size() - 1]; }
65  virtual bool IsOK() const { return m_isOK; }
66  protected:
67  void Initialize(wxWindow* parent, double timeStep, double integrationError, bool startAllZero, double input);
68  void FillAllConnectedChildren(ConnectionLine* parent);
69  ConnectionLine* SolveNextElement(ConnectionLine* currentLine);
70 
71  ControlElementContainer* m_ctrlContainer = NULL;
72  double m_timeStep;
73  double m_integrationError;
74  std::vector<double> m_solutions;
75  bool m_isOK = false;
76 
77  IOControl* m_inputControl = NULL;
78  IOControl* m_outputControl = NULL;
79 };
80 
81 #endif // CONTROLELEMENTSOLVER_H
Multiplies two inputs.
Definition: Multiplier.h:32
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
-
Definition: Sum.h:26
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
Limits the input value by superior and inferior values.
Definition: Limiter.h:32
Provides the communication with the power element.
Definition: IOControl.h:35
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
Connection between two control elements or other connection line and an element.
- +
Calculates the time response by a frequency domain transfer function.
A control element that provides a constant value.
Definition: Constant.h:35
diff --git a/docs/doxygen/html/_data_report_8cpp_source.html b/docs/doxygen/html/_data_report_8cpp_source.html index 2975535..56d6917 100644 --- a/docs/doxygen/html/_data_report_8cpp_source.html +++ b/docs/doxygen/html/_data_report_8cpp_source.html @@ -92,23 +92,23 @@ $(document).ready(function(){initNavTree('_data_report_8cpp_source.html','');});
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
-
Base class of electric calculations, with general methods.
- + +
Synchronous generator power element.
const std::vector< Bus * > GetBusList() const
Get the buses of the system (use GetElementsFromList first).
const std::vector< SyncGenerator * > GetSyncGeneratorList() const
Get the synchronous generators of the system (use GetElementsFromList first).
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
-
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
virtual void GetElementsFromList(std::vector< Element *> elementList)
Separate the power elements from a generic list.
- +
Base class of electric calculations, with general methods.
This class manages the graphical and power elements. It is responsible for handling the user&#39;s intera...
Definition: Workspace.h:81
const std::vector< Line * > GetLineList() const
Get the lines of the system (use GetElementsFromList first).
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_data_report_8h_source.html b/docs/doxygen/html/_data_report_8h_source.html index b16cf97..d3f000e 100644 --- a/docs/doxygen/html/_data_report_8h_source.html +++ b/docs/doxygen/html/_data_report_8h_source.html @@ -90,7 +90,7 @@ $(document).ready(function(){initNavTree('_data_report_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef DATAREPORT_H
19 #define DATAREPORT_H
20 
21 #include "DataReportBase.h"
22 
23 class Workspace;
25 
33 class DataReport : public DataReportBase
34 {
35  public:
36  enum GridSelection {
37  GRID_ALL = 0,
38  GRID_PF,
39  GRID_PFBUSES,
40  GRID_PFBRANCHES,
41  GRID_FAULT,
42  GRID_FAULTBUSES,
43  GRID_FAULTBRANCHES,
44  GRID_FAULTGENERATORS,
45  };
46 
47  DataReport(wxWindow* parent, Workspace* workspace);
48  virtual ~DataReport();
49 
50  virtual void SetHeaders();
51  virtual void CreateGrids();
52  virtual void FillValues(GridSelection gridToFill = GRID_ALL);
53  virtual void SetRowsColours(wxGrid* grid, int rowStart = 1);
54 
55  protected:
56  virtual void OnFaulrGridChanged(wxGridEvent& event);
57  virtual void OnFaultBranchesGridChanged(wxGridEvent& event);
58  virtual void OnFaultBusesGridChanged(wxGridEvent& event);
59  virtual void OnFaultGeneratorsGridChanged(wxGridEvent& event);
60  virtual void OnPFBranchesGridChanged(wxGridEvent& event);
61  virtual void OnPowerFlowGridChanged(wxGridEvent& event);
62  virtual void OnPFBusGridChanged(wxGridEvent& event);
63  Workspace* m_workspace = NULL;
64  bool m_changingValues = false;
65 
66  // Headers choices
67  wxArrayString m_voltageChoices;
68  wxArrayString m_activePowerChoices;
69  wxArrayString m_reactivePowerChoices;
70  wxArrayString m_resistanceChoices;
71  wxArrayString m_indReactanceChoices;
72  wxArrayString m_capSusceptanceChoices;
73  wxArrayString m_currentChoices;
74 
75  // Colors
76  wxColour m_headerColour;
77  wxColour m_offlineColour;
78  wxColour m_oddRowColour;
79  wxColour m_evenRowColour;
80 };
81 #endif // DATAREPORT_H
Form that shows the results of power flow and fault calculations.
Definition: DataReport.h:33
- +
Base class of electric calculations, with general methods.
This class manages the graphical and power elements. It is responsible for handling the user&#39;s intera...
Definition: Workspace.h:81
diff --git a/docs/doxygen/html/_electric_calculation_8cpp_source.html b/docs/doxygen/html/_electric_calculation_8cpp_source.html index 03fc2e3..3833a23 100644 --- a/docs/doxygen/html/_electric_calculation_8cpp_source.html +++ b/docs/doxygen/html/_electric_calculation_8cpp_source.html @@ -90,43 +90,43 @@ $(document).ready(function(){initNavTree('_electric_calculation_8cpp_source.html
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ElectricCalculation.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
25 void ElectricCalculation::GetElementsFromList(std::vector<Element*> elementList)
26 {
27  m_powerElementList.clear();
28  m_busList.clear();
29  m_capacitorList.clear();
30  m_indMotorList.clear();
31  m_inductorList.clear();
32  m_lineList.clear();
33  m_loadList.clear();
34  m_syncGeneratorList.clear();
35  m_syncMotorList.clear();
36  m_transformerList.clear();
37  // TODO: Bad design?
38  for(auto it = elementList.begin(); it != elementList.end(); it++) {
39  Element* element = *it;
40  m_powerElementList.push_back(static_cast<PowerElement*>(element));
41 
42  if(Bus* bus = dynamic_cast<Bus*>(element))
43  m_busList.push_back(bus);
44  else if(Capacitor* capacitor = dynamic_cast<Capacitor*>(element))
45  m_capacitorList.push_back(capacitor);
46  else if(IndMotor* indMotor = dynamic_cast<IndMotor*>(element))
47  m_indMotorList.push_back(indMotor);
48  else if(Inductor* inductor = dynamic_cast<Inductor*>(element))
49  m_inductorList.push_back(inductor);
50  else if(Line* line = dynamic_cast<Line*>(element))
51  m_lineList.push_back(line);
52  else if(Load* load = dynamic_cast<Load*>(element))
53  m_loadList.push_back(load);
54  else if(SyncGenerator* syncGenerator = dynamic_cast<SyncGenerator*>(element))
55  m_syncGeneratorList.push_back(syncGenerator);
56  else if(SyncMotor* syncMotor = dynamic_cast<SyncMotor*>(element))
57  m_syncMotorList.push_back(syncMotor);
58  else if(Transformer* transformer = dynamic_cast<Transformer*>(element))
59  m_transformerList.push_back(transformer);
60  }
61 
62  // Set buses numbers
63  int busNumber = 0;
64  for(auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
65  Bus* bus = *itb;
66  BusElectricalData data = bus->GetElectricalData();
67  data.number = busNumber;
68  bus->SetElectricalData(data);
69  busNumber++;
70  }
71 }
72 
73 bool ElectricCalculation::GetYBus(std::vector<std::vector<std::complex<double> > >& yBus,
74  double systemPowerBase,
75  YBusSequence sequence,
76  bool includeSyncMachines,
77  bool allLoadsAsImpedances)
78 {
79  if(m_busList.size() == 0) return false;
80 
81  // Clear and fill with zeros the Ybus
82  yBus.clear();
83  for(int i = 0; i < (int)m_busList.size(); i++) {
84  std::vector<std::complex<double> > line;
85  for(int j = 0; j < (int)m_busList.size(); j++) {
86  line.push_back(std::complex<double>(0.0, 0.0));
87  }
88  yBus.push_back(line);
89  }
90 
91  // Set buses numbers
92  int busNumber = 0;
93  for(auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
94  Bus* bus = *itb;
95  BusElectricalData data = bus->GetElectricalData();
96  data.number = busNumber;
97  bus->SetElectricalData(data);
98  busNumber++;
99  }
100 
101  // Load
102  for(auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) {
103  Load* load = *it;
104  if(load->IsOnline()) {
105  int n = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().number;
106  LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
107  if(data.loadType == CONST_IMPEDANCE || allLoadsAsImpedances) {
108  std::complex<double> yLoad = std::complex<double>(data.activePower, -data.reactivePower);
109  if(allLoadsAsImpedances) {
110  std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
111  yLoad /= (std::abs(v) * std::abs(v));
112  }
113  yBus[n][n] += yLoad;
114  }
115  }
116  }
117 
118  // Capacitor
119  for(auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) {
120  Capacitor* capacitor = *it;
121  if(capacitor->IsOnline()) {
122  int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
123  CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
124  yBus[n][n] += std::complex<double>(0.0, data.reactivePower);
125  }
126  }
127 
128  // Inductor
129  for(auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) {
130  Inductor* inductor = *it;
131  if(inductor->IsOnline()) {
132  int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
133  InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
134  yBus[n][n] += std::complex<double>(0.0, -data.reactivePower);
135  }
136  }
137 
138  // Power line
139  for(auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) {
140  Line* line = *it;
141  if(line->IsOnline()) {
142  LineElectricalData data = line->GetPUElectricalData(systemPowerBase);
143 
144  int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
145  int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
146 
147  switch(sequence) {
148  case POSITIVE_SEQ:
149  case NEGATIVE_SEQ: {
150  yBus[n1][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
151  yBus[n2][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
152 
153  yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
154  yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
155 
156  yBus[n1][n1] += std::complex<double>(0.0, data.capSusceptance / 2.0);
157  yBus[n2][n2] += std::complex<double>(0.0, data.capSusceptance / 2.0);
158  } break;
159  case ZERO_SEQ: {
160  yBus[n1][n2] -= 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
161  yBus[n2][n1] -= 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
162 
163  yBus[n1][n1] += 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
164  yBus[n2][n2] += 1.0 / std::complex<double>(data.zeroResistance, data.zeroIndReactance);
165 
166  yBus[n1][n1] += std::complex<double>(0.0, data.zeroCapSusceptance / 2.0);
167  yBus[n2][n2] += std::complex<double>(0.0, data.zeroCapSusceptance / 2.0);
168  }
169  }
170  }
171  }
172 
173  // Transformer
174  for(auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) {
175  Transformer* transformer = *it;
176 
177  if(transformer->IsOnline()) {
178  TransformerElectricalData data = transformer->GetPUElectricalData(systemPowerBase);
179 
180  int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
181  int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
182 
183  // If the transformer have nominal turns ratio (1.0) and no phase shifting, it will be modelled as series
184  // impedance.
185  if(data.turnsRatio == 1.0 && data.phaseShift == 0.0 && sequence != ZERO_SEQ) {
186  yBus[n1][n2] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
187  yBus[n2][n1] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
188 
189  yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
190  yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
191  }
192  // If the transformer have no-nominal turn ratio and/or phase shifting, it will be modelled in a different
193  // way (see references).
194  //[Ref. 1: Elementos de analise de sistemas de potencia - Stevenson - pg. 232]
195  //[Ref. 2: http://www.ee.washington.edu/research/real/Library/Reports/Tap_Adjustments_in_AC_Load_Flows.pdf]
196  //[Ref. 3: http://www.columbia.edu/~dano/courses/power/notes/power/andersson1.pdf]
197  else if(sequence != ZERO_SEQ) {
198  // Complex turns ratio
199  double radPhaseShift = wxDegToRad(data.phaseShift);
200  std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
201  -data.turnsRatio * std::sin(radPhaseShift));
202 
203  // Transformer admitance
204  std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance);
205 
206  if(sequence == POSITIVE_SEQ) {
207  yBus[n1][n1] += y / std::pow(std::abs(a), 2.0);
208  yBus[n1][n2] += -(y / std::conj(a));
209  yBus[n2][n1] += -(y / a);
210  yBus[n2][n2] += y;
211  } else if(sequence == NEGATIVE_SEQ) {
212  yBus[n1][n1] += y / std::pow(std::abs(a), 2.0);
213  yBus[n1][n2] += -(y / a);
214  yBus[n2][n1] += -(y / std::conj(a));
215  yBus[n2][n2] += y;
216  }
217  } else if(sequence == ZERO_SEQ) {
218  switch(data.connection) {
219  case GWYE_GWYE: {
220  std::complex<double> y =
221  1.0 /
222  std::complex<double>(
223  data.zeroResistance + 3.0 * (data.primaryGrndResistance + data.secondaryGrndResistance),
224  data.zeroIndReactance +
225  3.0 * (data.primaryGrndReactance + data.secondaryGrndReactance));
226  std::complex<double> a = std::complex<double>(data.turnsRatio, 0.0);
227 
228  yBus[n1][n1] += y / (a * a);
229  yBus[n1][n2] += -(y / a);
230  yBus[n2][n1] += -(y / a);
231  yBus[n2][n2] += y;
232  } break;
233  case DELTA_GWYE: {
234  std::complex<double> y =
235  1.0 / std::complex<double>(data.zeroResistance + 3.0 * (data.secondaryGrndResistance),
236  data.zeroIndReactance + 3.0 * (data.secondaryGrndReactance));
237  yBus[n2][n2] += y;
238  break;
239  }
240  case GWYE_DELTA: {
241  std::complex<double> y =
242  1.0 / std::complex<double>(data.zeroResistance + 3.0 * (data.primaryGrndResistance),
243  data.zeroIndReactance + 3.0 * (data.primaryGrndReactance));
244  yBus[n1][n1] += y;
245  break;
246  }
247  default:
248  break;
249  }
250  }
251  }
252  }
253 
254  if(includeSyncMachines) {
255  // Synchronous generator
256  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
257  SyncGenerator* syncGenerator = *it;
258  if(syncGenerator->IsOnline()) {
259  int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
260  SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
261  switch(sequence) {
262  case POSITIVE_SEQ: {
263  yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance);
264  } break;
265  case NEGATIVE_SEQ: {
266  yBus[n][n] += 1.0 / std::complex<double>(data.negativeResistance, data.negativeReactance);
267  } break;
268  case ZERO_SEQ: {
269  if(data.groundNeutral) {
270  yBus[n][n] += 1.0 / std::complex<double>(data.zeroResistance + 3.0 * data.groundResistance,
271  data.zeroReactance + 3.0 * data.groundReactance);
272  }
273  } break;
274  }
275  }
276  }
277  // Synchronous motor
278  for(auto it = m_syncMotorList.begin(), itEnd = m_syncMotorList.end(); it != itEnd; ++it) {
279  SyncMotor* syncMotor = *it;
280  if(syncMotor->IsOnline()) {
281  int n = static_cast<Bus*>(syncMotor->GetParentList()[0])->GetElectricalData().number;
282  SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
283  switch(sequence) {
284  case POSITIVE_SEQ: {
285  yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance);
286  } break;
287  case NEGATIVE_SEQ: {
288  yBus[n][n] += 1.0 / std::complex<double>(data.negativeResistance, data.negativeReactance);
289  } break;
290  case ZERO_SEQ: {
291  if(data.groundNeutral) {
292  yBus[n][n] += 1.0 / std::complex<double>(data.zeroResistance + 3.0 * data.groundResistance,
293  data.zeroReactance + 3.0 * data.groundReactance);
294  }
295  } break;
296  }
297  }
298  }
299  }
300 
301  return true;
302 }
303 
304 void ElectricCalculation::UpdateElementsPowerFlow(std::vector<std::complex<double> > voltage,
305  std::vector<std::complex<double> > power,
306  std::vector<BusType> busType,
307  std::vector<ReactiveLimits> reactiveLimit,
308  double systemPowerBase)
309 {
310  double zeroLimit = 1e-4;
311  for(unsigned int i = 0; i < reactiveLimit.size(); ++i) {
312  if(reactiveLimit[i].maxLimit > -zeroLimit && reactiveLimit[i].maxLimit < zeroLimit)
313  reactiveLimit[i].maxLimit = zeroLimit;
314  if(reactiveLimit[i].minLimit > -zeroLimit && reactiveLimit[i].minLimit < zeroLimit)
315  reactiveLimit[i].minLimit = zeroLimit;
316  }
317  for(unsigned int i = 0; i < power.size(); ++i) {
318  if(std::real(power[i]) > -zeroLimit && std::real(power[i]) < zeroLimit)
319  power[i] = std::complex<double>(0.0, std::imag(power[i]));
320  if(std::imag(power[i]) > -zeroLimit && std::imag(power[i]) < zeroLimit)
321  power[i] = std::complex<double>(std::real(power[i]), 0.0);
322  }
323  // Buses
324  for(int i = 0; i < (int)m_busList.size(); i++) {
325  Bus* bus = m_busList[i];
326  BusElectricalData data = bus->GetElectricalData();
327  data.voltage = voltage[i];
328  data.power = power[i];
329  data.busType = busType[i];
330  bus->SetElectricalData(data);
331  }
332 
333  // Power line
334  for(int i = 0; i < (int)m_lineList.size(); i++) {
335  Line* line = m_lineList[i];
336  if(line->IsOnline()) {
337  int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
338  int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
339 
340  LineElectricalData data = line->GetElectricalData();
341  std::complex<double> v1 = voltage[n1];
342  std::complex<double> v2 = voltage[n2];
343 
344  data.current[0] = (v1 - v2) / std::complex<double>(data.resistance, data.indReactance) +
345  v1 * std::complex<double>(0.0, data.capSusceptance / 2.0);
346  data.current[1] = (v2 - v1) / std::complex<double>(data.resistance, data.indReactance) +
347  v2 * std::complex<double>(0.0, data.capSusceptance / 2.0);
348 
349  data.powerFlow[0] = v1 * std::conj(data.current[0]);
350  data.powerFlow[1] = v2 * std::conj(data.current[1]);
351 
352  if(data.powerFlow[0].real() > data.powerFlow[1].real())
354  else
356 
357  line->SetElectricalData(data);
358  }
359  }
360 
361  // Transformer
362  for(int i = 0; i < (int)m_transformerList.size(); i++) {
363  Transformer* transformer = m_transformerList[i];
364  if(transformer->IsOnline()) {
365  TransformerElectricalData data = transformer->GetElectricalData();
366  int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
367  int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
368  std::complex<double> v1 = voltage[n1]; // Primary voltage
369  std::complex<double> v2 = voltage[n2]; // Secondary voltage
370 
371  // Transformer admitance
372  std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance);
373 
374  if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) {
375  data.current[0] = (v1 - v2) * y;
376  data.current[1] = (v2 - v1) * y;
377  } else {
378  double radPS = wxDegToRad(data.phaseShift);
379  std::complex<double> a =
380  std::complex<double>(data.turnsRatio * std::cos(radPS), -data.turnsRatio * std::sin(radPS));
381 
382  data.current[0] = v1 * (y / std::pow(std::abs(a), 2)) - v2 * (y / std::conj(a));
383  data.current[1] = -v1 * (y / a) + v2 * y;
384  }
385 
386  data.powerFlow[0] = v1 * std::conj(data.current[0]);
387  data.powerFlow[1] = v2 * std::conj(data.current[1]);
388 
389  if(data.powerFlow[0].real() > data.powerFlow[1].real())
391  else
393 
394  transformer->SetElectricaData(data);
395  }
396  }
397 
398  // Synchronous machines
399  for(int i = 0; i < (int)m_busList.size(); i++) {
400  Bus* bus = m_busList[i];
401  BusElectricalData data = bus->GetElectricalData();
402 
403  // Get the synchronous machines connected and calculate the load power on the bus.
404  std::vector<SyncGenerator*> syncGeneratorsOnBus;
405  std::vector<SyncMotor*> syncMotorsOnBus;
406  std::complex<double> loadPower(0.0, 0.0);
407 
408  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
409  SyncGenerator* syncGenerator = *itsg;
410  if(bus == syncGenerator->GetParentList()[0] && syncGenerator->IsOnline())
411  syncGeneratorsOnBus.push_back(syncGenerator);
412  }
413  for(auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
414  SyncMotor* syncMotor = *itsm;
415  if(bus == syncMotor->GetParentList()[0] && syncMotor->IsOnline()) {
416  syncMotorsOnBus.push_back(syncMotor);
417  SyncMotorElectricalData childData = syncMotor->GetPUElectricalData(systemPowerBase);
418  loadPower += std::complex<double>(childData.activePower, 0.0);
419  }
420  }
421  for(auto itlo = m_loadList.begin(); itlo != m_loadList.end(); itlo++) {
422  Load* load = *itlo;
423  if(bus == load->GetParentList()[0] && load->IsOnline()) {
424  LoadElectricalData childData = load->GetPUElectricalData(systemPowerBase);
425  if(childData.loadType == CONST_POWER)
426  loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
427 
428  if(childData.activePower >= 0.0)
430  else
432  }
433  }
434  for(auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) {
435  IndMotor* indMotor = *itim;
436  if(bus == indMotor->GetParentList()[0] && indMotor->IsOnline()) {
437  IndMotorElectricalData childData = indMotor->GetPUElectricalData(systemPowerBase);
438  loadPower += std::complex<double>(childData.activePower, childData.reactivePower);
439 
440  if(childData.activePower >= 0.0)
442  else
443  indMotor->SetPowerFlowDirection(PF_TO_BUS);
444  }
445  }
446 
447  // Set the sync generator power
448  for(auto itsg = syncGeneratorsOnBus.begin(); itsg != syncGeneratorsOnBus.end(); itsg++) {
449  SyncGenerator* generator = *itsg;
450  if(generator->IsOnline()) {
451  SyncGeneratorElectricalData childData = generator->GetElectricalData();
452 
453  if(busType[i] == BUS_SLACK) {
454  double activePower =
455  (power[i].real() + loadPower.real()) * systemPowerBase / (double)(syncGeneratorsOnBus.size());
456 
457  switch(childData.activePowerUnit) {
458  case UNIT_PU: {
459  activePower /= systemPowerBase;
460  } break;
461  case UNIT_kW: {
462  activePower /= 1e3;
463  } break;
464  case UNIT_MW: {
465  activePower /= 1e6;
466  } break;
467  default:
468  break;
469  }
470 
471  childData.activePower = activePower;
472  }
473  if(busType[i] == BUS_PV || busType[i] == BUS_SLACK) {
474  // double reactivePower = (power[i].imag() + loadPower.imag()) * systemPowerBase /
475  // (double)(syncGeneratorsOnBus.size() + syncMotorsOnBus.size());
476  SyncGeneratorElectricalData childData_PU = generator->GetPUElectricalData(systemPowerBase);
477 
478  double reactivePower = (power[i].imag() + loadPower.imag()) * systemPowerBase;
479 
480  if(reactiveLimit[i].limitReached == RL_MAX_REACHED)
481  reactivePower *= (childData_PU.maxReactive / reactiveLimit[i].maxLimit);
482 
483  else if(reactiveLimit[i].limitReached == RL_MIN_REACHED)
484  reactivePower *= (childData_PU.minReactive / reactiveLimit[i].minLimit);
485 
486  else
487  reactivePower /= (double)(syncGeneratorsOnBus.size() + syncMotorsOnBus.size());
488 
489  switch(childData.reactivePowerUnit) {
490  case UNIT_PU: {
491  reactivePower /= systemPowerBase;
492  } break;
493  case UNIT_kVAr: {
494  reactivePower /= 1e3;
495  } break;
496  case UNIT_MVAr: {
497  reactivePower /= 1e6;
498  } break;
499  default:
500  break;
501  }
502  childData.reactivePower = reactivePower;
503  }
504 
505  if(childData.activePower >= 0.0)
506  generator->SetPowerFlowDirection(PF_TO_BUS);
507  else
509 
510  generator->SetElectricalData(childData);
511  }
512  }
513 
514  // Set the sync motor reactive power
515  double exceededReactive = 0.0;
516  int numMachines = syncGeneratorsOnBus.size() + syncMotorsOnBus.size();
517  for(auto itsm = syncMotorsOnBus.begin(); itsm != syncMotorsOnBus.end(); itsm++) {
518  SyncMotor* syncMotor = *itsm;
519  SyncMotorElectricalData childData = syncMotor->GetElectricalData();
520 
521  bool reachedMachineLimit = false;
522 
523  if(busType[i] == BUS_PV || busType[i] == BUS_SLACK) {
524  // double reactivePower = (power[i].imag() + loadPower.imag()) * systemPowerBase /
525  // (double)(syncGeneratorsOnBus.size() + syncMotorsOnBus.size());
526 
527  SyncMotorElectricalData childData_PU = syncMotor->GetPUElectricalData(systemPowerBase);
528 
529  double reactivePower = power[i].imag() + loadPower.imag();
530 
531  // Bus reachd maximum reactive limit.
532  if(reactiveLimit[i].limitReached == RL_MAX_REACHED)
533  reactivePower *= (childData_PU.maxReactive / reactiveLimit[i].maxLimit);
534  // Bus reached minimum reactive limit.
535  else if(reactiveLimit[i].limitReached == RL_MIN_REACHED)
536  reactivePower *= (childData_PU.minReactive / reactiveLimit[i].minLimit);
537  // Bus didn't reach any limits
538  else {
539  reactivePower /= (double)(numMachines);
540  if(childData_PU.haveMaxReactive && (reactivePower > childData_PU.maxReactive)) {
541  exceededReactive += reactivePower - childData_PU.maxReactive;
542  reactivePower = childData_PU.maxReactive;
543  reachedMachineLimit = true;
544  } else if(childData_PU.haveMinReactive && (reactivePower < childData_PU.minReactive)) {
545  exceededReactive += reactivePower - childData_PU.minReactive;
546  reactivePower = childData_PU.minReactive;
547  reachedMachineLimit = true;
548  } else if((!childData_PU.haveMaxReactive && reactiveLimit[i].limitReached == RL_MAX_REACHED) ||
549  (!childData_PU.haveMinReactive && reactiveLimit[i].limitReached == RL_MIN_REACHED) ||
550  (!childData_PU.haveMaxReactive && !childData_PU.haveMaxReactive)) {
551  reactivePower += exceededReactive;
552  exceededReactive = 0.0;
553  }
554  }
555 
556  reactivePower *= systemPowerBase;
557 
558  switch(childData.reactivePowerUnit) {
559  case UNIT_PU: {
560  reactivePower /= systemPowerBase;
561  } break;
562  case UNIT_kVAr: {
563  reactivePower /= 1e3;
564  } break;
565  case UNIT_MVAr: {
566  reactivePower /= 1e6;
567  } break;
568  default:
569  break;
570  }
571  childData.reactivePower = reactivePower;
572  }
573 
574  if(childData.activePower > 0.0)
576  else
577  syncMotor->SetPowerFlowDirection(PF_TO_BUS);
578 
579  syncMotor->SetElectricalData(childData);
580 
581  if(reachedMachineLimit) {
582  syncMotorsOnBus.erase(itsm);
583  itsm = syncMotorsOnBus.begin();
584  }
585  }
586  }
587 }
588 
589 bool ElectricCalculation::InvertMatrix(std::vector<std::vector<std::complex<double> > > matrix,
590  std::vector<std::vector<std::complex<double> > >& inverse)
591 {
592  int order = static_cast<int>(matrix.size());
593 
594  inverse.clear();
595  // Fill the inverse matrix with identity.
596  for(int i = 0; i < order; ++i) {
597  std::vector<std::complex<double> > line;
598  for(int j = 0; j < order; ++j) {
599  line.push_back(i == j ? std::complex<double>(1.0, 0.0) : std::complex<double>(0.0, 0.0));
600  }
601  inverse.push_back(line);
602  }
603 
604  // Check if a main diagonal value of the matrix is zero, if one is zero, try a linear combination to remove it.
605  for(int i = 0; i < order; ++i) {
606  for(int j = 0; j < order; ++j) {
607  if(i == j && matrix[i][j] == std::complex<double>(0.0, 0.0)) {
608  int row = 0;
609  while(row < order) {
610  if(matrix[row][j] != std::complex<double>(0.0, 0.0)) {
611  for(int k = 0; k < order; ++k) {
612  matrix[i][k] += matrix[row][k];
613  inverse[i][k] += inverse[row][k];
614  }
615  break;
616  }
617  row++;
618  }
619  // If all line values are zero, the matrix is singular and the solution is impossible.
620  if(row == order) return false;
621  }
622  }
623  }
624 
625  // Linear combinations are made in both matrices, the goal is the input matrix become the identity. The final result
626  // have two matrices: the identity and the inverse of the input.
627  for(int i = 0; i < order; ++i) {
628  for(int j = 0; j < order; ++j) {
629  if(i != j) {
630  if(matrix[i][i] == std::complex<double>(0.0, 0.0)) return false;
631 
632  std::complex<double> factor = matrix[j][i] / matrix[i][i];
633  for(int k = 0; k < order; ++k) {
634  matrix[j][k] -= factor * matrix[i][k];
635  inverse[j][k] -= factor * inverse[i][k];
636  }
637  }
638  }
639  }
640  // Main diagonal calculation.
641  for(int i = 0; i < order; ++i) {
642  for(int j = 0; j < order; ++j) {
643  if(i == j) {
644  if(matrix[i][j] == std::complex<double>(0.0, 0.0)) return false;
645 
646  std::complex<double> factor = (matrix[i][j] - std::complex<double>(1.0, 0.0)) / matrix[i][j];
647  for(int k = 0; k < order; ++k) {
648  matrix[j][k] -= factor * matrix[i][k];
649  inverse[j][k] -= factor * inverse[i][k];
650  }
651  }
652  }
653  }
654 
655  return true;
656 }
657 
658 void ElectricCalculation::ABCtoDQ0(std::complex<double> complexValue, double angle, double& dValue, double& qValue)
659 {
660  dValue = -std::real(complexValue) * std::sin(angle) + std::imag(complexValue) * std::cos(angle);
661  qValue = std::real(complexValue) * std::cos(angle) + std::imag(complexValue) * std::sin(angle);
662 }
663 
664 void ElectricCalculation::DQ0toABC(double dValue, double qValue, double angle, std::complex<double>& complexValue)
665 {
666  double real = qValue * std::cos(angle) - dValue * std::sin(angle);
667  double imag = qValue * std::sin(angle) + dValue * std::cos(angle);
668  complexValue = std::complex<double>(real, imag);
669 }
670 
671 std::vector<std::complex<double> > ElectricCalculation::GaussianElimination(
672  std::vector<std::vector<std::complex<double> > > matrix,
673  std::vector<std::complex<double> > array)
674 {
675  //[Ref] http://pt.wikipedia.org/wiki/Elimina%C3%A7%C3%A3o_de_Gauss
676 
677  std::vector<std::complex<double> > solution;
678 
679  std::vector<std::vector<std::complex<double> > > triangMatrix;
680  triangMatrix.resize(matrix.size());
681  for(unsigned int i = 0; i < matrix.size(); i++) {
682  triangMatrix[i].resize(matrix.size());
683  }
684 
685  for(unsigned int i = 0; i < matrix.size(); i++) {
686  solution.push_back(array[i]);
687  }
688 
689  for(unsigned int i = 0; i < matrix.size(); i++) {
690  for(unsigned int j = 0; j < matrix.size(); j++) {
691  triangMatrix[i][j] = matrix[i][j];
692  }
693  }
694 
695  for(unsigned int k = 0; k < matrix.size(); k++) {
696  unsigned int k1 = k + 1;
697  for(unsigned int i = k; i < matrix.size(); i++) {
698  if(triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
699  for(unsigned int j = k1; j < matrix.size(); j++) {
700  triangMatrix[i][j] = triangMatrix[i][j] / triangMatrix[i][k];
701  }
702  solution[i] = solution[i] / triangMatrix[i][k];
703  }
704  }
705  for(unsigned int i = k1; i < matrix.size(); i++) {
706  if(triangMatrix[i][k] != std::complex<double>(0.0, 0.0)) {
707  for(unsigned int j = k1; j < matrix.size(); j++) {
708  triangMatrix[i][j] -= triangMatrix[k][j];
709  }
710  solution[i] -= solution[k];
711  }
712  }
713  }
714  for(unsigned int i = matrix.size() - 2; i >= 0; i--) {
715  for(unsigned int j = matrix.size() - 1; j >= i + 1; j--) {
716  solution[i] -= triangMatrix[i][j] * solution[j];
717  }
718  }
719 
720  return solution;
721 }
722 
723 Machines::SyncMachineModel ElectricCalculation::GetMachineModel(SyncGenerator* generator)
724 {
725  auto data = generator->GetElectricalData();
726  if(data.transTd0 != 0.0) {
727  if(data.transTq0 != 0.0) {
728  if(data.subTd0 != 0.0 || data.subTq0 != 0.0) {
729  return Machines::SM_MODEL_5;
730  }
731  return Machines::SM_MODEL_3;
732  } else {
733  if(data.subTd0 != 0.0 || data.subTq0 != 0.0) {
734  return Machines::SM_MODEL_4;
735  }
736  return Machines::SM_MODEL_2;
737  }
738  }
739 
740  return Machines::SM_MODEL_1;
741 }
742 
743 std::vector<std::complex<double> > ElectricCalculation::ComplexMatrixTimesVector(
744  std::vector<std::vector<std::complex<double> > > matrix,
745  std::vector<std::complex<double> > vector)
746 {
747  std::vector<std::complex<double> > solution;
748  for(unsigned int i = 0; i < matrix.size(); i++) {
749  solution.push_back(std::complex<double>(0.0, 0.0));
750 
751  for(unsigned int j = 0; j < matrix.size(); j++) {
752  solution[i] += matrix[i][j] * vector[j];
753  }
754  }
755 
756  return solution;
757 }
758 
759 void ElectricCalculation::GetLUDecomposition(std::vector<std::vector<std::complex<double> > > matrix,
760  std::vector<std::vector<std::complex<double> > >& matrixL,
761  std::vector<std::vector<std::complex<double> > >& matrixU)
762 {
763  // Doolittle method
764  // [Ref] http://www3.nd.edu/~zxu2/acms40390F11/Alg-LU-Crout.pdf
765  // [Ref] http://www.engr.colostate.edu/~thompson/hPage/CourseMat/Tutorials/CompMethods/doolittle.pdf
766 
767  int size = static_cast<int>(matrix.size()); // Decomposed matrix size.
768 
769  // Set upper and lower matrices sizes.
770  matrixL.resize(size);
771  matrixU.resize(size);
772  for(int i = 0; i < size; i++) {
773  matrixL[i].resize(size);
774  matrixU[i].resize(size);
775  }
776 
777  // First row of upper matrix and first column of lower matrix.
778  for(int i = 0; i < size; i++) {
779  matrixU[0][i] = matrix[0][i];
780  matrixL[i][0] = matrix[i][0] / matrixU[0][0];
781  }
782 
783  // Lower matrix main diagonal.
784  for(int i = 1; i < size; i++) {
785  matrixL[i][i] = std::complex<double>(1.0, 0.0);
786  }
787 
788  for(int i = 1; i < size - 1; i++) {
789  // Upper matrix main diagonal.
790  matrixU[i][i] = matrix[i][i];
791  for(int k = 0; k < i; k++) {
792  matrixU[i][i] -= matrixL[i][k] * matrixU[k][i];
793  }
794 
795  // Others elements of upper matrix
796  for(int j = i + 1; j < size; j++) {
797  matrixU[i][j] = matrix[i][j];
798  for(int k = 0; k < i; k++) {
799  matrixU[i][j] -= matrixL[i][k] * matrixU[k][j];
800  }
801  }
802 
803  // Lower matrix elements
804  for(int j = i + 1; j < size; j++) {
805  matrixL[j][i] = matrix[j][i];
806  for(int k = 0; k < i; k++) {
807  matrixL[j][i] -= matrixL[j][k] * matrixU[k][i];
808  }
809  matrixL[j][i] = matrixL[j][i] / matrixU[i][i];
810  }
811  }
812 
813  // Last element of upper matrix.
814  matrixU[size - 1][size - 1] = matrix[size - 1][size - 1];
815  for(int k = 0; k < size - 1; k++) {
816  matrixU[size - 1][size - 1] -= matrixL[size - 1][k] * matrixU[k][size - 1];
817  }
818 }
819 
820 std::vector<std::complex<double> > ElectricCalculation::LUEvaluate(std::vector<std::vector<std::complex<double> > > u,
821  std::vector<std::vector<std::complex<double> > > l,
822  std::vector<std::complex<double> > b)
823 {
824  int size = static_cast<int>(b.size());
825  std::vector<std::complex<double> > x;
826  std::vector<std::complex<double> > y;
827  x.resize(size);
828  y.resize(size);
829 
830  // Forward
831  for(int i = 0; i < size; i++) {
832  y[i] = b[i];
833  for(int j = 0; j < i; j++) {
834  y[i] -= l[i][j] * y[j];
835  }
836  y[i] /= l[i][i];
837  }
838  // Backward
839  for(int i = size - 1; i >= 0; i--) {
840  x[i] = y[i];
841  for(int j = i + 1; j < size; j++) {
842  x[i] -= u[i][j] * x[j];
843  }
844  x[i] /= u[i][i];
845  }
846  return x;
847 }
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition: PowerElement.h:187
-
Base class of electric calculations, with general methods.
+ - +
Synchronous generator power element.
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
~ElectricCalculation()
Destructor.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition: Machines.cpp:267
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
virtual bool InvertMatrix(std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::vector< std::complex< double > > > &inverse)
Invert a matrix.
-
Definition: Line.h:52
-
Definition: Load.h:35
+
Power line element.
Definition: Line.h:59
+
Loas shunt power element.
Definition: Load.h:42
virtual bool GetYBus(std::vector< std::vector< std::complex< double > > > &yBus, double systemPowerBase, YBusSequence sequence=POSITIVE_SEQ, bool includeSyncMachines=false, bool allLoadsAsImpedances=false)
Get the admittance matrix from the list of elements (use GetElementsFromList first).
virtual void UpdateElementsPowerFlow(std::vector< std::complex< double > > voltage, std::vector< std::complex< double > > power, std::vector< BusType > busType, std::vector< ReactiveLimits > reactiveLimit, double systemPowerBase)
Update the elements after the power flow calculation.
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
ElectricCalculation()
Constructor.
- - +
Induction motor power element.
Definition: IndMotor.h:40
+
Shunt capactior power element.
Definition: Capacitor.h:38
- +
Inductor shunt power element.
Definition: Inductor.h:38
virtual void GetElementsFromList(std::vector< Element *> elementList)
Separate the power elements from a generic list.
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
Definition: Line.cpp:449
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_electric_calculation_8h.html b/docs/doxygen/html/_electric_calculation_8h.html index 900a8c0..dd36dcb 100644 --- a/docs/doxygen/html/_electric_calculation_8h.html +++ b/docs/doxygen/html/_electric_calculation_8h.html @@ -91,23 +91,20 @@ $(document).ready(function(){initNavTree('_electric_calculation_8h.html','');});
ElectricCalculation.h File Reference
- -

Base class of electric calculations, with general methods. -More...

#include <vector>
#include <complex>
#include "Element.h"
#include "PowerElement.h"
-#include "Bus.h"
-#include "Capacitor.h"
-#include "IndMotor.h"
-#include "Inductor.h"
-#include "Line.h"
-#include "Load.h"
-#include "SyncGenerator.h"
-#include "SyncMotor.h"
-#include "Transformer.h"
-#include "PropertiesData.h"
+#include "Bus.h"
+#include "Capacitor.h"
+#include "IndMotor.h"
+#include "Inductor.h"
+#include "Line.h"
+#include "Load.h"
+#include "SyncGenerator.h"
+#include "SyncMotor.h"
+#include "Transformer.h"
+#include "PropertiesData.h"

Go to the source code of this file.

@@ -116,6 +113,7 @@ Classes +
struct  ReactiveLimits
 
class  ElectricCalculation
 Base class of electric calculations, with general methods. More...
 
}

@@ -142,11 +140,7 @@ Enumerations

 
-

Detailed Description

-

Base class of electric calculations, with general methods.

- -

Definition in file ElectricCalculation.h.

-
+
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELECTRICCALCULATION_H
19 #define ELECTRICCALCULATION_H
20 
21 #include <vector>
22 #include <complex>
23 
24 #include "Element.h"
25 #include "PowerElement.h"
26 #include "Bus.h"
27 #include "Capacitor.h"
28 #include "IndMotor.h"
29 #include "Inductor.h"
30 #include "Line.h"
31 #include "Load.h"
32 #include "SyncGenerator.h"
33 #include "SyncMotor.h"
34 #include "Transformer.h"
35 
36 #include "PropertiesData.h"
37 
38 enum BusType { BUS_SLACK = 0, BUS_PV, BUS_PQ };
39 
40 enum ReactiveLimitsType {
41  RL_UNLIMITED = 0, // The bus can generate any ammount of reactive power.
42  RL_LIMITED, // The bus reactive power generation is limited.
43  RL_UNLIMITED_SOURCE, // The bus have at least one source of infinite reative power.
44  RL_MAX_REACHED, // Max limit reached
45  RL_MIN_REACHED, // Min limit reached
46  RL_NONE_REACHED // No limits reached
47 };
48 
49 enum YBusSequence { POSITIVE_SEQ = 0, NEGATIVE_SEQ, ZERO_SEQ };
50 
52  double maxLimit = 0.0;
53  double minLimit = 0.0;
54  ReactiveLimitsType maxLimitType = RL_UNLIMITED;
55  ReactiveLimitsType minLimitType = RL_UNLIMITED;
56  ReactiveLimitsType limitReached = RL_NONE_REACHED;
57 };
58 
67 {
68  public:
73 
78 
83  virtual void GetElementsFromList(std::vector<Element*> elementList);
84 
93  virtual bool GetYBus(std::vector<std::vector<std::complex<double> > >& yBus,
94  double systemPowerBase,
95  YBusSequence sequence = POSITIVE_SEQ,
96  bool includeSyncMachines = false,
97  bool allLoadsAsImpedances = false);
98 
105  virtual bool InvertMatrix(std::vector<std::vector<std::complex<double> > > matrix,
106  std::vector<std::vector<std::complex<double> > >& inverse);
107 
116  virtual void UpdateElementsPowerFlow(std::vector<std::complex<double> > voltage,
117  std::vector<std::complex<double> > power,
118  std::vector<BusType> busType,
119  std::vector<ReactiveLimits> reactiveLimit,
120  double systemPowerBase);
121 
122  void ABCtoDQ0(std::complex<double> complexValue, double angle, double& dValue, double& qValue);
123  void DQ0toABC(double dValue, double qValue, double angle, std::complex<double>& complexValue);
124 
125  std::vector<std::complex<double> > GaussianElimination(std::vector<std::vector<std::complex<double> > > matrix,
126  std::vector<std::complex<double> > array);
127 
128  Machines::SyncMachineModel GetMachineModel(SyncGenerator* generator);
129 
130  std::vector<std::complex<double> > ComplexMatrixTimesVector(std::vector<std::vector<std::complex<double> > > matrix,
131  std::vector<std::complex<double> > vector);
132 
133  void GetLUDecomposition(std::vector<std::vector<std::complex<double> > > matrix,
134  std::vector<std::vector<std::complex<double> > >& matrixL,
135  std::vector<std::vector<std::complex<double> > >& matrixU);
136 
137  std::vector<std::complex<double> > LUEvaluate(std::vector<std::vector<std::complex<double> > > u,
138  std::vector<std::vector<std::complex<double> > > l,
139  std::vector<std::complex<double> > b);
140 
145  const std::vector<Bus*> GetBusList() const { return m_busList; }
150  const std::vector<Capacitor*> GetCapacitorList() const { return m_capacitorList; }
155  const std::vector<IndMotor*> GetIndMotorList() const { return m_indMotorList; }
160  const std::vector<Inductor*> GetInductorList() const { return m_inductorList; }
165  const std::vector<Line*> GetLineList() const { return m_lineList; }
170  const std::vector<Load*> GetLoadList() const { return m_loadList; }
175  const std::vector<SyncGenerator*> GetSyncGeneratorList() const { return m_syncGeneratorList; }
180  const std::vector<SyncMotor*> GetSyncMotorList() const { return m_syncMotorList; }
185  const std::vector<Transformer*> GetTransformerList() const { return m_transformerList; }
186  protected:
187  std::vector<PowerElement*> m_powerElementList;
188  std::vector<Bus*> m_busList;
189  std::vector<Capacitor*> m_capacitorList;
190  std::vector<IndMotor*> m_indMotorList;
191  std::vector<Inductor*> m_inductorList;
192  std::vector<Line*> m_lineList;
193  std::vector<Load*> m_loadList;
194  std::vector<SyncGenerator*> m_syncGeneratorList;
195  std::vector<SyncMotor*> m_syncMotorList;
196  std::vector<Transformer*> m_transformerList;
197 };
198 
199 #endif // ELECTRICCALCULATION_H
const std::vector< Transformer * > GetTransformerList() const
Get the transformers of the system (use GetElementsFromList first).
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELECTRICCALCULATION_H
19 #define ELECTRICCALCULATION_H
20 
21 #include <vector>
22 #include <complex>
23 
24 #include "Element.h"
25 #include "PowerElement.h"
26 #include "Bus.h"
27 #include "Capacitor.h"
28 #include "IndMotor.h"
29 #include "Inductor.h"
30 #include "Line.h"
31 #include "Load.h"
32 #include "SyncGenerator.h"
33 #include "SyncMotor.h"
34 #include "Transformer.h"
35 
36 #include "PropertiesData.h"
37 
38 enum BusType { BUS_SLACK = 0, BUS_PV, BUS_PQ };
39 
40 enum ReactiveLimitsType {
41  RL_UNLIMITED = 0, // The bus can generate any ammount of reactive power.
42  RL_LIMITED, // The bus reactive power generation is limited.
43  RL_UNLIMITED_SOURCE, // The bus have at least one source of infinite reative power.
44  RL_MAX_REACHED, // Max limit reached
45  RL_MIN_REACHED, // Min limit reached
46  RL_NONE_REACHED // No limits reached
47 };
48 
49 enum YBusSequence { POSITIVE_SEQ = 0, NEGATIVE_SEQ, ZERO_SEQ };
50 
52  double maxLimit = 0.0;
53  double minLimit = 0.0;
54  ReactiveLimitsType maxLimitType = RL_UNLIMITED;
55  ReactiveLimitsType minLimitType = RL_UNLIMITED;
56  ReactiveLimitsType limitReached = RL_NONE_REACHED;
57 };
58 
67 {
68  public:
73 
78 
83  virtual void GetElementsFromList(std::vector<Element*> elementList);
84 
93  virtual bool GetYBus(std::vector<std::vector<std::complex<double> > >& yBus,
94  double systemPowerBase,
95  YBusSequence sequence = POSITIVE_SEQ,
96  bool includeSyncMachines = false,
97  bool allLoadsAsImpedances = false);
98 
105  virtual bool InvertMatrix(std::vector<std::vector<std::complex<double> > > matrix,
106  std::vector<std::vector<std::complex<double> > >& inverse);
107 
116  virtual void UpdateElementsPowerFlow(std::vector<std::complex<double> > voltage,
117  std::vector<std::complex<double> > power,
118  std::vector<BusType> busType,
119  std::vector<ReactiveLimits> reactiveLimit,
120  double systemPowerBase);
121 
122  void ABCtoDQ0(std::complex<double> complexValue, double angle, double& dValue, double& qValue);
123  void DQ0toABC(double dValue, double qValue, double angle, std::complex<double>& complexValue);
124 
125  std::vector<std::complex<double> > GaussianElimination(std::vector<std::vector<std::complex<double> > > matrix,
126  std::vector<std::complex<double> > array);
127 
128  Machines::SyncMachineModel GetMachineModel(SyncGenerator* generator);
129 
130  std::vector<std::complex<double> > ComplexMatrixTimesVector(std::vector<std::vector<std::complex<double> > > matrix,
131  std::vector<std::complex<double> > vector);
132 
133  void GetLUDecomposition(std::vector<std::vector<std::complex<double> > > matrix,
134  std::vector<std::vector<std::complex<double> > >& matrixL,
135  std::vector<std::vector<std::complex<double> > >& matrixU);
136 
137  std::vector<std::complex<double> > LUEvaluate(std::vector<std::vector<std::complex<double> > > u,
138  std::vector<std::vector<std::complex<double> > > l,
139  std::vector<std::complex<double> > b);
140 
145  const std::vector<Bus*> GetBusList() const { return m_busList; }
150  const std::vector<Capacitor*> GetCapacitorList() const { return m_capacitorList; }
155  const std::vector<IndMotor*> GetIndMotorList() const { return m_indMotorList; }
160  const std::vector<Inductor*> GetInductorList() const { return m_inductorList; }
165  const std::vector<Line*> GetLineList() const { return m_lineList; }
170  const std::vector<Load*> GetLoadList() const { return m_loadList; }
175  const std::vector<SyncGenerator*> GetSyncGeneratorList() const { return m_syncGeneratorList; }
180  const std::vector<SyncMotor*> GetSyncMotorList() const { return m_syncMotorList; }
185  const std::vector<Transformer*> GetTransformerList() const { return m_transformerList; }
186  protected:
187  std::vector<PowerElement*> m_powerElementList;
188  std::vector<Bus*> m_busList;
189  std::vector<Capacitor*> m_capacitorList;
190  std::vector<IndMotor*> m_indMotorList;
191  std::vector<Inductor*> m_inductorList;
192  std::vector<Line*> m_lineList;
193  std::vector<Load*> m_loadList;
194  std::vector<SyncGenerator*> m_syncGeneratorList;
195  std::vector<SyncMotor*> m_syncMotorList;
196  std::vector<Transformer*> m_transformerList;
197 };
198 
199 #endif // ELECTRICCALCULATION_H
const std::vector< Transformer * > GetTransformerList() const
Get the transformers of the system (use GetElementsFromList first).
+ +
const std::vector< IndMotor * > GetIndMotorList() const
Get the induction motors of the system (use GetElementsFromList first).
+ - +
Synchronous generator power element.
const std::vector< Bus * > GetBusList() const
Get the buses of the system (use GetElementsFromList first).
const std::vector< SyncGenerator * > GetSyncGeneratorList() const
Get the synchronous generators of the system (use GetElementsFromList first).
+
const std::vector< Inductor * > GetInductorList() const
Get the inductors of the system (use GetElementsFromList first).
-
Class to manage color of OpenGL.
+ + + +
const std::vector< Capacitor * > GetCapacitorList() const
Get the capacitors of the system (use GetElementsFromList first).
+
const std::vector< Load * > GetLoadList() const
Get the loads of the system (use GetElementsFromList first).
-
Switching data of power elements.
+ +
const std::vector< SyncMotor * > GetSyncMotorList() const
Get the synchronous motors of the system (use GetElementsFromList first).
- +
Base class of electric calculations, with general methods.
+
const std::vector< Line * > GetLineList() const
Get the lines of the system (use GetElementsFromList first).
diff --git a/docs/doxygen/html/_electromechanical_8cpp_source.html b/docs/doxygen/html/_electromechanical_8cpp_source.html index ad6d4e0..951a8d7 100644 --- a/docs/doxygen/html/_electromechanical_8cpp_source.html +++ b/docs/doxygen/html/_electromechanical_8cpp_source.html @@ -91,31 +91,31 @@ $(document).ready(function(){initNavTree('_electromechanical_8cpp_source.html','
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Electromechanical.h"
19 #include "ControlElementSolver.h"
20 
21 Electromechanical::Electromechanical(wxWindow* parent, std::vector<Element*> elementList, SimulationData data)
22 {
23  m_parent = parent;
24  GetElementsFromList(elementList);
25  SetEventTimeList();
26 
27  Bus dummyBus;
28  m_powerSystemBase = dummyBus.GetValueFromUnit(data.basePower, data.basePowerUnit);
29  m_systemFreq = data.stabilityFrequency;
30  m_simTime = data.stabilitySimulationTime;
31  m_timeStep = data.timeStep;
32  m_tolerance = data.stabilityTolerance;
33  m_maxIterations = data.stabilityMaxIterations;
34 
35  m_ctrlTimeStepMultiplier = 1.0 / static_cast<double>(data.controlTimeStepRatio);
36 
37  m_plotTime = data.plotTime;
38  m_useCOI = data.useCOI;
39 }
40 
41 Electromechanical::~Electromechanical() {}
42 bool Electromechanical::RunStabilityCalculation()
43 {
44  wxProgressDialog pbd(_("Running simulation"), _("Initializing..."), 100, m_parent,
45  wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_SMOOTH);
46 
47  SetSyncMachinesModel();
48 
49  // Calculate the admittance matrix with the synchronous machines.
50  if(!GetYBus(m_yBus, m_powerSystemBase, POSITIVE_SEQ, false, true)) {
51  m_errorMsg = _("It was not possible to build the admittance matrix.");
52  return false;
53  }
54  InsertSyncMachinesOnYBus();
55  GetLUDecomposition(m_yBus, m_yBusL, m_yBusU);
56 
57  // Get buses voltages.
58  m_vBus.clear();
59  m_vBus.resize(m_busList.size());
60  for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
61  Bus* bus = *it;
62  auto data = bus->GetElectricalData();
63  m_vBus[data.number] = data.voltage;
64  }
65 
66  // Calculate injected currents
67  m_iBus = ComplexMatrixTimesVector(m_yBus, m_vBus);
68  for(unsigned int i = 0; i < m_iBus.size(); ++i) {
69  if(std::abs(m_iBus[i]) < 1e-5) m_iBus[i] = std::complex<double>(0.0, 0.0);
70  }
71 
72  if(!InitializeDynamicElements()) return false;
73 
74  double pbdTime = m_plotTime;
75  double currentTime = 0.0;
76  double currentPlotTime = 0.0;
77  double currentPbdTime = 0.0;
78  while(currentTime < m_simTime) {
79  if(HasEvent(currentTime)) {
80  SetEvent(currentTime);
81  GetLUDecomposition(m_yBus, m_yBusL, m_yBusU);
82  }
83 
84  if(currentPlotTime >= m_plotTime || currentTime == 0.0) {
85  m_timeVector.push_back(currentTime);
86  SaveData();
87  currentPlotTime = 0.0;
88  }
89 
90  if(currentPbdTime > pbdTime) {
91  if(!pbd.Update((currentTime / m_simTime) * 100, wxString::Format("Time = %.2fs", currentTime))) {
92  m_errorMsg = wxString::Format(_("Simulation cancelled at %.2fs."), currentTime);
93  pbd.Update(100);
94  return false;
95  }
96  currentPbdTime = 0.0;
97  }
98 
99  if(!SolveSynchronousMachines()) return false;
100 
101  currentTime += m_timeStep;
102  currentPlotTime += m_timeStep;
103  currentPbdTime += m_timeStep;
104  }
105  return true;
106 }
107 
108 void Electromechanical::SetEventTimeList()
109 {
110  // Fault
111  for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
112  Bus* bus = *it;
113  auto data = bus->GetElectricalData();
114  if(data.stabHasFault) {
115  m_eventTimeList.push_back(data.stabFaultTime);
116  m_eventOccurrenceList.push_back(false);
117  m_eventTimeList.push_back(data.stabFaultTime + data.stabFaultLength);
118  m_eventOccurrenceList.push_back(false);
119  }
120  }
121  // Switching
122  for(auto it = m_powerElementList.begin(), itEnd = m_powerElementList.end(); it != itEnd; ++it) {
123  PowerElement* element = *it;
124  SwitchingData swData = element->GetSwitchingData();
125  for(unsigned int i = 0; i < swData.swTime.size(); ++i) {
126  m_eventTimeList.push_back(swData.swTime[i]);
127  m_eventOccurrenceList.push_back(false);
128  }
129  }
130 }
131 
132 bool Electromechanical::HasEvent(double currentTime)
133 {
134  for(unsigned int i = 0; i < m_eventTimeList.size(); ++i) {
135  if(!m_eventOccurrenceList[i]) {
136  if(EventTrigger(m_eventTimeList[i], currentTime)) {
137  m_eventOccurrenceList[i] = true;
138  return true;
139  }
140  }
141  }
142  return false;
143 }
144 
145 void Electromechanical::SetEvent(double currentTime)
146 {
147  // Fault
148  for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
149  Bus* bus = *it;
150  auto data = bus->GetElectricalData();
151  if(data.stabHasFault) {
152  int n = data.number;
153 
154  // Insert fault
155  if(EventTrigger(data.stabFaultTime, currentTime)) {
156  double r, x;
157  r = data.stabFaultResistance;
158  x = data.stabFaultReactance;
159  if(x < 1e-5) x = 1e-5;
160  m_yBus[n][n] += std::complex<double>(1.0, 0.0) / std::complex<double>(r, x);
161  }
162 
163  // Remove fault
164  else if(EventTrigger(data.stabFaultTime + data.stabFaultLength, currentTime)) {
165  double r, x;
166  r = data.stabFaultResistance;
167  x = data.stabFaultReactance;
168  if(x < 1e-5) x = 1e-5;
169  m_yBus[n][n] -= std::complex<double>(1.0, 0.0) / std::complex<double>(r, x);
170  }
171  }
172  }
173 
174  // SyncGenerator switching
175  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
176  SyncGenerator* generator = *it;
177  auto swData = generator->GetSwitchingData();
178  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
179  if(EventTrigger(swData.swTime[i], currentTime)) {
180  // Remove machine (only connected machines)
181  if(swData.swType[i] == SW_REMOVE && generator->IsOnline()) {
182  generator->SetOnline(false);
183  int n = static_cast<Bus*>(generator->GetParentList()[0])->GetElectricalData().number;
184  m_yBus[n][n] -= GetSyncMachineAdmittance(generator);
185  }
186 
187  // Insert machine (only disconnected machines)
188  if(swData.swType[i] == SW_INSERT && !generator->IsOnline() && generator->GetParentList().size() == 1) {
189  if(generator->SetOnline(true)) {
190  int n = static_cast<Bus*>(generator->GetParentList()[0])->GetElectricalData().number;
191  m_yBus[n][n] += GetSyncMachineAdmittance(generator);
192  }
193  }
194  }
195  }
196  }
197 
198  // Load switching
199  for(auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) {
200  Load* load = *it;
201  auto swData = load->GetSwitchingData();
202  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
203  if(EventTrigger(swData.swTime[i], currentTime)) {
204  // Remove load (only connected loads)
205  if(swData.swType[i] == SW_REMOVE && load->IsOnline()) {
206  load->SetOnline(false);
207  auto data = load->GetPUElectricalData(m_powerSystemBase);
208  Bus* parentBus = static_cast<Bus*>(load->GetParentList()[0]);
209  int n = parentBus->GetElectricalData().number;
210  std::complex<double> v = parentBus->GetElectricalData().voltage;
211  m_yBus[n][n] -= std::complex<double>(data.activePower, -data.reactivePower) / (v * v);
212  }
213 
214  // Insert load (only disconnected load)
215  if(swData.swType[i] == SW_INSERT && !load->IsOnline() && load->GetParentList().size() == 1) {
216  if(load->SetOnline(true)) {
217  auto data = load->GetPUElectricalData(m_powerSystemBase);
218  Bus* parentBus = static_cast<Bus*>(load->GetParentList()[0]);
219  int n = parentBus->GetElectricalData().number;
220  std::complex<double> v = parentBus->GetElectricalData().voltage;
221  m_yBus[n][n] += std::complex<double>(data.activePower, -data.reactivePower) / (v * v);
222  }
223  }
224  }
225  }
226  }
227 
228  // Line switching
229  for(auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) {
230  Line* line = *it;
231  auto swData = line->GetSwitchingData();
232  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
233  if(EventTrigger(swData.swTime[i], currentTime)) {
234  // Remove line (only connected lines)
235  if(swData.swType[i] == SW_REMOVE && line->IsOnline()) {
236  line->SetOnline(false);
237  auto data = line->GetElectricalData();
238 
239  int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
240  int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
241 
242  m_yBus[n1][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
243  m_yBus[n2][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
244 
245  m_yBus[n1][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
246  m_yBus[n2][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
247 
248  m_yBus[n1][n1] -= std::complex<double>(0.0, data.capSusceptance / 2.0);
249  m_yBus[n2][n2] -= std::complex<double>(0.0, data.capSusceptance / 2.0);
250  }
251 
252  // Insert line (only disconnected lines)
253  if(swData.swType[i] == SW_INSERT && !line->IsOnline() && line->GetParentList().size() == 2) {
254  if(line->SetOnline(true)) {
255  auto data = line->GetElectricalData();
256 
257  int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
258  int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
259 
260  m_yBus[n1][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
261  m_yBus[n2][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
262 
263  m_yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
264  m_yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
265 
266  m_yBus[n1][n1] += std::complex<double>(0.0, data.capSusceptance / 2.0);
267  m_yBus[n2][n2] += std::complex<double>(0.0, data.capSusceptance / 2.0);
268  }
269  }
270  }
271  }
272  }
273 
274  // Transformer switching
275  for(auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) {
276  Transformer* transformer = *it;
277  auto swData = transformer->GetSwitchingData();
278  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
279  if(EventTrigger(swData.swTime[i], currentTime)) {
280  // Remove transformer (only connected transformers)
281  if(swData.swType[i] == SW_REMOVE && transformer->IsOnline()) {
282  transformer->SetOnline(false);
283  auto data = transformer->GetElectricalData();
284 
285  int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
286  int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
287 
288  if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) {
289  m_yBus[n1][n2] -= -1.0 / std::complex<double>(data.resistance, data.indReactance);
290  m_yBus[n2][n1] -= -1.0 / std::complex<double>(data.resistance, data.indReactance);
291 
292  m_yBus[n1][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
293  m_yBus[n2][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance);
294  } else {
295  // Complex turns ratio
296  double radPhaseShift = wxDegToRad(data.phaseShift);
297  std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
298  -data.turnsRatio * std::sin(radPhaseShift));
299 
300  // Transformer admitance
301  std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance);
302  m_yBus[n1][n1] -= y / std::pow(std::abs(a), 2.0);
303  m_yBus[n1][n2] -= -(y / std::conj(a));
304  m_yBus[n2][n1] -= -(y / a);
305  m_yBus[n2][n2] -= y;
306  }
307  }
308 
309  // Insert transformer (only disconnected transformers)
310  if(swData.swType[i] == SW_INSERT && !transformer->IsOnline() &&
311  transformer->GetParentList().size() == 2) {
312  if(transformer->SetOnline(true)) {
313  auto data = transformer->GetElectricalData();
314 
315  int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
316  int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
317 
318  if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) {
319  m_yBus[n1][n2] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
320  m_yBus[n2][n1] += -1.0 / std::complex<double>(data.resistance, data.indReactance);
321 
322  m_yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
323  m_yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance);
324  } else {
325  // Complex turns ratio
326  double radPhaseShift = wxDegToRad(data.phaseShift);
327  std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
328  -data.turnsRatio * std::sin(radPhaseShift));
329 
330  // Transformer admitance
331  std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance);
332  m_yBus[n1][n1] += y / std::pow(std::abs(a), 2.0);
333  m_yBus[n1][n2] += -(y / std::conj(a));
334  m_yBus[n2][n1] += -(y / a);
335  m_yBus[n2][n2] += y;
336  }
337  }
338  }
339  }
340  }
341  }
342 
343  // Capacitor switching
344  for(auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) {
345  Capacitor* capacitor = *it;
346  auto swData = capacitor->GetSwitchingData();
347  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
348  if(EventTrigger(swData.swTime[i], currentTime)) {
349  // Remove capacitor (only connected capacitors)
350  if(swData.swType[i] == SW_REMOVE && capacitor->IsOnline()) {
351  capacitor->SetOnline(false);
352  auto data = capacitor->GetPUElectricalData(m_powerSystemBase);
353  int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
354  m_yBus[n][n] -= std::complex<double>(0.0, data.reactivePower);
355  }
356 
357  // Insert capacitor (only disconnected capacitors)
358  if(swData.swType[i] == SW_INSERT && !capacitor->IsOnline() && capacitor->GetParentList().size() == 1) {
359  if(capacitor->SetOnline(true)) {
360  auto data = capacitor->GetPUElectricalData(m_powerSystemBase);
361  int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
362  m_yBus[n][n] += std::complex<double>(0.0, data.reactivePower);
363  }
364  }
365  }
366  }
367  }
368 
369  // Inductor switching
370  for(auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) {
371  Inductor* inductor = *it;
372  auto swData = inductor->GetSwitchingData();
373  for(unsigned int i = 0; i < swData.swType.size(); ++i) {
374  if(EventTrigger(swData.swTime[i], currentTime)) {
375  // Remove inductor (only connected inductors)
376  if(swData.swType[i] == SW_REMOVE && inductor->IsOnline()) {
377  inductor->SetOnline(false);
378  auto data = inductor->GetPUElectricalData(m_powerSystemBase);
379  int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
380  m_yBus[n][n] -= std::complex<double>(0.0, -data.reactivePower);
381  }
382 
383  // Insert inductor (only disconnected inductors)
384  if(swData.swType[i] == SW_INSERT && !inductor->IsOnline() && inductor->GetParentList().size() == 1) {
385  if(inductor->SetOnline(true)) {
386  auto data = inductor->GetPUElectricalData(m_powerSystemBase);
387  int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
388  m_yBus[n][n] += std::complex<double>(0.0, -data.reactivePower);
389  }
390  }
391  }
392  }
393  }
394 }
395 
396 void Electromechanical::InsertSyncMachinesOnYBus()
397 {
398  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
399  SyncGenerator* generator = *it;
400  if(generator->IsOnline()) {
401  auto data = generator->GetElectricalData();
402  int n = static_cast<Bus*>(generator->GetParentList()[0])->GetElectricalData().number;
403  m_yBus[n][n] += GetSyncMachineAdmittance(generator);
404  }
405  }
406 }
407 
408 bool Electromechanical::EventTrigger(double eventTime, double currentTime)
409 {
410  return (((eventTime - m_timeStep) < currentTime) && (eventTime >= currentTime));
411 }
412 
413 std::complex<double> Electromechanical::GetSyncMachineAdmittance(SyncGenerator* generator)
414 {
415  auto data = generator->GetElectricalData();
416  double k = 1.0; // Power base change factor.
417  if(data.useMachineBase) {
418  double oldBase = generator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
419  k = m_powerSystemBase / oldBase;
420  }
421 
422  double ra = data.armResistance * k;
423  auto smModelData = GetSyncMachineModelData(generator);
424  double xd = smModelData.xd;
425  double xq = smModelData.xq;
426  double xdq = 0.5 * (xd + xq);
427  return (std::complex<double>(ra, -xdq) / std::complex<double>(ra * ra + xd * xq, 0.0));
428 }
429 
430 bool Electromechanical::InitializeDynamicElements()
431 {
432  // Buses
433  for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
434  Bus* bus = *it;
435  auto data = bus->GetElectricalData();
436  data.stabVoltageVector.clear();
437  bus->SetElectricalData(data);
438  }
439  // Synchronous generators
440  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
441  SyncGenerator* syncGenerator = *it;
442  auto dataPU = syncGenerator->GetPUElectricalData(m_powerSystemBase);
443  auto data = syncGenerator->GetElectricalData();
444  if(syncGenerator->IsOnline()) {
445  double k = 1.0; // Power base change factor.
446  if(data.useMachineBase) {
447  double oldBase = syncGenerator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
448  k = m_powerSystemBase / oldBase;
449  }
450  data.terminalVoltage = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().voltage;
451 
452  std::complex<double> conjS(dataPU.activePower, -dataPU.reactivePower);
453  std::complex<double> vt = data.terminalVoltage;
454  std::complex<double> ia = conjS / std::conj(vt);
455 
456  double xd = data.syncXd * k;
457  double xq = data.syncXq * k;
458  double ra = data.armResistance * k;
459 
460  if(data.model == Machines::SM_MODEL_1) {
461  xq = data.transXd * k;
462  xd = xq;
463  } else if(data.syncXq == 0.0)
464  xq = data.syncXd * k;
465 
466  double sd = 1.0;
467  double sq = 1.0;
468  double satF = 1.0;
469  double xp = data.potierReactance * k;
470  bool hasSaturation = false;
471  if(data.satFactor != 0.0) { // Have saturation.
472  satF = (data.satFactor - 1.2) / std::pow(1.2, 7);
473  if(xp == 0.0) xp = 0.8 * (data.transXd * k);
474  hasSaturation = true;
475  }
476 
477  // Initialize state variables
478  std::complex<double> eq0 = vt + std::complex<double>(ra, xq) * ia;
479  double delta = std::arg(eq0);
480 
481  double id0, iq0, vd0, vq0;
482  ABCtoDQ0(ia, delta, id0, iq0);
483  ABCtoDQ0(vt, delta, vd0, vq0);
484 
485  // Initialize saturation
486  double xqs = xq;
487  double xds = xd;
488  if(hasSaturation) {
489  double oldDelta = 0;
490  bool exit = false;
491  int numIt = 0;
492  while(!exit) {
493  oldDelta = delta;
494  ABCtoDQ0(ia, delta, id0, iq0);
495  ABCtoDQ0(vt, delta, vd0, vq0);
496 
497  // Direct-axis Potier voltage.
498  double epd = vd0 + ra * id0 + xp * iq0;
499 
500  sq = 1.0 + satF * (xq / xd) * std::pow(epd, 6);
501  xqs = (xq - xp) / sq + xp;
502  eq0 = data.terminalVoltage + std::complex<double>(ra, xqs) * ia;
503  delta = std::arg(eq0);
504  if(std::abs(delta - oldDelta) < m_saturationTolerance) {
505  exit = true;
506  } else if(numIt >= m_maxIterations) {
507  m_errorMsg = _("Error on initializate the saturation values of \"") + data.name + _("\".");
508  return false;
509  }
510  numIt++;
511  }
512  // Quadrature-axis Potier voltage.
513  double epq = vq0 + ra * iq0 - xp * id0;
514  sd = 1.0 + satF * std::pow(epq, 6);
515  xds = (xd - xp) / sd + xp;
516  /*CalculateSyncMachineSaturation(syncGenerator, id0, iq0, sq, sd, true, k);
517  xqs = (xq - xp) / sq + xp;
518  xds = (xd - xp) / sd + xp;
519  eq0 = data.terminalVoltage + std::complex<double>(ra, xqs) * ia;
520  delta = std::arg(eq0);*/
521  }
522 
523  double ef0 = vq0 + ra * iq0 - xds * id0;
524 
525  data.initialFieldVoltage = ef0 * sd;
526  data.fieldVoltage = data.initialFieldVoltage;
527  data.pm = std::real((data.terminalVoltage * std::conj(ia)) + (std::abs(ia) * std::abs(ia) * ra));
528  data.speed = 2.0 * M_PI * m_systemFreq;
529  data.delta = delta;
530  data.pe = data.pm;
531  data.electricalPower = std::complex<double>(dataPU.activePower, dataPU.reactivePower);
532  data.sd = sd;
533  data.sq = sq;
534  data.id = id0;
535  data.iq = iq0;
536 
537  // Variables to extrapolate.
538  data.oldIq = iq0;
539  data.oldId = id0;
540  data.oldPe = data.pe;
541  data.oldSd = sd;
542  data.oldSq = sq;
543 
544  m_sdC = sd;
545  m_sqC = sq;
546 
547  switch(data.model) {
548  case Machines::SM_MODEL_1: {
549  // double tranXd = data.transXd * k;
550 
551  // data.tranEq = data.initialFieldVoltage + (xd - tranXd) * id0;
552  data.tranEq = std::abs(eq0);
553 
554  data.tranEd = 0.0;
555  data.subEq = 0.0;
556  data.subEd = 0.0;
557  } break;
558  case Machines::SM_MODEL_2: {
559  double tranXd = data.transXd * k;
560 
561  data.tranEq = ef0 + (xd - tranXd) * (id0 / sd);
562  data.tranEd = 0.0;
563  data.subEd = 0.0;
564  data.subEq = 0.0;
565  } break;
566  case Machines::SM_MODEL_3: {
567  double tranXd = data.transXd * k;
568  double tranXq = data.transXq * k;
569  if(tranXq == 0.0) tranXq = tranXd;
570 
571  data.tranEq = ef0 + (xd - tranXd) * (id0 / sd);
572  data.tranEd = -(xq - tranXq) * (iq0 / sq);
573 
574  data.subEd = 0.0;
575  data.subEq = 0.0;
576  } break;
577  case Machines::SM_MODEL_4: {
578  double tranXd = data.transXd * k;
579  double subXd = data.subXd * k;
580  double subXq = data.subXq * k;
581  if(subXd == 0.0) subXd = subXq;
582  if(subXq == 0.0) subXq = subXd;
583 
584  data.tranEq = ef0 + (xd - tranXd) * (id0 / sd);
585  data.tranEd = 0.0;
586  data.subEq = data.tranEq + (tranXd - subXd) * (id0 / sd);
587  data.subEd = -(xq - subXq) * (iq0 / sq);
588  } break;
589  case Machines::SM_MODEL_5: {
590  double tranXd = data.transXd * k;
591  double tranXq = data.transXq * k;
592  double subXd = data.subXd * k;
593  double subXq = data.subXq * k;
594  if(subXd == 0.0) subXd = subXq;
595  if(subXq == 0.0) subXq = subXd;
596 
597  data.tranEq = ef0 + (xd - tranXd) * (id0 / sd);
598  data.tranEd = -(xq - tranXq) * (iq0 / sq);
599  data.subEq = data.tranEq + (tranXd - subXd) * (id0 / sd);
600  data.subEd = data.tranEd - (tranXq - subXq) * (iq0 / sq);
601  } break;
602  default:
603  break;
604  }
605 
606  // Initialize controllers
607  if(data.useAVR) {
608  if(data.avrSolver) delete data.avrSolver;
609  data.avrSolver = new ControlElementSolver(data.avr, m_timeStep * m_ctrlTimeStepMultiplier, m_tolerance,
610  false, std::abs(data.terminalVoltage), m_parent);
611  if(!data.avrSolver->IsOK()) {
612  m_errorMsg = _("Error on initializate the AVR of \"") + data.name + _("\".");
613  syncGenerator->SetElectricalData(data);
614  return false;
615  }
616  }
617  if(data.useSpeedGovernor) {
618  if(data.speedGovSolver) delete data.speedGovSolver;
619  data.speedGovSolver = new ControlElementSolver(data.speedGov, m_timeStep * m_ctrlTimeStepMultiplier,
620  m_tolerance, false, data.speed, m_parent);
621  if(!data.speedGovSolver->IsOK()) {
622  m_errorMsg = _("Error on initializate the speed governor of \"") + data.name + _("\".");
623  syncGenerator->SetElectricalData(data);
624  return false;
625  }
626  }
627  } else {
628  // Initialize open circuit machine.
629  }
630  // Reset plot data
631  data.terminalVoltageVector.clear();
632  data.electricalPowerVector.clear();
633  data.mechanicalPowerVector.clear();
634  data.freqVector.clear();
635  data.fieldVoltageVector.clear();
636  data.deltaVector.clear();
637 
638  syncGenerator->SetElectricalData(data);
639  }
640  CalculateReferenceSpeed();
641  return true;
642 }
643 
644 bool Electromechanical::CalculateMachinesCurrents()
645 {
646  // Reset injected currents vector
647  for(unsigned int i = 0; i < m_iBus.size(); ++i) m_iBus[i] = std::complex<double>(0.0, 0.0);
648 
649  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
650  SyncGenerator* syncGenerator = *it;
651  auto data = syncGenerator->GetElectricalData();
652  if(syncGenerator->IsOnline()) {
653  double k = 1.0; // Power base change factor.
654  if(data.useMachineBase) {
655  double oldBase = syncGenerator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
656  k = m_powerSystemBase / oldBase;
657  }
658 
659  double ra = data.armResistance * k;
660  double xp = data.potierReactance * k;
661  if(xp == 0.0) xp = 0.8 * data.transXd * k;
662 
663  int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
664  std::complex<double> e = std::complex<double>(0.0, 0.0);
665  std::complex<double> v = m_vBus[n];
666  std::complex<double> iInj = m_iBus[n];
667 
668  auto smModelData = GetSyncMachineModelData(syncGenerator);
669  DQ0toABC(smModelData.ed, smModelData.eq, data.delta, e);
670  double xd = smModelData.xd;
671  double xq = smModelData.xq;
672 
673  double sd = data.sd;
674  double sq = data.sq;
675  double id, iq;
676 
677  // Calculate the saturation effect
678  if(data.satFactor != 0.0) {
679  if(!CalculateSyncMachineSaturation(syncGenerator, id, iq, sd, sq, false, k)) return false;
680  }
681 
682  double xdq, xds, xqs, xdqs;
683  xdq = 0.5 * (xd + xq);
684  xds = (xd - xp) / sd + xp;
685  xqs = (xq - xp) / sq + xp;
686  xdqs = 0.5 * (xds + xqs);
687 
688  std::complex<double> y0 = std::complex<double>(ra, -xdq) / std::complex<double>(ra * ra + xd * xq, 0.0);
689  // std::complex<double> iUnadjusted = y0 * e;
690  std::complex<double> iUnadjusted = y0 * v;
691 
692  // [Ref] Arrillaga, J.; Arnold, C. P.. "Computer Modelling of Electrical Power Systems". Pg. 225-226
693  // [Ref] Dommell, H. W.; Sato, N.. "Fast transient stability solutions". IEEE Transactions on Power
694  // Apparatus and Systems, PAS-91 (4), 1643-1650
695  std::complex<double> iSaliency = std::complex<double>(0.0, -((0.5 * (xqs - xds)) / (ra * ra + xds * xqs))) *
696  (std::conj(e) - std::conj(v));
697  iSaliency = iSaliency * std::cos(2.0 * data.delta) +
698  iSaliency * std::complex<double>(0.0, std::sin(2.0 * data.delta));
699 
700  // [Ref] Arrillaga, J.; Arnold, C. P.; Computer Modelling of Electrical Power Systems. Pg. 258-259
701  std::complex<double> y0s = std::complex<double>(ra, -xdqs) / std::complex<double>(ra * ra + xds * xqs, 0.0);
702  std::complex<double> iSaturation = y0s * (e - v);
703 
704  iInj = iUnadjusted + iSaliency + iSaturation;
705 
706  m_iBus[n] += iInj;
707 
708  // Remove the current flowing through y0 (i.e. iUnadjusted in this case, y0 is inserted in admittance
709  // matrix) to calculate the electrical power.
710  std::complex<double> iMachine = iInj - iUnadjusted;
711  data.electricalPower = v * std::conj(iMachine);
712 
713  ABCtoDQ0(iMachine, data.delta, id, iq);
714 
715  data.id = id;
716  data.iq = iq;
717  data.sd = sd;
718  data.sq = sq;
719  } else {
720  data.electricalPower = std::complex<double>(0.0, 0.0);
721  }
722 
723  syncGenerator->SetElectricalData(data);
724  }
725  return true;
726 }
727 
728 void Electromechanical::CalculateIntegrationConstants(SyncGenerator* syncGenerator, double id, double iq, double k)
729 {
730  CalculateReferenceSpeed();
731  auto data = syncGenerator->GetElectricalData();
732 
733  double syncXd, syncXq, transXd, transXq, subXd, subXq;
734  syncXd = data.syncXd * k;
735  syncXq = data.syncXq * k;
736  transXd = data.transXd * k;
737  transXq = data.transXq * k;
738  subXd = data.subXd * k;
739  subXq = data.subXq * k;
740 
741  if(syncXq == 0.0) syncXq = syncXd;
742  if(transXq == 0.0) transXq = transXd;
743  if(subXd == 0.0) subXd = subXq;
744  if(subXq == 0.0) subXq = subXd;
745 
746  double transTd0, transTq0, subTd0, subTq0;
747  transTd0 = data.transTd0;
748  transTq0 = data.transTq0;
749  subTd0 = data.subTd0;
750  subTq0 = data.subTq0;
751 
752  if(subTd0 == 0.0) subTd0 = subTq0;
753  if(subTq0 == 0.0) subTq0 = subTd0;
754 
755  // Speed
756  data.icSpeed.m = m_timeStep / ((4.0f * data.inertia / m_refSpeed) / k + m_timeStep * data.damping * k);
757  data.icSpeed.c = (1.0f - 2.0f * data.icSpeed.m * data.damping * k) * data.speed +
758  data.icSpeed.m * (data.pm - data.pe + 2.0f * m_refSpeed * data.damping * k);
759 
760  // Delta
761  data.icDelta.m = 0.5f * m_timeStep;
762  data.icDelta.c = data.delta + data.icDelta.m * (data.speed - 2.0f * m_refSpeed);
763 
764  // Eq'
765  if(data.model == Machines::SM_MODEL_2 || data.model == Machines::SM_MODEL_3 || data.model == Machines::SM_MODEL_4 ||
766  data.model == Machines::SM_MODEL_5) {
767  data.icTranEq.m = m_timeStep / (2.0f * transTd0 + m_timeStep);
768  // data.icTranEq.c = (1.0f - 2.0 * data.icTranEq.m) * data.tranEq +
769  // data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id);
770  data.icTranEq.c = (1.0 - data.icTranEq.m * (1.0 + data.sd)) * data.tranEq +
771  data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id);
772  }
773 
774  // Ed'
775  if(data.model == Machines::SM_MODEL_3 || data.model == Machines::SM_MODEL_4 || data.model == Machines::SM_MODEL_5) {
776  data.icTranEd.m = m_timeStep / (2.0f * transTq0 + m_timeStep);
777  // data.icTranEd.c = (1.0f - 2.0f * data.icTranEd.m) * data.tranEd - data.icTranEd.m * (syncXq - transXq) * iq;
778  data.icTranEd.c =
779  (1.0 - data.icTranEd.m * (1.0 + data.sq)) * data.tranEd - data.icTranEd.m * (syncXq - transXq) * iq;
780  }
781 
782  // Eq''
783  if(data.model == Machines::SM_MODEL_4 || data.model == Machines::SM_MODEL_5) {
784  data.icSubEq.m = m_timeStep / (2.0f * subTd0 + m_timeStep);
785  // data.icSubEq.c =
786  // (1.0f - 2.0f * data.icSubEq.m) * data.subEq + data.icSubEq.m * (data.tranEq + (transXd - subXd) * id);
787  data.icSubEq.c = (1.0 - data.icSubEq.m * (1.0 + data.sd)) * data.subEq +
788  data.icSubEq.m * (data.sd * data.tranEq + (transXd - subXd) * id);
789  }
790  // Ed''
791  if(data.model == Machines::SM_MODEL_4) {
792  data.icSubEd.m = m_timeStep / (2.0f * subTq0 + m_timeStep);
793  // data.icSubEd.c = (1.0f - 2.0f * data.icSubEd.m) * data.subEd - data.icSubEd.m * (syncXq - subXq) * iq;
794  data.icSubEd.c =
795  (1.0f - data.icSubEd.m * (1.0 + data.sq)) * data.subEd - data.icSubEd.m * (syncXq - subXq) * iq;
796  }
797  if(data.model == Machines::SM_MODEL_5) {
798  data.icSubEd.m = m_timeStep / (2.0f * subTq0 + m_timeStep);
799  // data.icSubEd.c =
800  // (1.0f - 2.0f * data.icSubEd.m) * data.subEd + data.icSubEd.m * (data.tranEd - (transXq - subXq) * iq);
801  data.icSubEd.c = (1.0f - data.icSubEd.m * (1.0 + data.sq)) * data.subEd +
802  data.icSubEd.m * (data.sq * data.tranEd - (transXq - subXq) * iq);
803  }
804 
805  syncGenerator->SetElectricalData(data);
806 }
807 
808 bool Electromechanical::SolveSynchronousMachines()
809 {
810  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
811  SyncGenerator* syncGenerator = *it;
812  auto data = syncGenerator->GetElectricalData();
813 
814  if(syncGenerator->IsOnline()) {
815  double id, iq, pe, sd, sq;
816  pe = data.pe;
817  id = data.id;
818  iq = data.iq;
819  sd = data.sd;
820  sq = data.sq;
821 
822  double k = 1.0; // Power base change factor.
823  if(data.useMachineBase) {
824  double oldBase = syncGenerator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
825  k = m_powerSystemBase / oldBase;
826  }
827 
828  // Calculate integration constants.
829  CalculateIntegrationConstants(syncGenerator, id, iq, k);
830 
831  if(!CalculateSyncMachineNonIntVariables(syncGenerator, id, iq, sd, sq, pe, k)) return false;
832  // Extrapolate nonintegrable variables.
833  id = 2.0 * id - data.oldId;
834  iq = 2.0 * iq - data.oldIq;
835  pe = 2.0 * pe - data.oldPe;
836  sd = 2.0 * sd - data.oldSd;
837  sq = 2.0 * sq - data.oldSq;
838 
839  m_sdC = sd;
840  m_sqC = sq;
841 
842  CalculateSyncMachineIntVariables(syncGenerator, id, iq, sd, sq, pe, k);
843  } else {
844  CalculateIntegrationConstants(syncGenerator, 0.0f, 0.0f);
845  }
846  }
847 
848  m_wError = 0;
849 
850  double error = 1.0;
851  int iterations = 0;
852  while(error > m_tolerance) {
853  error = 0.0;
854 
855  // Calculate the injected currents.
856  if(!CalculateMachinesCurrents()) return false;
857 
858  // Calculate the buses voltages.
859  m_vBus = LUEvaluate(m_yBusU, m_yBusL, m_iBus);
860 
861  // Solve machine equations.
862  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
863  SyncGenerator* syncGenerator = *it;
864 
865  auto data = syncGenerator->GetElectricalData();
866 
867  double id = data.id;
868  double iq = data.iq;
869  double pe = data.pe;
870  double sd = data.sd;
871  double sq = data.sq;
872 
873  // Power base change factor.
874  double k = 1.0;
875  if(data.useMachineBase) {
876  double oldBase = syncGenerator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
877  k = m_powerSystemBase / oldBase;
878  }
879 
880  // Calculate id, iq, dq, sd
881  if(!CalculateSyncMachineNonIntVariables(syncGenerator, id, iq, sd, sq, pe, k)) return false;
882 
883  double genError = CalculateSyncMachineIntVariables(syncGenerator, id, iq, sd, sq, pe, k);
884 
885  if(genError > error) error = genError;
886  }
887 
888  ++iterations;
889 
890  if(iterations > m_maxIterations) {
891  m_errorMsg = _("Impossible to solve the synchronous generators.\nCheck the system parameters and/or "
892  "decrease the time step.");
893  return false;
894  }
895  }
896  m_numIt = iterations;
897 
898  // Solve controllers.
899  int ctrlRatio = static_cast<int>(1 / m_ctrlTimeStepMultiplier);
900  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
901  SyncGenerator* syncGenerator = *it;
902  auto data = syncGenerator->GetElectricalData();
903  if(data.useAVR && data.avrSolver) {
904  for(int i = 0; i < ctrlRatio; ++i) data.avrSolver->SolveNextStep(std::abs(data.terminalVoltage));
905  data.fieldVoltage = data.initialFieldVoltage + data.avrSolver->GetLastSolution();
906  }
907 
908  if(data.useSpeedGovernor && data.speedGovSolver) {
909  for(int i = 0; i < ctrlRatio; ++i) data.speedGovSolver->SolveNextStep(data.speed);
910  data.pm = data.speedGovSolver->GetLastSolution();
911  }
912  syncGenerator->SetElectricalData(data);
913  }
914 
915  return true;
916 }
917 
918 void Electromechanical::SaveData()
919 {
920  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
921  SyncGenerator* syncGenerator = *it;
922  auto data = syncGenerator->GetElectricalData();
923  if(data.plotSyncMachine) {
924  data.terminalVoltageVector.push_back(data.terminalVoltage);
925  data.electricalPowerVector.push_back(data.electricalPower);
926  data.mechanicalPowerVector.push_back(data.pm);
927  data.freqVector.push_back(data.speed / (2.0f * M_PI));
928  data.fieldVoltageVector.push_back(data.fieldVoltage);
929  data.deltaVector.push_back(wxRadToDeg(data.delta));
930  syncGenerator->SetElectricalData(data);
931  }
932  }
933  for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
934  Bus* bus = *it;
935  auto data = bus->GetElectricalData();
936  if(data.plotBus) {
937  data.stabVoltageVector.push_back(m_vBus[data.number]);
938  bus->SetElectricalData(data);
939  }
940  }
941 
942  m_wErrorVector.push_back(m_wError);
943  m_numItVector.push_back(m_numIt);
944  m_sdCVector.push_back(m_sdC);
945  m_sqCVector.push_back(m_sqC);
946 }
947 
948 void Electromechanical::SetSyncMachinesModel()
949 {
950  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
951  SyncGenerator* syncGenerator = *it;
952  auto data = syncGenerator->GetElectricalData();
953  data.model = GetMachineModel(syncGenerator);
954  syncGenerator->SetElectricalData(data);
955  }
956 }
957 
958 bool Electromechanical::CalculateSyncMachineNonIntVariables(SyncGenerator* syncGenerator,
959  double& id,
960  double& iq,
961  double& sd,
962  double& sq,
963  double& pe,
964  double k)
965 {
966  auto data = syncGenerator->GetElectricalData();
967  int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
968 
969  if(syncGenerator->IsOnline()) {
970  data.terminalVoltage = m_vBus[n];
971  }
972 
973  double vd, vq;
974  ABCtoDQ0(data.terminalVoltage, data.delta, vd, vq);
975 
976  if(data.satFactor != 0.0) {
977  if(!CalculateSyncMachineSaturation(syncGenerator, id, iq, sd, sq, true, k)) return false;
978  data.sd = sd;
979  data.sq = sq;
980  data.oldSd = sd;
981  data.oldSq = sq;
982  }
983 
984  if(syncGenerator->IsOnline()) {
985  pe = id * vd + iq * vq + (id * id + iq * iq) * data.armResistance * k;
986  } else {
987  pe = id = iq = 0.0f;
988  }
989  data.pe = pe;
990  data.id = id;
991  data.iq = iq;
992  data.oldPe = pe;
993  data.oldId = id;
994  data.oldIq = iq;
995  syncGenerator->SetElectricalData(data);
996 
997  return true;
998 }
999 
1000 double Electromechanical::CalculateSyncMachineIntVariables(SyncGenerator* syncGenerator,
1001  double id,
1002  double iq,
1003  double sd,
1004  double sq,
1005  double pe,
1006  double k)
1007 {
1008  double error = 0.0;
1009  auto data = syncGenerator->GetElectricalData();
1010 
1011  // Mechanical differential equations.
1012  double w = data.icSpeed.c + data.icSpeed.m * (data.pm - pe);
1013  error = std::max(error, std::abs(data.speed - w) / m_refSpeed);
1014 
1015  m_wError += std::abs(data.speed - w) / m_refSpeed;
1016 
1017  double delta = data.icDelta.c + data.icDelta.m * w;
1018  error = std::max(error, std::abs(data.delta - delta));
1019 
1020  data.speed = w;
1021  data.delta = delta;
1022 
1023  // Electrical differential equations
1024  switch(data.model) {
1025  case Machines::SM_MODEL_1: {
1026  // There is no differential equations.
1027  } break;
1028  case Machines::SM_MODEL_2: {
1029  double syncXd, transXd;
1030  syncXd = data.syncXd * k;
1031  transXd = data.transXd * k;
1032 
1033  double tranEq = (data.icTranEq.c + data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id)) /
1034  (1.0 + data.icTranEq.m * (sd - 1.0));
1035  error = std::max(error, std::abs(data.tranEq - tranEq));
1036 
1037  data.tranEq = tranEq;
1038  } break;
1039  case Machines::SM_MODEL_3: {
1040  double syncXd, syncXq, transXd, transXq;
1041  syncXd = data.syncXd * k;
1042  syncXq = data.syncXq * k;
1043  transXd = data.transXd * k;
1044  transXq = data.transXq * k;
1045  if(syncXq == 0.0) syncXq = syncXd;
1046  if(transXq == 0.0) transXq = transXd;
1047 
1048  double tranEq = (data.icTranEq.c + data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id)) /
1049  (1.0 + data.icTranEq.m * (sd - 1.0));
1050  error = std::max(error, std::abs(data.tranEq - tranEq));
1051 
1052  double tranEd =
1053  (data.icTranEd.c - data.icTranEd.m * (syncXq - transXq) * iq) / (1.0 + data.icTranEd.m * (sq - 1.0));
1054  error = std::max(error, std::abs(data.tranEd - tranEd));
1055 
1056  data.tranEq = tranEq;
1057  data.tranEd = tranEd;
1058 
1059  if(!syncGenerator->IsOnline()) {
1060  std::complex<double> e;
1061  DQ0toABC(data.tranEd, data.tranEq, data.delta, e);
1062  data.terminalVoltage = e;
1063  }
1064  } break;
1065  case Machines::SM_MODEL_4: {
1066  double syncXd, syncXq, transXd, subXd, subXq;
1067  syncXd = data.syncXd * k;
1068  syncXq = data.syncXq * k;
1069  transXd = data.transXd * k;
1070  subXd = data.subXd * k;
1071  subXq = data.subXq * k;
1072  if(syncXq == 0.0) syncXq = syncXd;
1073  if(subXd == 0.0) subXd = subXq;
1074  if(subXq == 0.0) subXq = subXd;
1075 
1076  double tranEq = (data.icTranEq.c + data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id)) /
1077  (1.0 + data.icTranEq.m * (sd - 1.0));
1078  error = std::max(error, std::abs(data.tranEq - tranEq));
1079 
1080  double subEq = (data.icSubEq.c + data.icSubEq.m * (sd * tranEq + (transXd - subXd) * id)) /
1081  (1.0 + data.icSubEq.m * (sd - 1.0));
1082  error = std::max(error, std::abs(data.subEq - subEq));
1083 
1084  double subEd =
1085  (data.icSubEd.c - data.icSubEd.m * ((syncXq - subXq) * iq)) / (1.0 + data.icSubEd.m * (sq - 1.0));
1086  error = std::max(error, std::abs(data.subEd - subEd));
1087 
1088  data.tranEq = tranEq;
1089  data.subEq = subEq;
1090  data.subEd = subEd;
1091  } break;
1092  case Machines::SM_MODEL_5: {
1093  double syncXd, syncXq, transXd, transXq, subXd, subXq;
1094  syncXd = data.syncXd * k;
1095  syncXq = data.syncXq * k;
1096  transXd = data.transXd * k;
1097  transXq = data.transXq * k;
1098  subXd = data.subXd * k;
1099  subXq = data.subXq * k;
1100  if(syncXq == 0.0) syncXq = syncXd;
1101  if(transXq == 0.0) transXq = transXd;
1102  if(subXd == 0.0) subXd = subXq;
1103  if(subXq == 0.0) subXq = subXd;
1104 
1105  double tranEq = (data.icTranEq.c + data.icTranEq.m * (data.fieldVoltage + (syncXd - transXd) * id)) /
1106  (1.0 + data.icTranEq.m * (sd - 1.0));
1107  error = std::max(error, std::abs(data.tranEq - tranEq));
1108 
1109  double tranEd =
1110  (data.icTranEd.c - data.icTranEd.m * (syncXq - transXq) * iq) / (1.0 + data.icTranEd.m * (sq - 1.0));
1111  error = std::max(error, std::abs(data.tranEd - tranEd));
1112 
1113  double subEq = (data.icSubEq.c + data.icSubEq.m * (sd * tranEq + (transXd - subXd) * id)) /
1114  (1.0 + data.icSubEq.m * (sd - 1.0));
1115  error = std::max(error, std::abs(data.subEq - subEq));
1116 
1117  double subEd = (data.icSubEd.c + data.icSubEd.m * (sq * tranEd - (transXq - subXq) * iq)) /
1118  (1.0 + data.icSubEd.m * (sq - 1.0));
1119  error = std::max(error, std::abs(data.subEd - subEd));
1120 
1121  data.tranEq = tranEq;
1122  data.tranEd = tranEd;
1123  data.subEq = subEq;
1124  data.subEd = subEd;
1125  } break;
1126  }
1127 
1128  syncGenerator->SetElectricalData(data);
1129  return error;
1130 }
1131 
1132 void Electromechanical::CalculateReferenceSpeed()
1133 {
1134  if(m_useCOI) {
1135  double sumHW = 0.0;
1136  double sumH = 0.0;
1137  for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
1138  SyncGenerator* syncGenerator = *it;
1139  if(syncGenerator->IsOnline()) {
1140  auto data = syncGenerator->GetElectricalData();
1141  double k = 1.0; // Power base change factor.
1142  if(data.useMachineBase) {
1143  double oldBase = syncGenerator->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
1144  k = m_powerSystemBase / oldBase;
1145  }
1146  sumH += data.inertia / k;
1147  sumHW += data.inertia * data.speed / k;
1148  }
1149  }
1150  m_refSpeed = sumHW / sumH;
1151  } else {
1152  m_refSpeed = 2.0 * M_PI * m_systemFreq;
1153  }
1154 }
1155 
1156 bool Electromechanical::CalculateSyncMachineSaturation(SyncGenerator* syncMachine,
1157  double& id,
1158  double& iq,
1159  double& sd,
1160  double& sq,
1161  bool updateCurrents,
1162  double k)
1163 {
1164  // [Ref] Arrillaga, J.; Arnold, C. P.. "Computer Modelling of Electrical Power Systems". Pg. 254-260
1165  auto data = syncMachine->GetElectricalData();
1166  auto smDataModel = GetSyncMachineModelData(syncMachine);
1167 
1168  int n = static_cast<Bus*>(syncMachine->GetParentList()[0])->GetElectricalData().number;
1169  if(syncMachine->IsOnline()) {
1170  data.terminalVoltage = m_vBus[n];
1171  }
1172  double idCalc = id;
1173  double iqCalc = iq;
1174  double sdCalc = sd;
1175  double sqCalc = sq;
1176 
1177  double vd, vq;
1178  ABCtoDQ0(data.terminalVoltage, data.delta, vd, vq);
1179  double deltaVd = smDataModel.ed - vd;
1180  double deltaVq = smDataModel.eq - vq;
1181 
1182  double ra = data.armResistance * k;
1183  double xd = smDataModel.xd;
1184  double xq = smDataModel.xq;
1185 
1186  double syncXd = data.syncXd * k;
1187  double syncXq = data.syncXq * k;
1188  if(data.model == Machines::SM_MODEL_1) {
1189  syncXq = data.transXd * k;
1190  syncXd = syncXq;
1191  } else if(data.syncXq == 0.0)
1192  syncXq = data.syncXd * k;
1193 
1194  double xp = data.potierReactance * k;
1195  if(xp == 0.0) xp = 0.8 * data.transXd * k;
1196  double satFacd = (data.satFactor - 1.2) / std::pow(1.2, 7);
1197  double satFacq = satFacd * (syncXq / syncXd);
1198 
1199  bool exit = false;
1200  int iterations = 0;
1201  while(!exit) {
1202  double oldSd = sdCalc;
1203  double oldSq = sqCalc;
1204 
1205  // Saturated reactances.
1206  double xds = (xd - xp) / sdCalc + xp;
1207  double xqs = (xq - xp) / sqCalc + xp;
1208  // dq currents.
1209  double den = 1.0 / (ra * ra + xds * xqs);
1210  iqCalc = den * (ra * deltaVq + xds * deltaVd);
1211  idCalc = den * (-xqs * deltaVq + ra * deltaVd);
1212  // Potier voltages
1213  double epq = vq + ra * iqCalc - xp * idCalc;
1214  double epd = vd + ra * idCalc + xp * iqCalc;
1215  // Saturation factors.
1216  // Gauss
1217  /*sdCalc = 1.0 + satFacd * std::pow(epq, 6);
1218  sqCalc = 1.0 + satFacq * std::pow(epd, 6);*/
1219 
1220  // Newton-raphson
1221  double f1 = 1.0 - sdCalc + satFacd * std::pow(epq, 6);
1222  double f2 = 1.0 - sqCalc + satFacq * std::pow(epd, 6);
1223  double dF1dSd =
1224  (6.0 * satFacd * std::pow(epq, 5) * xp * (xd - xp) * deltaVq) / ((sdCalc - 1.0) * xp + xd) - 1.0;
1225  double dF2dSq =
1226  (6.0 * satFacq * std::pow(epd, 5) * xp * (xq - xp) * deltaVd) / ((sqCalc - 1.0) * xp + xq) - 1.0;
1227 
1228  sdCalc = sdCalc - f1 / dF1dSd;
1229  sqCalc = sqCalc - f2 / dF2dSq;
1230 
1231  double error = std::abs(sdCalc - oldSd) + std::abs(sqCalc - oldSq);
1232  if(error < m_saturationTolerance) exit = true;
1233 
1234  iterations++;
1235  if((iterations >= m_maxIterations) & !exit) {
1236  m_errorMsg =
1237  _("It was not possible to solve the saturation of the synchronous machine \"") + data.name + wxT("\".");
1238  return false;
1239  }
1240  }
1241 
1242  sd = sdCalc;
1243  sq = sqCalc;
1244  if(updateCurrents) {
1245  id = idCalc;
1246  iq = iqCalc;
1247  }
1248  return true;
1249 }
1250 
1251 SyncMachineModelData Electromechanical::GetSyncMachineModelData(SyncGenerator* syncMachine)
1252 {
1253  SyncMachineModelData smModelData;
1254 
1255  auto data = syncMachine->GetElectricalData();
1256  double k = 1.0; // Power base change factor.
1257  if(data.useMachineBase) {
1258  double oldBase = syncMachine->GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
1259  k = m_powerSystemBase / oldBase;
1260  }
1261 
1262  switch(data.model) {
1263  case Machines::SM_MODEL_1: {
1264  smModelData.ed = data.tranEd;
1265  smModelData.eq = data.tranEq;
1266  smModelData.xq = data.transXd * k;
1267  smModelData.xd = smModelData.xq;
1268  } break;
1269  case Machines::SM_MODEL_2: {
1270  smModelData.ed = data.tranEd;
1271  smModelData.eq = data.tranEq;
1272  smModelData.xd = data.transXd * k;
1273  smModelData.xq = data.transXq * k;
1274  if(smModelData.xq == 0.0) {
1275  smModelData.xq = data.syncXq * k;
1276  if(smModelData.xq == 0.0) {
1277  smModelData.xq = data.syncXd * k;
1278  }
1279  }
1280  } break;
1281  case Machines::SM_MODEL_3: {
1282  smModelData.ed = data.tranEd;
1283  smModelData.eq = data.tranEq;
1284  smModelData.xd = data.transXd * k;
1285  smModelData.xq = data.transXq * k;
1286  if(smModelData.xq == 0.0) smModelData.xq = smModelData.xd;
1287  } break;
1288  case Machines::SM_MODEL_4:
1289  case Machines::SM_MODEL_5: {
1290  smModelData.ed = data.subEd;
1291  smModelData.eq = data.subEq;
1292  smModelData.xd = data.subXd * k;
1293  smModelData.xq = data.subXq * k;
1294  if(smModelData.xd == 0.0) smModelData.xd = smModelData.xq;
1295  if(smModelData.xq == 0.0) smModelData.xq = smModelData.xd;
1296  } break;
1297  }
1298  return smModelData;
1299 }
std::vector< double > swTime
Definition: PowerElement.h:95
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
-
Calculates the electromechanical transient based on disturbances (e.g. system fault).
+
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition: Element.cpp:235
- +
Synchronous generator power element.
std::vector< SwitchingType > swType
Definition: PowerElement.h:94
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
- +
Switching data of power elements.
Definition: PowerElement.h:93
Synchronous machine data for different models.
-
Definition: Line.h:52
-
Definition: Load.h:35
+
Power line element.
Definition: Line.h:59
+
Loas shunt power element.
Definition: Load.h:42
virtual bool GetYBus(std::vector< std::vector< std::complex< double > > > &yBus, double systemPowerBase, YBusSequence sequence=POSITIVE_SEQ, bool includeSyncMachines=false, bool allLoadsAsImpedances=false)
Get the admittance matrix from the list of elements (use GetElementsFromList first).
virtual SwitchingData GetSwitchingData()
Returns the switching data of the element.
Definition: PowerElement.h:182
- - - +
Shunt capactior power element.
Definition: Capacitor.h:38
+
Abstract class of power elements.
Definition: PowerElement.h:117
+
Inductor shunt power element.
Definition: Inductor.h:38
virtual void GetElementsFromList(std::vector< Element *> elementList)
Separate the power elements from a generic list.
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_electromechanical_8h.html b/docs/doxygen/html/_electromechanical_8h.html index edeac51..bf54f4c 100644 --- a/docs/doxygen/html/_electromechanical_8h.html +++ b/docs/doxygen/html/_electromechanical_8h.html @@ -90,9 +90,6 @@ $(document).ready(function(){initNavTree('_electromechanical_8h.html','');});
Electromechanical.h File Reference
- -

Calculates the electromechanical transient based on disturbances (e.g. system fault). -More...

#include "ElectricCalculation.h"
#include <wx/progdlg.h>
#include <wx/log.h>
@@ -105,13 +102,10 @@ Classes  Synchronous machine data for different models. More...
  class  Electromechanical + Calculates the electromechanical transient based on disturbances (e.g. system fault). More...
  -

Detailed Description

-

Calculates the electromechanical transient based on disturbances (e.g. system fault).

- -

Definition in file Electromechanical.h.

-
+
diff --git a/docs/doxygen/html/_element_8cpp_source.html b/docs/doxygen/html/_element_8cpp_source.html index f5772b7..3ea17ab 100644 --- a/docs/doxygen/html/_element_8cpp_source.html +++ b/docs/doxygen/html/_element_8cpp_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_element_8cpp_source.html','');});
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Element.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
23 Element::Element() { m_selectionColour.SetRGBA(0.0, 0.5, 1.0, 0.5); }
25 void Element::SetPosition(const wxPoint2DDouble position)
26 {
27  m_position = position;
28  m_rect =
29  wxRect2DDouble(m_position.m_x - m_width / 2.0 - m_borderSize, m_position.m_y - m_height / 2.0 - m_borderSize,
30  m_width + 2.0 * m_borderSize, m_height + 2.0 * m_borderSize);
31 }
32 
33 void Element::DrawCircle(wxPoint2DDouble position, double radius, int numSegments, GLenum mode) const
34 {
35  glBegin(mode);
36  for(int i = 0; i < numSegments; i++) {
37  double theta = 2.0 * 3.1415926 * double(i) / double(numSegments);
38  glVertex2f(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y);
39  }
40  glEnd();
41 }
42 
43 void Element::DrawArc(wxPoint2DDouble position,
44  double radius,
45  double initAngle,
46  double finalAngle,
47  int numSegments,
48  GLenum mode) const
49 {
50  double initAngRad = wxDegToRad(initAngle);
51  double finalAngRad = wxDegToRad(finalAngle);
52  glBegin(mode);
53  for(int i = 0; i <= numSegments; i++) {
54  double theta = initAngRad + (finalAngRad - initAngRad) * double(i) / double(numSegments);
55  glVertex2f(radius * std::cos(theta) + position.m_x, radius * std::sin(theta) + position.m_y);
56  }
57  glEnd();
58 }
59 
60 void Element::DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode) const
61 {
62  glBegin(mode);
63  for(int i = 0; i < 3; i++) {
64  glVertex2d(points[i].m_x, points[i].m_y);
65  }
66  glEnd();
67 }
68 
69 void Element::DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode) const
70 {
71  glBegin(mode); // TODO: GL_QUADS é obsoleto (OpenGL 3.0+), encontrar outra solução.
72  glVertex2d(position.m_x - width / 2.0, position.m_y - height / 2.0);
73  glVertex2d(position.m_x - width / 2.0, position.m_y + height / 2.0);
74  glVertex2d(position.m_x + width / 2.0, position.m_y + height / 2.0);
75  glVertex2d(position.m_x + width / 2.0, position.m_y - height / 2.0);
76  glEnd();
77 }
78 
79 void Element::DrawRectangle(wxPoint2DDouble* points, GLenum mode) const
80 {
81  glBegin(mode); // TODO: GL_QUADS é obsoleto (OpenGL 3.0+), encontrar outra solução.
82  glVertex2d(points[0].m_x, points[0].m_y);
83  glVertex2d(points[1].m_x, points[1].m_y);
84  glVertex2d(points[2].m_x, points[2].m_y);
85  glVertex2d(points[3].m_x, points[3].m_y);
86  glEnd();
87 }
88 
89 void Element::DrawLine(std::vector<wxPoint2DDouble> points, GLenum mode) const
90 {
91  glBegin(mode);
92  for(auto it = points.begin(); it != points.end(); ++it) {
93  glVertex2d((*it).m_x, (*it).m_y);
94  }
95  glEnd();
96 }
97 
98 void Element::DrawPickbox(wxPoint2DDouble position) const
99 {
100  glLineWidth(1.0);
101  glColor4d(1.0, 1.0, 1.0, 0.8);
102  DrawRectangle(position, 8.0, 8.0);
103  glColor4d(0.0, 0.0, 0.0, 1.0);
104  DrawRectangle(position, 8.0, 8.0, GL_LINE_LOOP);
105 }
106 
107 wxPoint2DDouble Element::RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees) const
108 {
109  double radAngle = angle;
110  if(degrees) radAngle = wxDegToRad(angle);
111  return wxPoint2DDouble(std::cos(radAngle) * (pointToRotate.m_x - m_position.m_x) -
112  std::sin(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_x,
113  std::sin(radAngle) * (pointToRotate.m_x - m_position.m_x) +
114  std::cos(radAngle) * (pointToRotate.m_y - m_position.m_y) + m_position.m_y);
115 }
116 
117 void Element::StartMove(wxPoint2DDouble position)
118 {
119  this->m_moveStartPt = position;
120  this->m_movePos = m_position;
121 }
122 
123 void Element::Move(wxPoint2DDouble position) { SetPosition(m_movePos + position - m_moveStartPt); }
124 wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX, double offsetY) const
125 {
126  return wxPoint2DDouble(m_position.m_x + offsetX + translation.m_x, m_position.m_y + offsetY + translation.m_y) *
127  scale;
128 }
129 
130 wxPoint2DDouble Element::WorldToScreen(wxPoint2DDouble position,
131  wxPoint2DDouble translation,
132  double scale,
133  double offsetX,
134  double offsetY) const
135 {
136  return wxPoint2DDouble(position.m_x + offsetX + translation.m_x, position.m_y + offsetY + translation.m_y) * scale;
137 }
138 
139 void Element::DrawPoint(wxPoint2DDouble position, double size) const
140 {
141  glPointSize(size);
142  glBegin(GL_POINTS);
143  glVertex2d(position.m_x, position.m_y);
144  glEnd();
145 }
146 
147 bool Element::RotatedRectanglesIntersects(wxRect2DDouble rect1,
148  wxRect2DDouble rect2,
149  double angle1,
150  double angle2) const
151 {
152  wxPoint2DDouble rect1Corners[4] = {rect1.GetLeftTop(), rect1.GetLeftBottom(), rect1.GetRightBottom(),
153  rect1.GetRightTop()};
154  wxPoint2DDouble rect2Corners[4] = {rect2.GetLeftTop(), rect2.GetLeftBottom(), rect2.GetRightBottom(),
155  rect2.GetRightTop()};
156  wxPoint2DDouble rect1Center(rect1.m_x + rect1.m_width / 2.0, rect1.m_y + rect1.m_height / 2.0);
157  wxPoint2DDouble rect2Center(rect2.m_x + rect2.m_width / 2.0, rect2.m_y + rect2.m_height / 2.0);
158 
159  // Rotate the corners.
160  double radAngle1 = wxDegToRad(angle1);
161  double radAngle2 = wxDegToRad(angle2);
162 
163  for(int i = 0; i < 4; i++) {
164  rect1Corners[i] =
165  wxPoint2DDouble(std::cos(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) -
166  std::sin(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_x,
167  std::sin(radAngle1) * (rect1Corners[i].m_x - rect1Center.m_x) +
168  std::cos(radAngle1) * (rect1Corners[i].m_y - rect1Center.m_y) + rect1Center.m_y);
169 
170  rect2Corners[i] =
171  wxPoint2DDouble(std::cos(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) -
172  std::sin(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_x,
173  std::sin(radAngle2) * (rect2Corners[i].m_x - rect2Center.m_x) +
174  std::cos(radAngle2) * (rect2Corners[i].m_y - rect2Center.m_y) + rect2Center.m_y);
175  }
176 
177  //[Ref] http://www.gamedev.net/page/resources/_/technical/game-programming/2d-rotated-rectangle-collision-r2604
178 
179  // Find the rectangles axis to project
180  wxPoint2DDouble axis[4] = {rect1Corners[3] - rect1Corners[0], rect1Corners[3] - rect1Corners[2],
181  rect2Corners[3] - rect2Corners[0], rect2Corners[3] - rect2Corners[2]};
182 
183  // Calculate the projected points to each axis
184  wxPoint2DDouble rect1ProjPts[4][4]; // [axis][corner]
185  wxPoint2DDouble rect2ProjPts[4][4]; // [axis][corner]
186  for(int i = 0; i < 4; i++) {
187  double den = axis[i].m_x * axis[i].m_x + axis[i].m_y * axis[i].m_y;
188  for(int j = 0; j < 4; j++) {
189  double m_rectProj = (rect1Corners[j].m_x * axis[i].m_x + rect1Corners[j].m_y * axis[i].m_y) / den;
190  double rectProj = (rect2Corners[j].m_x * axis[i].m_x + rect2Corners[j].m_y * axis[i].m_y) / den;
191 
192  rect1ProjPts[i][j] = wxPoint2DDouble(m_rectProj * axis[i].m_x, m_rectProj * axis[i].m_y);
193  rect2ProjPts[i][j] = wxPoint2DDouble(rectProj * axis[i].m_x, rectProj * axis[i].m_y);
194  }
195  }
196 
197  // Calculate the scalar value to identify the max and min values on projections
198  double rect1Scalar[4][4]; //[axis][corner]
199  double rect2Scalar[4][4]; //[axis][corner]
200  for(int i = 0; i < 4; i++) {
201  for(int j = 0; j < 4; j++) {
202  rect1Scalar[i][j] = rect1ProjPts[i][j].m_x * axis[i].m_x + rect1ProjPts[i][j].m_y * axis[i].m_y;
203  rect2Scalar[i][j] = rect2ProjPts[i][j].m_x * axis[i].m_x + rect2ProjPts[i][j].m_y * axis[i].m_y;
204  }
205  }
206  // Identify the max and min scalar values
207  double rect1Min[4];
208  double rect1Max[4];
209  double rect2Min[4];
210  double rect2Max[4];
211 
212  for(int i = 0; i < 4; i++) {
213  rect1Max[i] = rect1Scalar[i][0];
214  rect2Max[i] = rect2Scalar[i][0];
215  rect1Min[i] = rect1Scalar[i][0];
216  rect2Min[i] = rect2Scalar[i][0];
217 
218  for(int j = 1; j < 4; j++) {
219  if(rect1Max[i] < rect1Scalar[i][j]) rect1Max[i] = rect1Scalar[i][j];
220  if(rect2Max[i] < rect2Scalar[i][j]) rect2Max[i] = rect2Scalar[i][j];
221 
222  if(rect1Min[i] > rect1Scalar[i][j]) rect1Min[i] = rect1Scalar[i][j];
223  if(rect2Min[i] > rect2Scalar[i][j]) rect2Min[i] = rect2Scalar[i][j];
224  }
225  }
226 
227  // Check if any segment don't overlap
228  for(int i = 0; i < 4; i++) {
229  if(!(rect2Min[i] <= rect1Max[i] && rect2Max[i] >= rect1Min[i])) return false;
230  }
231 
232  return true;
233 }
234 
235 bool Element::SetOnline(bool online)
236 {
237  // Check if any parent is null.
238  for(auto it = m_parentList.begin(); it != m_parentList.end(); it++) {
239  if(!(*it)) return false;
240  }
241  m_online = online;
242  return true;
243 }
244 
245 void Element::GeneralMenuItens(wxMenu& menu)
246 {
247  wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
248  wxString exePath = exeFileName.GetPath();
249 
250  wxMenuItem* clockItem = new wxMenuItem(&menu, ID_ROTATE_CLOCK, _("Rotate clockwise"));
251  clockItem->SetBitmap(wxImage(exePath + "\\..\\data\\images\\menu\\rotateClock16.png"));
252  menu.Append(clockItem);
253 
254  wxMenuItem* counterClockItem = new wxMenuItem(&menu, ID_ROTATE_COUNTERCLOCK, _("Rotate counter-clockwise"));
255  counterClockItem->SetBitmap(wxImage(exePath + "\\..\\data\\images\\menu\\rotateCounterClock16.png"));
256  menu.Append(counterClockItem);
257 
258  wxMenuItem* deleteItem = new wxMenuItem(&menu, ID_DELETE, _("Delete"));
259  deleteItem->SetBitmap(wxImage(exePath + "\\..\\data\\images\\menu\\delete16.png"));
260  menu.Append(deleteItem);
261 }
262 
263 void Element::CalculateBoundaries(wxPoint2DDouble& leftUp, wxPoint2DDouble& rightBottom) const
264 {
265  // Check rect corners boundaries.
266 
267  // Get rectangle corners
268  wxPoint2DDouble rectCorner[4] = {m_rect.GetLeftTop(), m_rect.GetLeftBottom(), m_rect.GetRightBottom(),
269  m_rect.GetRightTop()};
270  // Rotate corners.
271  for(int i = 0; i < 4; ++i) {
272  rectCorner[i] = RotateAtPosition(rectCorner[i], m_angle);
273  }
274  leftUp = rectCorner[0];
275  rightBottom = rectCorner[0];
276  for(int i = 1; i < 4; ++i) {
277  if(rectCorner[i].m_x < leftUp.m_x) leftUp.m_x = rectCorner[i].m_x;
278  if(rectCorner[i].m_y < leftUp.m_y) leftUp.m_y = rectCorner[i].m_y;
279  if(rectCorner[i].m_x > rightBottom.m_x) rightBottom.m_x = rectCorner[i].m_x;
280  if(rectCorner[i].m_y > rightBottom.m_y) rightBottom.m_y = rectCorner[i].m_y;
281  }
282 
283  // Check points list boundaries.
284  for(int i = 0; i < (int)m_pointList.size(); i++) {
285  if(m_pointList[i].m_x < leftUp.m_x) leftUp.m_x = m_pointList[i].m_x;
286  if(m_pointList[i].m_y < leftUp.m_y) leftUp.m_y = m_pointList[i].m_y;
287  if(m_pointList[i].m_x > rightBottom.m_x) rightBottom.m_x = m_pointList[i].m_x;
288  if(m_pointList[i].m_y > rightBottom.m_y) rightBottom.m_y = m_pointList[i].m_y;
289  }
290 }
291 
292 bool Element::DoubleFromString(wxWindow* parent, wxString strValue, double& value, wxString errorMsg)
293 {
294  double dValue = 0.0;
295 
296  if(!strValue.ToDouble(&dValue)) {
297  wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
298  msgDialog.ShowModal();
299  return false;
300  }
301 
302  value = dValue;
303  return true;
304 }
305 
306 bool Element::IntFromString(wxWindow* parent, wxString strValue, int& value, wxString errorMsg)
307 {
308  long int iValue = 0;
309 
310  if(!strValue.ToLong(&iValue)) {
311  wxMessageDialog msgDialog(parent, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
312  msgDialog.ShowModal();
313  return false;
314  }
315 
316  value = iValue;
317  return true;
318 }
319 
320 wxString Element::StringFromDouble(double value, int minDecimal)
321 {
322  wxString str = wxString::FromCDouble(value, 13);
323  int cutNumber = 0;
324  int numDecimal = 0;
325  bool foundCut = false;
326  for(int i = (int)str.length() - 1; i >= 0; i--) {
327  if(str[i] != '0' && !foundCut) {
328  cutNumber = i;
329  foundCut = true;
330  }
331  if(str[i] == '.') {
332  numDecimal = i;
333  break;
334  }
335  }
336 
337  wxString formatedStr = "";
338  if(cutNumber - numDecimal > minDecimal)
339  formatedStr = wxString::FromDouble(value, cutNumber - numDecimal);
340  else
341  formatedStr = wxString::FromDouble(value, minDecimal);
342 
343  return formatedStr;
344 }
345 
346 void Element::ReplaceParent(Element* oldParent, Element* newParent)
347 {
348  for(int i = 0; i < (int)m_parentList.size(); i++) {
349  if(m_parentList[i] == oldParent) m_parentList[i] = newParent;
350  }
351 }
352 
353 void Element::AddChild(Element* child) { m_childList.push_back(child); }
355 {
356  for(auto it = m_childList.begin(); it != m_childList.end(); ++it) {
357  Element* element = *it;
358  if(element == child) m_childList.erase(it--);
359  }
360 }
361 
362 void Element::ReplaceChild(Element* oldChild, Element* newChild)
363 {
364  for(int i = 0; i < (int)m_childList.size(); i++) {
365  if(m_childList[i] == oldChild) m_childList[i] = newChild;
366  }
367 }
368 
369 void OpenGLColour::SetRGBA(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
370 {
371  rgba[0] = red;
372  rgba[1] = green;
373  rgba[2] = blue;
374  rgba[3] = alpha;
375 }
376 
377 OpenGLColour::OpenGLColour() { SetRGBA(1.0, 1.0, 1.0, 1.0); }
378 OpenGLColour::OpenGLColour(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
379 {
380  SetRGBA(red, green, blue, alpha);
381 }
382 
383 double Element::PointToLineDistance(wxPoint2DDouble point, int* segmentNumber) const
384 {
385  //[Ref] http://geomalgorithms.com/a02-_lines.html
386  double distance = 100.0; // Big initial distance.
387  wxPoint2DDouble p0 = point;
388 
389  for(int i = 1; i < (int)m_pointList.size() - 2; i++) {
390  double d = 0.0;
391 
392  wxPoint2DDouble p1 = m_pointList[i];
393  wxPoint2DDouble p2 = m_pointList[i + 1];
394 
395  wxPoint2DDouble v = p2 - p1;
396  wxPoint2DDouble w = p0 - p1;
397 
398  double c1 = w.m_x * v.m_x + w.m_y * v.m_y;
399  double c2 = v.m_x * v.m_x + v.m_y * v.m_y;
400 
401  if(c1 <= 0.0) {
402  d = std::sqrt(std::pow(p0.m_y - p1.m_y, 2) + std::pow(p0.m_x - p1.m_x, 2));
403  } else if(c2 <= c1) {
404  d = std::sqrt(std::pow(p0.m_y - p2.m_y, 2) + std::pow(p0.m_x - p2.m_x, 2));
405  } else {
406  d = std::abs((p2.m_y - p1.m_y) * p0.m_x - (p2.m_x - p1.m_x) * p0.m_y + p2.m_x * p1.m_y - p2.m_y * p1.m_x) /
407  std::sqrt(std::pow(p2.m_y - p1.m_y, 2) + std::pow(p2.m_x - p1.m_x, 2));
408  }
409  if(d < distance) {
410  distance = d;
411  if(segmentNumber) *segmentNumber = i;
412  }
413  }
414 
415  return distance;
416 }
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Element.cpp:123
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void DrawTriangle(std::vector< wxPoint2DDouble > points, GLenum mode=GL_TRIANGLES) const
Draw a triangle.
Definition: Element.cpp:60
virtual void DrawLine(std::vector< wxPoint2DDouble > points, GLenum mode=GL_LINE_STRIP) const
Draw line.
Definition: Element.cpp:89
virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble translation, double scale, double offsetX=0.0, double offsetY=0.0) const
Convert the element position to screen position.
Definition: Element.cpp:124
@@ -101,7 +101,7 @@ $(document).ready(function(){initNavTree('_element_8cpp_source.html','');});
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition: Element.cpp:107
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
Definition: Element.cpp:263
virtual void DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode=GL_QUADS) const
Draw rectangle.
Definition: Element.cpp:69
-
Class to manage color of OpenGL.
+
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition: Element.cpp:245
virtual void ReplaceChild(Element *oldChild, Element *newChild)
Replace a child from the list.
Definition: Element.cpp:362
static bool IntFromString(wxWindow *parent, wxString strValue, int &value, wxString errorMsg)
Convert a string to int. Show a error message if the conversion fail.
Definition: Element.cpp:306
diff --git a/docs/doxygen/html/_element_8h.html b/docs/doxygen/html/_element_8h.html index 453f108..7fda9d3 100644 --- a/docs/doxygen/html/_element_8h.html +++ b/docs/doxygen/html/_element_8h.html @@ -91,9 +91,6 @@ $(document).ready(function(){initNavTree('_element_8h.html','');});
Element.h File Reference
- -

Class to manage color of OpenGL. -More...

#include <wx/msgdlg.h>
#include <wx/geometry.h>
#include <wx/cursor.h>
@@ -108,8 +105,10 @@ $(document).ready(function(){initNavTree('_element_8h.html','');});

Classes

class  OpenGLColour + Class to manage color of OpenGL. More...
  class  Element + Base class of all elements of the program. This class is responsible for manage graphical and his data. More...
 

@@ -140,12 +139,7 @@ Enumerations

 
-

Detailed Description

-

Class to manage color of OpenGL.

-

Base class of all elements of the program. This class is responsible for manage graphical and his data.

- -

Definition in file Element.h.

-

Enumeration Type Documentation

+

Enumeration Type Documentation

◆ ContextMenuID

diff --git a/docs/doxygen/html/_element_8h_source.html b/docs/doxygen/html/_element_8h_source.html index afc215f..d71ef94 100644 --- a/docs/doxygen/html/_element_8h_source.html +++ b/docs/doxygen/html/_element_8h_source.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_element_8h_source.html','');}); Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELEMENT_H
19 #define ELEMENT_H
20 
21 #include <wx/msgdlg.h>
22 #include <wx/geometry.h>
23 #include <wx/cursor.h>
24 #include <wx/menu.h>
25 #include <wx/stdpaths.h>
26 #include <wx/filename.h>
27 #include <GL/gl.h>
28 
29 #include <complex>
30 
31 //#include <wx/log.h>
32 
37 enum PickboxID {
38  ID_PB_NONE = 0,
45 };
46 
58 };
59 
68 {
69  public:
73  OpenGLColour();
74 
82  OpenGLColour(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
83 
87  virtual ~OpenGLColour() {}
95  void SetRGBA(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);
96 
101  const GLdouble* GetRGBA() const { return rgba; }
102  protected:
103  GLdouble rgba[4];
104 };
105 
113 class Element
114 {
115  public:
119  Element();
120 
124  virtual ~Element();
125 
130  void SetDragging(bool dragging = true) { m_dragging = dragging; }
135  void SetHeight(double height) { m_height = height; }
140  void SetPosition(const wxPoint2DDouble position);
141 
146  void SetSelected(bool selected = true) { m_selected = selected; }
151  void SetWidth(double width) { m_width = width; }
156  void SetAngle(double angle) { m_angle = angle; }
161  void ShowPickbox(bool showPickbox = true) { m_showPickbox = showPickbox; }
166  void SetBorderSize(double borderSize) { m_borderSize = borderSize; }
171  bool SetOnline(bool online = true);
172 
177  virtual void SetPointList(std::vector<wxPoint2DDouble> pointList) { m_pointList = pointList; }
182  wxRect2DDouble GetRect() const { return m_rect; }
187  wxPoint2DDouble GetPosition() const { return m_position; }
192  bool IsDragging() const { return m_dragging; }
197  double GetHeight() const { return m_height; }
202  bool IsSelected() const { return m_selected; }
207  double GetWidth() const { return m_width; }
212  double GetAngle() const { return m_angle; }
217  double GetRotationAngle() const { return m_rotationAngle; }
222  bool IsPickboxShown() const { return m_showPickbox; }
227  bool IsOnline() const { return m_online; }
232  virtual std::vector<wxPoint2DDouble> GetPointList() const { return m_pointList; }
240  virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return false; }
245  virtual void AddParent(Element* parent) { m_parentList.push_back(parent); }
250  virtual bool Contains(wxPoint2DDouble position) const = 0;
251 
256  virtual bool Intersects(wxRect2DDouble rect) const = 0;
257 
262  virtual Element* GetCopy() { return NULL; }
267  virtual void SetID(int id) { m_elementID = id; }
272  virtual int GetID() const { return m_elementID; }
277  virtual void AddChild(Element* child);
278 
283  virtual void RemoveChild(Element* child);
284 
290  virtual void ReplaceChild(Element* oldChild, Element* newChild);
291 
296  virtual wxString GetTipText() const { return wxEmptyString; }
302  virtual void Draw(wxPoint2DDouble translation, double scale) const {}
307  virtual void Rotate(bool clockwise = true) {}
313  virtual bool GetContextMenu(wxMenu& menu) { return false; }
318  virtual void AddPoint(wxPoint2DDouble point) {}
323  virtual void StartMove(wxPoint2DDouble position);
324 
330  virtual void Move(wxPoint2DDouble position);
331 
337  virtual void MoveNode(Element* parent, wxPoint2DDouble position) {}
343  virtual bool NodeContains(wxPoint2DDouble position) { return false; }
347  virtual void UpdateNodes() {}
354  virtual bool SetNodeParent(Element* parent) { return false; }
359  virtual void RemoveParent(Element* parent) {}
365  virtual void ReplaceParent(Element* oldParent, Element* newParent);
366 
372  virtual void RotateNode(Element* parent, bool clockwise = true) {}
379  virtual bool PickboxContains(wxPoint2DDouble position) { return false; }
384  virtual void MovePickbox(wxPoint2DDouble position) {}
389  virtual wxCursor GetBestPickboxCursor() const { return wxCURSOR_ARROW; }
393  virtual void ResetPickboxes() { m_activePickboxID = ID_PB_NONE; }
397  virtual void ResetNodes() { m_activeNodeID = 0; }
405  virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble translation,
406  double scale,
407  double offsetX = 0.0,
408  double offsetY = 0.0) const;
409 
418  virtual wxPoint2DDouble WorldToScreen(wxPoint2DDouble position,
419  wxPoint2DDouble translation,
420  double scale,
421  double offsetX = 0.0,
422  double offsetY = 0.0) const;
423 
431  virtual bool RotatedRectanglesIntersects(wxRect2DDouble rect1,
432  wxRect2DDouble rect2,
433  double angle1,
434  double angle2) const;
435 
443  virtual void DrawCircle(wxPoint2DDouble position, double radius, int numSegments, GLenum mode = GL_LINE_LOOP) const;
444  virtual void DrawArc(wxPoint2DDouble position,
445  double radius,
446  double initAngle,
447  double finalAngle,
448  int numSegments,
449  GLenum mode = GL_LINE_LOOP) const;
450 
458  virtual void DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode = GL_QUADS) const;
459 
465  virtual void DrawRectangle(wxPoint2DDouble* points, GLenum mode = GL_QUADS) const;
466 
472  virtual void DrawTriangle(std::vector<wxPoint2DDouble> points, GLenum mode = GL_TRIANGLES) const;
473 
479  virtual void DrawPoint(wxPoint2DDouble position, double size) const;
480 
486  virtual void DrawLine(std::vector<wxPoint2DDouble> points, GLenum mode = GL_LINE_STRIP) const;
487 
492  virtual void DrawPickbox(wxPoint2DDouble position) const;
493 
500  virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees = true) const;
501 
506  virtual std::vector<Element*> GetParentList() const { return m_parentList; }
511  virtual std::vector<Element*> GetChildList() const { return m_childList; }
512  // virtual wxPoint2DDouble GetMoveStartPosition() const { return m_moveStartPt; }
513  // virtual wxPoint2DDouble GetMovePosition() const { return m_movePos; }
514 
520  virtual void CalculateBoundaries(wxPoint2DDouble& leftUp, wxPoint2DDouble& rightBottom) const;
521 
526  virtual void GeneralMenuItens(wxMenu& menu);
527 
534  virtual bool ShowForm(wxWindow* parent, Element* element) { return false; }
542  static bool DoubleFromString(wxWindow* parent, wxString strValue, double& value, wxString errorMsg);
543 
551  static bool IntFromString(wxWindow* parent, wxString strValue, int& value, wxString errorMsg);
552 
558  static wxString StringFromDouble(double value, int minDecimal = 1);
559 
566  virtual double PointToLineDistance(wxPoint2DDouble point, int* segmentNumber = NULL) const;
567 
568  protected:
569  int m_elementID = 0;
570  std::vector<Element*> m_parentList;
571  std::vector<Element*> m_childList;
572 
573  wxRect2DDouble m_rect;
574  wxPoint2DDouble m_position;
575  double m_width = 0.0;
576  double m_height = 0.0;
577  double m_angle = 0.0;
578  double m_borderSize = 2.0;
579  double m_rotationAngle = 45.0;
580  double m_switchSize = 10.0;
581 
582  std::vector<wxRect2DDouble> m_switchRect;
583 
584  bool m_selected = false;
585  bool m_dragging = false;
586  bool m_showPickbox = false;
587 
588  int m_activePickboxID = ID_PB_NONE;
589  int m_activeNodeID = 0;
590 
591  std::vector<wxPoint2DDouble> m_pointList;
592  std::vector<wxPoint2DDouble> m_movePts;
593 
594  wxPoint2DDouble m_moveStartPt;
595  wxPoint2DDouble m_movePos;
596 
597  bool m_online = true;
598 
599  OpenGLColour m_selectionColour;
600 };
601 
602 #endif // ELEMENT_H
double GetAngle() const
Get the element angle.
Definition: Element.h:212
void ShowPickbox(bool showPickbox=true)
Set if the pickbox is shown.
Definition: Element.h:161
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
Definition: Element.h:318
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
void SetSelected(bool selected=true)
Set element selection.
Definition: Element.h:146
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
void SetWidth(double width)
Set element width.
Definition: Element.h:151
@@ -134,7 +134,7 @@ $(document).ready(function(){initNavTree('_element_8h_source.html','');});
void SetBorderSize(double borderSize)
Set the size of the border (shown in selected elements).
Definition: Element.h:166
PickboxID
ID of the pickbox.
Definition: Element.h:37
bool IsSelected() const
Checks if the element is selected.
Definition: Element.h:202
- +
Class to manage color of OpenGL.
Definition: Element.h:67
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition: Element.h:372
diff --git a/docs/doxygen/html/_element_data_object_8cpp_source.html b/docs/doxygen/html/_element_data_object_8cpp_source.html index 6ce0314..273056d 100644 --- a/docs/doxygen/html/_element_data_object_8cpp_source.html +++ b/docs/doxygen/html/_element_data_object_8cpp_source.html @@ -88,9 +88,10 @@ $(document).ready(function(){initNavTree('_element_data_object_8cpp_source.html'
ElementDataObject.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ElementDataObject.h"
19 
20 ElementDataObject::ElementDataObject() : wxDataObjectSimple(wxDataFormat("PSPCopy"))
21 {
22  m_elementsLists = new ElementsLists();
23 }
24 
25 ElementDataObject::ElementDataObject(std::vector<Element*> elementList) : wxDataObjectSimple(wxDataFormat("PSPCopy"))
26 {
27  m_elementsLists = new ElementsLists();
28  if(elementList.size() > 0) {
29  // Separate buses (parents) from the rest of the elements (childs).
30  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
31  Element* copy = (*it)->GetCopy();
32  if(copy) {
33  if(Bus* bus = dynamic_cast<Bus*>(copy))
34  m_elementsLists->parentList.push_back(bus);
35  else
36  m_elementsLists->elementList.push_back(copy);
37  }
38  }
39  }
40 }
41 
42 ElementDataObject::~ElementDataObject() {}
43 size_t ElementDataObject::GetDataSize() const { return sizeof(void*); }
44 bool ElementDataObject::GetDataHere(void* buf) const
45 {
46  *(ElementsLists**)buf = m_elementsLists;
47  return true;
48 }
49 
50 bool ElementDataObject::SetData(size_t len, const void* buf)
51 {
52  m_elementsLists = *(ElementsLists**)buf;
53  return true;
54 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ElementDataObject.h"
19 
20 ElementDataObject::ElementDataObject() : wxDataObjectSimple(wxDataFormat("PSPCopy"))
21 {
22  m_elementsLists = new ElementsLists();
23 }
24 
25 ElementDataObject::ElementDataObject(std::vector<Element*> elementList) : wxDataObjectSimple(wxDataFormat("PSPCopy"))
26 {
27  m_elementsLists = new ElementsLists();
28  if(elementList.size() > 0) {
29  // Separate buses (parents) from the rest of the elements (childs).
30  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
31  Element* copy = (*it)->GetCopy();
32  if(copy) {
33  if(Bus* bus = dynamic_cast<Bus*>(copy))
34  m_elementsLists->parentList.push_back(bus);
35  else
36  m_elementsLists->elementList.push_back(copy);
37  }
38  }
39  }
40 }
41 
42 ElementDataObject::~ElementDataObject() {}
43 size_t ElementDataObject::GetDataSize() const { return sizeof(void*); }
44 bool ElementDataObject::GetDataHere(void* buf) const
45 {
46  *(ElementsLists**)buf = m_elementsLists;
47  return true;
48 }
49 
50 bool ElementDataObject::SetData(size_t len, const void* buf)
51 {
52  m_elementsLists = *(ElementsLists**)buf;
53  return true;
54 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
+
virtual Element * GetCopy()
Get a the element copy.
Definition: Element.h:262
diff --git a/docs/doxygen/html/_element_data_object_8h.html b/docs/doxygen/html/_element_data_object_8h.html new file mode 100644 index 0000000..7c9b487 --- /dev/null +++ b/docs/doxygen/html/_element_data_object_8h.html @@ -0,0 +1,118 @@ + + + + + + + + + +Project/ElementDataObject.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
ElementDataObject.h File Reference
+
+
+
#include "Workspace.h"
+#include <wx/dataobj.h>
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  ElementsLists
 
class  ElementDataObject
 Class to store the elements in the clipboard. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_element_data_object_8h_source.html b/docs/doxygen/html/_element_data_object_8h_source.html index 99ab853..d709e22 100644 --- a/docs/doxygen/html/_element_data_object_8h_source.html +++ b/docs/doxygen/html/_element_data_object_8h_source.html @@ -88,15 +88,15 @@ $(document).ready(function(){initNavTree('_element_data_object_8h_source.html','
ElementDataObject.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELEMENTDATAOBJECT_H
19 #define ELEMENTDATAOBJECT_H
20 
21 #include "Workspace.h"
22 #include <wx/dataobj.h>
23 
24 struct ElementsLists {
25  std::vector<Element*> elementList;
26  std::vector<Bus*> parentList;
27 };
28 
29 class ElementDataObject : public wxDataObjectSimple
30 {
31  public:
33  ElementDataObject(std::vector<Element*> elementList);
35 
36  size_t GetDataSize() const override;
37  bool GetDataHere(void* buf) const override;
38  bool SetData(size_t len, const void* buf) override;
39 
40  ElementsLists* GetElementsLists() { return m_elementsLists; }
41  protected:
42  ElementsLists* m_elementsLists = NULL;
43 };
44 
45 #endif // ELEMENTDATAOBJECT_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELEMENTDATAOBJECT_H
19 #define ELEMENTDATAOBJECT_H
20 
21 #include "Workspace.h"
22 #include <wx/dataobj.h>
23 
24 struct ElementsLists {
25  std::vector<Element*> elementList;
26  std::vector<Bus*> parentList;
27 };
28 
36 class ElementDataObject : public wxDataObjectSimple
37 {
38  public:
40  ElementDataObject(std::vector<Element*> elementList);
42 
43  size_t GetDataSize() const override;
44  bool GetDataHere(void* buf) const override;
45  bool SetData(size_t len, const void* buf) override;
46 
47  ElementsLists* GetElementsLists() { return m_elementsLists; }
48  protected:
49  ElementsLists* m_elementsLists = NULL;
50 };
51 
52 #endif // ELEMENTDATAOBJECT_H
- +
Class to store the elements in the clipboard.
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ElementPlotData.h"
19 
20 ElementPlotData::ElementPlotData(wxString name, CurveType curveType)
21 {
22  m_name = name;
23  m_curveType = curveType;
24 }
25 
26 ElementPlotData::~ElementPlotData() {}
27 void ElementPlotData::AddData(std::vector<double> values, wxString name)
28 {
29  PlotData* data = new PlotData();
30  data->SetName(name);
31  data->SetValues(values);
32  data->SetPlot(false);
33  data->SetAxis(0);
34  data->SetColour(*wxBLACK);
35  data->SetPenType(wxPENSTYLE_SOLID);
36  data->SetThick(2);
37 
38  m_elementData.push_back(data);
39 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ElementPlotData.h"
19 
20 ElementPlotData::ElementPlotData(wxString name, CurveType curveType)
21 {
22  m_name = name;
23  m_curveType = curveType;
24 }
25 
26 ElementPlotData::~ElementPlotData() {}
27 void ElementPlotData::AddData(std::vector<double> values, wxString name)
28 {
29  PlotData* data = new PlotData();
30  data->SetName(name);
31  data->SetValues(values);
32  data->SetPlot(false);
33  data->SetAxis(0);
34  data->SetColour(*wxBLACK);
35  data->SetPenType(wxPENSTYLE_SOLID);
36  data->SetThick(2);
37 
38  m_elementData.push_back(data);
39 }
+
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...
diff --git a/docs/doxygen/html/_element_plot_data_8h.html b/docs/doxygen/html/_element_plot_data_8h.html new file mode 100644 index 0000000..efd1791 --- /dev/null +++ b/docs/doxygen/html/_element_plot_data_8h.html @@ -0,0 +1,120 @@ + + + + + + + + + +Project/ElementPlotData.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
ElementPlotData.h File Reference
+
+
+
#include <wx/treectrl.h>
+#include <wx/colour.h>
+#include <wx/pen.h>
+#include <vector>
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

class  PlotData
 This class is responsible to manage the graphical data of electromechanical result to be plotted on chart viewer. More...
 
class  ElementPlotData
 
+
+
+ + + + diff --git a/docs/doxygen/html/_element_plot_data_8h_source.html b/docs/doxygen/html/_element_plot_data_8h_source.html index 2d65d02..b86375d 100644 --- a/docs/doxygen/html/_element_plot_data_8h_source.html +++ b/docs/doxygen/html/_element_plot_data_8h_source.html @@ -88,14 +88,14 @@ $(document).ready(function(){initNavTree('_element_plot_data_8h_source.html','')
ElementPlotData.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELEMENTPLOTDATA_H
19 #define ELEMENTPLOTDATA_H
20 
21 #include <wx/treectrl.h>
22 #include <wx/colour.h>
23 #include <wx/pen.h>
24 
25 #include <vector>
26 
27 class PlotData : public wxTreeItemData
28 {
29  public:
30  PlotData() {}
31  ~PlotData() {}
32  void SetAxis(int axis) { m_axis = axis; }
33  void SetColour(const wxColour& colour) { m_colour = colour; }
34  void SetName(const wxString& name) { m_name = name; }
35  void SetPenType(const wxPenStyle& penType) { m_penType = penType; }
36  void SetPlot(bool plot) { m_plot = plot; }
37  void SetThick(int thick) { m_thick = thick; }
38  void SetValues(const std::vector<double>& values) { m_values = values; }
39  int GetAxis() const { return m_axis; }
40  wxColour GetColour() const { return m_colour; }
41  wxString GetName() const { return m_name; }
42  wxPenStyle GetPenType() const { return m_penType; }
43  bool IsPlot() const { return m_plot; }
44  int GetThick() const { return m_thick; }
45  std::vector<double> GetValues() const { return m_values; }
46  protected:
47  std::vector<double> m_values;
48  wxString m_name;
49  bool m_plot;
50  wxColour m_colour;
51  int m_thick;
52  wxPenStyle m_penType;
53  int m_axis;
54 };
55 
57 {
58  public:
59  enum CurveType {
60  CT_BUS = 0,
61  CT_SYNC_GENERATOR,
62  CT_SYNC_COMPENSATOR,
63  CT_TRANSFORMER,
64  CT_LINE,
65  CT_IND_MOTOR,
66  CT_SHUNT_INDUCTOR,
67  CT_SHUNT_CAPACITOR,
68  CT_LOAD,
69  CT_TEST,
70  NUM_ELEMENTS,
71  CT_TIME
72  };
73  ElementPlotData(){};
74  ElementPlotData(wxString name, CurveType curveType);
75  ~ElementPlotData();
76 
77  wxString GetName() const { return m_name; }
78  void SetName(wxString name) { m_name = name; }
79  CurveType GetCurveType() const { return m_curveType; }
80  void SetCurveType(CurveType type) { m_curveType = type; }
81  PlotData* GetPlotData(int index) const { return m_elementData[index]; }
82  void AddData(std::vector<double> values, wxString name);
83 
84  int GetElementDataNumber() const { return static_cast<int>(m_elementData.size()); }
85  std::vector<double> GetValues(int index) const { return m_elementData[index]->GetValues(); }
86  void SetValues(int index, std::vector<double> values) { m_elementData[index]->SetValues(values); }
87  void SetPlot(int index, bool plot = true) { m_elementData[index]->SetPlot(plot); }
88  wxString GetDataName(int index) const { return m_elementData[index]->GetName(); }
89  void SetDataName(int index, wxString name) { m_elementData[index]->SetName(name); }
90  wxColour GetColour(int index) const { return m_elementData[index]->GetColour(); }
91  void SetColour(int index, wxColour colour) { m_elementData[index]->SetColour(colour); }
92  int GetThick(int index) const { return m_elementData[index]->GetThick(); }
93  void SetThick(int index, int thick) { m_elementData[index]->SetThick(thick); }
94  wxPenStyle GetPenType(int index) const { return m_elementData[index]->GetPenType(); }
95  void SetPenType(int index, wxPenStyle penType) { m_elementData[index]->SetPenType(penType); }
96  int GetAxis(int index) const { return m_elementData[index]->GetAxis(); }
97  void SetAxis(int index, int axis) { m_elementData[index]->SetAxis(axis); }
98  protected:
99  wxString m_name;
100  CurveType m_curveType;
101  std::vector<PlotData*> m_elementData;
102 };
103 
104 #endif // ELEMENTPLOTDATA_H
- +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ELEMENTPLOTDATA_H
19 #define ELEMENTPLOTDATA_H
20 
21 #include <wx/treectrl.h>
22 #include <wx/colour.h>
23 #include <wx/pen.h>
24 
25 #include <vector>
26 
35 class PlotData : public wxTreeItemData
36 {
37  public:
38  PlotData() {}
39  ~PlotData() {}
40  void SetAxis(int axis) { m_axis = axis; }
41  void SetColour(const wxColour& colour) { m_colour = colour; }
42  void SetName(const wxString& name) { m_name = name; }
43  void SetPenType(const wxPenStyle& penType) { m_penType = penType; }
44  void SetPlot(bool plot) { m_plot = plot; }
45  void SetThick(int thick) { m_thick = thick; }
46  void SetValues(const std::vector<double>& values) { m_values = values; }
47  int GetAxis() const { return m_axis; }
48  wxColour GetColour() const { return m_colour; }
49  wxString GetName() const { return m_name; }
50  wxPenStyle GetPenType() const { return m_penType; }
51  bool IsPlot() const { return m_plot; }
52  int GetThick() const { return m_thick; }
53  std::vector<double> GetValues() const { return m_values; }
54  protected:
55  std::vector<double> m_values;
56  wxString m_name;
57  bool m_plot;
58  wxColour m_colour;
59  int m_thick;
60  wxPenStyle m_penType;
61  int m_axis;
62 };
63 
65 {
66  public:
67  enum CurveType {
68  CT_BUS = 0,
69  CT_SYNC_GENERATOR,
70  CT_SYNC_COMPENSATOR,
71  CT_TRANSFORMER,
72  CT_LINE,
73  CT_IND_MOTOR,
74  CT_SHUNT_INDUCTOR,
75  CT_SHUNT_CAPACITOR,
76  CT_LOAD,
77  CT_TEST,
78  NUM_ELEMENTS,
79  CT_TIME
80  };
81  ElementPlotData(){};
82  ElementPlotData(wxString name, CurveType curveType);
83  ~ElementPlotData();
84 
85  wxString GetName() const { return m_name; }
86  void SetName(wxString name) { m_name = name; }
87  CurveType GetCurveType() const { return m_curveType; }
88  void SetCurveType(CurveType type) { m_curveType = type; }
89  PlotData* GetPlotData(int index) const { return m_elementData[index]; }
90  void AddData(std::vector<double> values, wxString name);
91 
92  int GetElementDataNumber() const { return static_cast<int>(m_elementData.size()); }
93  std::vector<double> GetValues(int index) const { return m_elementData[index]->GetValues(); }
94  void SetValues(int index, std::vector<double> values) { m_elementData[index]->SetValues(values); }
95  void SetPlot(int index, bool plot = true) { m_elementData[index]->SetPlot(plot); }
96  wxString GetDataName(int index) const { return m_elementData[index]->GetName(); }
97  void SetDataName(int index, wxString name) { m_elementData[index]->SetName(name); }
98  wxColour GetColour(int index) const { return m_elementData[index]->GetColour(); }
99  void SetColour(int index, wxColour colour) { m_elementData[index]->SetColour(colour); }
100  int GetThick(int index) const { return m_elementData[index]->GetThick(); }
101  void SetThick(int index, int thick) { m_elementData[index]->SetThick(thick); }
102  wxPenStyle GetPenType(int index) const { return m_elementData[index]->GetPenType(); }
103  void SetPenType(int index, wxPenStyle penType) { m_elementData[index]->SetPenType(penType); }
104  int GetAxis(int index) const { return m_elementData[index]->GetAxis(); }
105  void SetAxis(int index, int axis) { m_elementData[index]->SetAxis(axis); }
106  protected:
107  wxString m_name;
108  CurveType m_curveType;
109  std::vector<PlotData*> m_elementData;
110 };
111 
112 #endif // ELEMENTPLOTDATA_H
+
This class is responsible to manage the graphical data of electromechanical result to be plotted on c...
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Exponential.h"
19 #include "ExponentialForm.h"
20 
21 Exponential::Exponential(int id) : ControlElement(id)
22 {
23  m_width = m_height = 36.0;
24  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize);
25  nodeIn->StartMove(m_position);
26  Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
27  nodeOut->SetAngle(180.0);
28  nodeOut->StartMove(m_position);
29  m_nodeList.push_back(nodeIn);
30  m_nodeList.push_back(nodeOut);
31 }
32 
33 Exponential::~Exponential() {}
34 void Exponential::Draw(wxPoint2DDouble translation, double scale) const
35 {
36  glLineWidth(1.0);
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
41  }
42  glColor4d(1.0, 1.0, 1.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
46 
47  // Plot symbol.
48  std::vector<wxPoint2DDouble> axis;
49  axis.push_back(m_position + wxPoint2DDouble(-13, 13));
50  axis.push_back(m_position + wxPoint2DDouble(13, 13));
51  axis.push_back(m_position + wxPoint2DDouble(-13, -13));
52  axis.push_back(m_position + wxPoint2DDouble(-13, 13));
53  DrawLine(axis, GL_LINES);
54 
55  glLineWidth(2.0);
56  std::vector<wxPoint2DDouble> expSymbol;
57  expSymbol.push_back(m_position + wxPoint2DDouble(-13, 13));
58  expSymbol.push_back(m_position + wxPoint2DDouble(-6, 13));
59  expSymbol.push_back(m_position + wxPoint2DDouble(2, 12));
60  expSymbol.push_back(m_position + wxPoint2DDouble(4, 11));
61  expSymbol.push_back(m_position + wxPoint2DDouble(6, 10));
62  expSymbol.push_back(m_position + wxPoint2DDouble(8, 7));
63  expSymbol.push_back(m_position + wxPoint2DDouble(11, -1));
64  expSymbol.push_back(m_position + wxPoint2DDouble(12, -7));
65  expSymbol.push_back(m_position + wxPoint2DDouble(13, -13));
66  glColor4d(0.0, 0.3, 1.0, 1.0);
67  DrawLine(expSymbol);
68 
69  glColor4d(0.0, 0.0, 0.0, 1.0);
70  DrawNodes();
71 }
72 
73 bool Exponential::ShowForm(wxWindow* parent, Element* element)
74 {
75  ExponentialForm* form = new ExponentialForm(parent, this);
76  if(form->ShowModal() == wxID_OK) {
77  form->Destroy();
78  return true;
79  }
80  form->Destroy();
81  return false;
82 }
83 
84 void Exponential::Rotate(bool clockwise)
85 {
86  if(clockwise)
87  m_angle += 90.0;
88  else
89  m_angle -= 90.0;
90  if(m_angle >= 360.0)
91  m_angle = 0.0;
92  else if(m_angle < 0)
93  m_angle = 270.0;
94 
95  UpdatePoints();
96 
97  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
98  Node* node = *it;
99  node->Rotate(clockwise);
100  }
101 }
102 
103 void Exponential::UpdatePoints()
104 {
105  if(m_angle == 0.0) {
106  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
107  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(18, 0));
108  } else if(m_angle == 90.0) {
109  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -18));
110  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, 18));
111  } else if(m_angle == 180.0) {
112  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(18, 0));
113  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
114  } else if(m_angle == 270.0) {
115  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, 18));
116  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
117  }
118 }
119 
120 void Exponential::GetValues(double& aValue, double& bValue)
121 {
122  aValue = m_aValue;
123  bValue = m_bValue;
124 }
125 
126 void Exponential::SetValues(double aValue, double bValue)
127 {
128  m_aValue = aValue;
129  m_bValue = bValue;
130 }
131 
132 bool Exponential::Solve(double input, double timeStep)
133 {
134  m_output = m_aValue * std::exp(m_bValue * input);
135  return true;
136 }
137 
139 {
140  Exponential* copy = new Exponential(m_elementID);
141  *copy = *this;
142  return copy;
143 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Exponential.h"
19 #include "ExponentialForm.h"
20 
21 Exponential::Exponential(int id) : ControlElement(id)
22 {
23  m_width = m_height = 36.0;
24  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize);
25  nodeIn->StartMove(m_position);
26  Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
27  nodeOut->SetAngle(180.0);
28  nodeOut->StartMove(m_position);
29  m_nodeList.push_back(nodeIn);
30  m_nodeList.push_back(nodeOut);
31 }
32 
33 Exponential::~Exponential() {}
34 void Exponential::Draw(wxPoint2DDouble translation, double scale) const
35 {
36  glLineWidth(1.0);
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
41  }
42  glColor4d(1.0, 1.0, 1.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
46 
47  // Plot symbol.
48  std::vector<wxPoint2DDouble> axis;
49  axis.push_back(m_position + wxPoint2DDouble(-13, 13));
50  axis.push_back(m_position + wxPoint2DDouble(13, 13));
51  axis.push_back(m_position + wxPoint2DDouble(-13, -13));
52  axis.push_back(m_position + wxPoint2DDouble(-13, 13));
53  DrawLine(axis, GL_LINES);
54 
55  glLineWidth(2.0);
56  std::vector<wxPoint2DDouble> expSymbol;
57  expSymbol.push_back(m_position + wxPoint2DDouble(-13, 13));
58  expSymbol.push_back(m_position + wxPoint2DDouble(-6, 13));
59  expSymbol.push_back(m_position + wxPoint2DDouble(2, 12));
60  expSymbol.push_back(m_position + wxPoint2DDouble(4, 11));
61  expSymbol.push_back(m_position + wxPoint2DDouble(6, 10));
62  expSymbol.push_back(m_position + wxPoint2DDouble(8, 7));
63  expSymbol.push_back(m_position + wxPoint2DDouble(11, -1));
64  expSymbol.push_back(m_position + wxPoint2DDouble(12, -7));
65  expSymbol.push_back(m_position + wxPoint2DDouble(13, -13));
66  glColor4d(0.0, 0.3, 1.0, 1.0);
67  DrawLine(expSymbol);
68 
69  glColor4d(0.0, 0.0, 0.0, 1.0);
70  DrawNodes();
71 }
72 
73 bool Exponential::ShowForm(wxWindow* parent, Element* element)
74 {
75  ExponentialForm* form = new ExponentialForm(parent, this);
76  if(form->ShowModal() == wxID_OK) {
77  form->Destroy();
78  return true;
79  }
80  form->Destroy();
81  return false;
82 }
83 
84 void Exponential::Rotate(bool clockwise)
85 {
86  if(clockwise)
87  m_angle += 90.0;
88  else
89  m_angle -= 90.0;
90  if(m_angle >= 360.0)
91  m_angle = 0.0;
92  else if(m_angle < 0)
93  m_angle = 270.0;
94 
95  UpdatePoints();
96 
97  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
98  Node* node = *it;
99  node->Rotate(clockwise);
100  }
101 }
102 
103 void Exponential::UpdatePoints()
104 {
105  if(m_angle == 0.0) {
106  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
107  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(18, 0));
108  } else if(m_angle == 90.0) {
109  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -18));
110  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, 18));
111  } else if(m_angle == 180.0) {
112  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(18, 0));
113  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
114  } else if(m_angle == 270.0) {
115  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, 18));
116  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
117  }
118 }
119 
120 void Exponential::GetValues(double& aValue, double& bValue)
121 {
122  aValue = m_aValue;
123  bValue = m_bValue;
124 }
125 
126 void Exponential::SetValues(double aValue, double bValue)
127 {
128  m_aValue = aValue;
129  m_bValue = bValue;
130 }
131 
132 bool Exponential::Solve(double input, double timeStep)
133 {
134  m_output = m_aValue * std::exp(m_bValue * input);
135  return true;
136 }
137 
139 {
140  Exponential* copy = new Exponential(m_elementID);
141  *copy = *this;
142  return copy;
143 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Node of a control element. This class manages the user interaction with the connection and control el...
+
virtual bool Solve(double input, double timeStep)
Calculates the exponential.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Exponential.cpp:84
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Exponential.cpp:73
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Exponential.cpp:34
virtual Element * GetCopy()
Get a the element copy.
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
Form to edit the exponential control data.
diff --git a/docs/doxygen/html/_exponential_8h.html b/docs/doxygen/html/_exponential_8h.html index 9973de9..56fc1e9 100644 --- a/docs/doxygen/html/_exponential_8h.html +++ b/docs/doxygen/html/_exponential_8h.html @@ -97,7 +97,7 @@ $(document).ready(function(){initNavTree('_exponential_8h.html','');});

Classes

class  Exponential - Generates an output following an exponential function. \( output = A\cdot e^{B\cdot input} \). More...
+ Generates an output following an exponential function. More...
 
diff --git a/docs/doxygen/html/_exponential_8h_source.html b/docs/doxygen/html/_exponential_8h_source.html index 67cb366..429bace 100644 --- a/docs/doxygen/html/_exponential_8h_source.html +++ b/docs/doxygen/html/_exponential_8h_source.html @@ -88,15 +88,16 @@ $(document).ready(function(){initNavTree('_exponential_8h_source.html','');});
Exponential.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef EXPONENTIAL_H
19 #define EXPONENTIAL_H
20 
21 #include "ControlElement.h"
22 
23 class ExponentialForm;
24 
34 {
35  public:
36  Exponential(int id);
37  ~Exponential();
38 
39  virtual void Draw(wxPoint2DDouble translation, double scale) const;
40  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
41  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
42  virtual bool ShowForm(wxWindow* parent, Element* element);
43  virtual void Rotate(bool clockwise = true);
44 
45  virtual void UpdatePoints();
46 
47  virtual void GetValues(double& aValue, double& bValue);
48  virtual void SetValues(double aValue, double bValue);
49 
50  virtual bool Solve(double input, double timeStep);
51 
52  virtual Element* GetCopy();
53 
54  protected:
55  double m_aValue = 0.001;
56  double m_bValue = 5.0;
57 };
58 
59 #endif // EXPONENTIAL_H
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Exponential.h:40
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef EXPONENTIAL_H
19 #define EXPONENTIAL_H
20 
21 #include "ControlElement.h"
22 
23 class ExponentialForm;
24 
33 {
34  public:
35  Exponential(int id);
36  ~Exponential();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
40  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
41  virtual bool ShowForm(wxWindow* parent, Element* element);
42  virtual void Rotate(bool clockwise = true);
43 
44  virtual void UpdatePoints();
45 
46  virtual void GetValues(double& aValue, double& bValue);
47  virtual void SetValues(double aValue, double bValue);
48 
57  virtual bool Solve(double input, double timeStep);
58 
59  virtual Element* GetCopy();
60 
61  protected:
62  double m_aValue = 0.001;
63  double m_bValue = 5.0;
64 };
65 
66 #endif // EXPONENTIAL_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Exponential.h:39
+
virtual bool Solve(double input, double timeStep)
Calculates the exponential.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Exponential.cpp:84
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Exponential.cpp:73
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Exponential.cpp:34
virtual Element * GetCopy()
Get a the element copy.
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
Form to edit the exponential control data.
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Exponential.h:41
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Exponential.h:40
Base class of a control element. Provide general methods to other control classes.
diff --git a/docs/doxygen/html/_exponential_form_8cpp_source.html b/docs/doxygen/html/_exponential_form_8cpp_source.html index c506321..a4fb180 100644 --- a/docs/doxygen/html/_exponential_form_8cpp_source.html +++ b/docs/doxygen/html/_exponential_form_8cpp_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_exponential_form_8cpp_source.html',''
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "ExponentialForm.h"
19 #include "Exponential.h"
20 
21 ExponentialForm::ExponentialForm(wxWindow* parent, Exponential* exponential) : ExponentialFormBase(parent)
22 {
23  SetSize(GetBestSize());
24 
25  wxString expSymbol = wxString::FromUTF8("\xF0\x9D\x91\x92");
26  wxString superscriptCapitalB = wxString::FromUTF8("\xE1\xB4\xAE");
27  wxString superscriptSmallX = wxString::FromUTF8("\xCB\xA3");
28  m_staticTextExp->SetLabel("y = A" + expSymbol + superscriptCapitalB + superscriptSmallX);
29 
30  wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
31  font.SetPointSize(14);
32  m_staticTextExp->SetFont(font);
33 
34  m_parent = parent;
35  m_exponential = exponential;
36 
37  double a, b;
38  m_exponential->GetValues(a, b);
39  m_textCtrlAValue->SetValue(m_exponential->StringFromDouble(a));
40  m_textCtrlBValue->SetValue(m_exponential->StringFromDouble(b));
41 
42  SetInitialSize();
43  Layout();
44 }
45 
46 ExponentialForm::~ExponentialForm() {}
47 void ExponentialForm::OnOKButtonClick(wxCommandEvent& event)
48 {
49  if(ValidateData()) EndModal(wxID_OK);
50 }
51 
52 bool ExponentialForm::ValidateData()
53 {
54  double a, b;
55  if(!m_exponential->DoubleFromString(this, m_textCtrlAValue->GetValue(), a,
56  _("Value entered incorrectly in the field \"A value\".")))
57  return false;
58  if(!m_exponential->DoubleFromString(this, m_textCtrlBValue->GetValue(), b,
59  _("Value entered incorrectly in the field \"B value\".")))
60  return false;
61  m_exponential->SetValues(a, b);
62  return true;
63 }
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
diff --git a/docs/doxygen/html/_exponential_form_8h_source.html b/docs/doxygen/html/_exponential_form_8h_source.html index e042b3f..8f4f99e 100644 --- a/docs/doxygen/html/_exponential_form_8h_source.html +++ b/docs/doxygen/html/_exponential_form_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_exponential_form_8h_source.html','');
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef EXPONENTIALFORM_H
19 #define EXPONENTIALFORM_H
20 #include "ElementForm.h"
21 
22 class Exponential;
23 
32 {
33  public:
34  ExponentialForm(wxWindow* parent, Exponential* exponential);
35  virtual ~ExponentialForm();
36  virtual bool ValidateData();
37 
38  protected:
39  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
40  virtual void OnOKButtonClick(wxCommandEvent& event);
41 
42  wxWindow* m_parent = NULL;
43  Exponential* m_exponential = NULL;
44 };
45 #endif // EXPONENTIALFORM_H
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
Form to edit the exponential control data.
diff --git a/docs/doxygen/html/_fault_8cpp_source.html b/docs/doxygen/html/_fault_8cpp_source.html index 82d6523..d78a93d 100644 --- a/docs/doxygen/html/_fault_8cpp_source.html +++ b/docs/doxygen/html/_fault_8cpp_source.html @@ -92,28 +92,28 @@ $(document).ready(function(){initNavTree('_fault_8cpp_source.html','');});
Definition: PowerElement.h:59
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
FaultData
Information about fault (type and location).
Definition: PowerElement.h:55
-
+
Synchronous generator power element.
Definition: Bus.h:24
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
virtual bool RunFaultCalculation(double systemPowerBase)
Calculate the fault of the system. Return true if was possible the calculation.
Definition: Fault.cpp:26
Definition: PowerElement.h:60
Fault()
Default contructor. Use GetElementsFromList(std::vector<Element*> elementList).
Definition: Fault.cpp:23
Definition: PowerElement.h:57
Definition: PowerElement.h:56
-
Calculate the fault of the system and update the elements data.
+
virtual bool InvertMatrix(std::vector< std::vector< std::complex< double > > > matrix, std::vector< std::vector< std::complex< double > > > &inverse)
Invert a matrix.
-
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
virtual bool GetYBus(std::vector< std::vector< std::complex< double > > > &yBus, double systemPowerBase, YBusSequence sequence=POSITIVE_SEQ, bool includeSyncMachines=false, bool allLoadsAsImpedances=false)
Get the admittance matrix from the list of elements (use GetElementsFromList first).
-
Definition: SyncMotor.h:127
+
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
Definition: PowerElement.h:58
virtual bool RunSCPowerCalcutation(double systemPowerBase)
Calculate the short-circuit power of the system. Return true if was possible the calculation.
Definition: Fault.cpp:399
~Fault()
Destructor.
Definition: Fault.cpp:25
Definition: PowerElement.h:61
virtual void GetElementsFromList(std::vector< Element *> elementList)
Separate the power elements from a generic list.
-
+
Base class of electric calculations, with general methods.
virtual void UpdateElementsFault(double systemPowerBase)
Update the data of the elements.
Definition: Fault.cpp:193
-
Definition: Transformer.h:71
+
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_fault_8h.html b/docs/doxygen/html/_fault_8h.html index ecd4a49..c85b102 100644 --- a/docs/doxygen/html/_fault_8h.html +++ b/docs/doxygen/html/_fault_8h.html @@ -90,9 +90,6 @@ $(document).ready(function(){initNavTree('_fault_8h.html','');});
Fault.h File Reference
- -

Calculate the fault of the system and update the elements data. -More...

Go to the source code of this file.

@@ -100,13 +97,10 @@ $(document).ready(function(){initNavTree('_fault_8h.html','');});

Classes

class  Fault + Calculate the fault of the system and update the elements data. More...
  -

Detailed Description

-

Calculate the fault of the system and update the elements data.

- -

Definition in file Fault.h.

-
+
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef FAULT_H
19 #define FAULT_H
20 
21 #include "ElectricCalculation.h"
30 class Fault : public ElectricCalculation
31 {
32  public:
37  Fault(std::vector<Element*> elementList);
38 
42  Fault();
43 
47  ~Fault();
48 
53  virtual bool RunFaultCalculation(double systemPowerBase);
54 
59  virtual bool RunSCPowerCalcutation(double systemPowerBase);
60 
65  virtual void UpdateElementsFault(double systemPowerBase);
66 
71  virtual wxString GetErrorMessage() { return m_errorMsg; }
72  protected:
73  wxString m_errorMsg = "";
74 
75  double m_systemPowerBase;
76 
77  std::vector<std::vector<std::complex<double> > > m_zBusPos;
78  std::vector<std::vector<std::complex<double> > > m_zBusNeg;
79  std::vector<std::vector<std::complex<double> > > m_zBusZero;
80 
81  std::vector<std::complex<double> > m_posFaultVoltagePos;
82  std::vector<std::complex<double> > m_posFaultVoltageNeg;
83  std::vector<std::complex<double> > m_posFaultVoltageZero;
84 
85  std::complex<double> m_fCurrentA;
86  std::complex<double> m_fCurrentB;
87  std::complex<double> m_fCurrentC;
88 
89  std::vector<std::complex<double> > m_posFaultVoltageA;
90  std::vector<std::complex<double> > m_posFaultVoltageB;
91  std::vector<std::complex<double> > m_posFaultVoltageC;
92 };
93 
94 #endif // FAULT_H
Base class of electric calculations, with general methods.
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef FAULT_H
19 #define FAULT_H
20 
21 #include "ElectricCalculation.h"
30 class Fault : public ElectricCalculation
31 {
32  public:
37  Fault(std::vector<Element*> elementList);
38 
42  Fault();
43 
47  ~Fault();
48 
53  virtual bool RunFaultCalculation(double systemPowerBase);
54 
59  virtual bool RunSCPowerCalcutation(double systemPowerBase);
60 
65  virtual void UpdateElementsFault(double systemPowerBase);
66 
71  virtual wxString GetErrorMessage() { return m_errorMsg; }
72  protected:
73  wxString m_errorMsg = "";
74 
75  double m_systemPowerBase;
76 
77  std::vector<std::vector<std::complex<double> > > m_zBusPos;
78  std::vector<std::vector<std::complex<double> > > m_zBusNeg;
79  std::vector<std::vector<std::complex<double> > > m_zBusZero;
80 
81  std::vector<std::complex<double> > m_posFaultVoltagePos;
82  std::vector<std::complex<double> > m_posFaultVoltageNeg;
83  std::vector<std::complex<double> > m_posFaultVoltageZero;
84 
85  std::complex<double> m_fCurrentA;
86  std::complex<double> m_fCurrentB;
87  std::complex<double> m_fCurrentC;
88 
89  std::vector<std::complex<double> > m_posFaultVoltageA;
90  std::vector<std::complex<double> > m_posFaultVoltageB;
91  std::vector<std::complex<double> > m_posFaultVoltageC;
92 };
93 
94 #endif // FAULT_H
virtual wxString GetErrorMessage()
Get the error message generated in RunFaultCalculation(double systemPowerBase).
Definition: Fault.h:71
virtual bool RunFaultCalculation(double systemPowerBase)
Calculate the fault of the system. Return true if was possible the calculation.
Definition: Fault.cpp:26
Fault()
Default contructor. Use GetElementsFromList(std::vector<Element*> elementList).
Definition: Fault.cpp:23
-
Definition: Fault.h:30
+
Calculate the fault of the system and update the elements data.
Definition: Fault.h:30
virtual bool RunSCPowerCalcutation(double systemPowerBase)
Calculate the short-circuit power of the system. Return true if was possible the calculation.
Definition: Fault.cpp:399
~Fault()
Destructor.
Definition: Fault.cpp:25
- +
Base class of electric calculations, with general methods.
virtual void UpdateElementsFault(double systemPowerBase)
Update the data of the elements.
Definition: Fault.cpp:193
diff --git a/docs/doxygen/html/_file_handing_8cpp_source.html b/docs/doxygen/html/_file_handing_8cpp_source.html index 983eb4f..5f11b75 100644 --- a/docs/doxygen/html/_file_handing_8cpp_source.html +++ b/docs/doxygen/html/_file_handing_8cpp_source.html @@ -89,20 +89,20 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "FileHanding.h"
19 
20 FileHanding::~FileHanding() {}
21 FileHanding::FileHanding(Workspace* workspace) { m_workspace = workspace; }
22 FileHanding::FileHanding(ControlEditor* controlEditor) { m_controlEditor = controlEditor; }
23 FileHanding::FileHanding() {}
24 void FileHanding::SaveProject(wxFileName path)
25 {
26  // Erase the file (if exists or not) and write the initial data
27  std::ofstream writeProjectsFile(path.GetFullPath());
28  writeProjectsFile.close();
29 
30  rapidxml::xml_document<> doc;
31  rapidxml::file<> xmlFile(path.GetFullPath().mb_str());
32  doc.parse<0>(xmlFile.data());
33 
34  rapidxml::xml_node<>* decl = doc.allocate_node(rapidxml::node_declaration);
35  rapidxml::xml_attribute<>* ver = doc.allocate_attribute("version", "1.0");
36  rapidxml::xml_attribute<>* encoding = doc.allocate_attribute("encoding", "utf-8");
37  decl->append_attribute(ver);
38  decl->append_attribute(encoding);
39  doc.append_node(decl);
40 
41  rapidxml::xml_node<>* rootNode = doc.allocate_node(rapidxml::node_element, "Project");
42  doc.append_node(rootNode);
43 
44  rapidxml::xml_node<>* projectNameNode = AppendNode(doc, rootNode, "Name");
45  SetNodeValue(doc, projectNameNode, path.GetName());
46 
47  auto elementsNode = AppendNode(doc, rootNode, "Elements");
48 
49  // Save all the data
50  ElectricCalculation allElements;
51  allElements.GetElementsFromList(m_workspace->GetElementList());
52 
53  //{ Buses
54  auto busesNode = AppendNode(doc, elementsNode, "BusList");
55  auto busList = allElements.GetBusList();
56  for(int i = 0; i < (int)busList.size(); i++) {
57  Bus* bus = busList[i];
58  auto busNode = AppendNode(doc, busesNode, "Bus");
59  SetNodeAttribute(doc, busNode, "ID", i);
60  auto cadProp = AppendNode(doc, busNode, "CADProperties");
61  auto position = AppendNode(doc, cadProp, "Position");
62  auto posX = AppendNode(doc, position, "X");
63  SetNodeValue(doc, posX, bus->GetPosition().m_x);
64  auto posY = AppendNode(doc, position, "Y");
65  SetNodeValue(doc, posY, bus->GetPosition().m_y);
66  auto size = AppendNode(doc, cadProp, "Size");
67  auto width = AppendNode(doc, size, "Width");
68  SetNodeValue(doc, width, bus->GetWidth());
69  auto height = AppendNode(doc, size, "Height");
70  SetNodeValue(doc, height, bus->GetHeight());
71  auto angle = AppendNode(doc, cadProp, "Angle");
72  SetNodeValue(doc, angle, bus->GetAngle());
73 
74  BusElectricalData data = bus->GetElectricalData();
75  auto electricalProp = AppendNode(doc, busNode, "ElectricalProperties");
76  auto name = AppendNode(doc, electricalProp, "Name");
77  SetNodeValue(doc, name, data.name);
78  auto nominalVoltage = AppendNode(doc, electricalProp, "NominalVoltage");
79  SetNodeValue(doc, nominalVoltage, data.nominalVoltage);
80  SetNodeAttribute(doc, nominalVoltage, "UnitID", data.nominalVoltageUnit);
81  auto isVoltageControlled = AppendNode(doc, electricalProp, "IsVoltageControlled");
82  SetNodeValue(doc, isVoltageControlled, data.isVoltageControlled);
83  auto controlledVoltage = AppendNode(doc, electricalProp, "ControlledVoltage");
84  SetNodeValue(doc, controlledVoltage, data.controlledVoltage);
85  SetNodeAttribute(doc, controlledVoltage, "Choice", data.controlledVoltageUnitChoice);
86  auto slackBus = AppendNode(doc, electricalProp, "SlackBus");
87  SetNodeValue(doc, slackBus, data.slackBus);
88 
89  auto fault = AppendNode(doc, electricalProp, "Fault");
90  auto hasFault = AppendNode(doc, fault, "HasFault");
91  SetNodeValue(doc, hasFault, data.hasFault);
92  auto faultType = AppendNode(doc, fault, "Type");
93  SetNodeValue(doc, faultType, data.faultType);
94  auto faultLocation = AppendNode(doc, fault, "Location");
95  SetNodeValue(doc, faultLocation, data.faultLocation);
96  auto faultResistance = AppendNode(doc, fault, "Resistance");
97  SetNodeValue(doc, faultResistance, data.faultResistance);
98  auto faultReactance = AppendNode(doc, fault, "Reactance");
99  SetNodeValue(doc, faultReactance, data.faultReactance);
100 
101  auto stability = AppendNode(doc, electricalProp, "Stability");
102  auto plotBus = AppendNode(doc, stability, "Plot");
103  SetNodeValue(doc, plotBus, data.plotBus);
104  auto stabHasFault = AppendNode(doc, stability, "HasFault");
105  SetNodeValue(doc, stabHasFault, data.stabHasFault);
106  auto stabFaultTime = AppendNode(doc, stability, "FaultTime");
107  SetNodeValue(doc, stabFaultTime, data.stabFaultTime);
108  auto stabFaultLength = AppendNode(doc, stability, "FaultLength");
109  SetNodeValue(doc, stabFaultLength, data.stabFaultLength);
110  auto stabFaultResistance = AppendNode(doc, stability, "FaultResistance");
111  SetNodeValue(doc, stabFaultResistance, data.stabFaultResistance);
112  auto stabFaultReactance = AppendNode(doc, stability, "FaultReactance");
113  SetNodeValue(doc, stabFaultReactance, data.stabFaultReactance);
114 
115  data.number = i;
116  bus->SetElectricalData(data);
117  } //}
118 
119  //{ Capacitor
120  auto capacitorsNode = AppendNode(doc, elementsNode, "CapacitorList");
121  auto capacitorList = allElements.GetCapacitorList();
122  for(int i = 0; i < (int)capacitorList.size(); i++) {
123  Capacitor* capacitor = capacitorList[i];
124  auto capacitorNode = AppendNode(doc, capacitorsNode, "Capacitor");
125  SetNodeAttribute(doc, capacitorNode, "ID", i);
126  auto cadProp = AppendNode(doc, capacitorNode, "CADProperties");
127  auto position = AppendNode(doc, cadProp, "Position");
128  auto posX = AppendNode(doc, position, "X");
129  SetNodeValue(doc, posX, capacitor->GetPosition().m_x);
130  auto posY = AppendNode(doc, position, "Y");
131  SetNodeValue(doc, posY, capacitor->GetPosition().m_y);
132  auto size = AppendNode(doc, cadProp, "Size");
133  auto width = AppendNode(doc, size, "Width");
134  SetNodeValue(doc, width, capacitor->GetWidth());
135  auto height = AppendNode(doc, size, "Height");
136  SetNodeValue(doc, height, capacitor->GetHeight());
137  auto angle = AppendNode(doc, cadProp, "Angle");
138  SetNodeValue(doc, angle, capacitor->GetAngle());
139  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
140  auto nodePosX = AppendNode(doc, nodePos, "X");
141  SetNodeValue(doc, nodePosX, capacitor->GetPointList()[0].m_x);
142  auto nodePosY = AppendNode(doc, nodePos, "Y");
143  SetNodeValue(doc, nodePosY, capacitor->GetPointList()[0].m_y);
144  auto parentID = AppendNode(doc, cadProp, "ParentID");
145  Bus* parent = static_cast<Bus*>(capacitor->GetParentList()[0]);
146  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
147 
148  CapacitorElectricalData data = capacitor->GetElectricalData();
149  auto electricalProp = AppendNode(doc, capacitorNode, "ElectricalProperties");
150  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
151  SetNodeValue(doc, isOnline, capacitor->IsOnline());
152  auto name = AppendNode(doc, electricalProp, "Name");
153  SetNodeValue(doc, name, data.name);
154  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
155  SetNodeValue(doc, reactivePower, data.reactivePower);
156  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
157 
158  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
159  SwitchingData swData = capacitor->GetSwitchingData();
160  for(int j = 0; j < (int)swData.swType.size(); j++) {
161  auto switching = AppendNode(doc, switchingList, "Switching");
162  SetNodeAttribute(doc, switching, "ID", j);
163  auto swType = AppendNode(doc, switching, "Type");
164  SetNodeValue(doc, swType, swData.swType[j]);
165  auto swTime = AppendNode(doc, switching, "Time");
166  SetNodeValue(doc, swTime, swData.swTime[j]);
167  }
168  } //}
169 
170  //{ IndMotor
171  auto indMotorsNode = AppendNode(doc, elementsNode, "IndMotorList");
172  auto indMotorList = allElements.GetIndMotorList();
173  for(int i = 0; i < (int)indMotorList.size(); i++) {
174  IndMotor* indMotor = indMotorList[i];
175  auto indMotorNode = AppendNode(doc, indMotorsNode, "IndMotor");
176  SetNodeAttribute(doc, indMotorNode, "ID", i);
177  auto cadProp = AppendNode(doc, indMotorNode, "CADProperties");
178  auto position = AppendNode(doc, cadProp, "Position");
179  auto posX = AppendNode(doc, position, "X");
180  SetNodeValue(doc, posX, indMotor->GetPosition().m_x);
181  auto posY = AppendNode(doc, position, "Y");
182  SetNodeValue(doc, posY, indMotor->GetPosition().m_y);
183  auto size = AppendNode(doc, cadProp, "Size");
184  auto width = AppendNode(doc, size, "Width");
185  SetNodeValue(doc, width, indMotor->GetWidth());
186  auto height = AppendNode(doc, size, "Height");
187  SetNodeValue(doc, height, indMotor->GetHeight());
188  auto angle = AppendNode(doc, cadProp, "Angle");
189  SetNodeValue(doc, angle, indMotor->GetAngle());
190  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
191  auto nodePosX = AppendNode(doc, nodePos, "X");
192  SetNodeValue(doc, nodePosX, indMotor->GetPointList()[0].m_x);
193  auto nodePosY = AppendNode(doc, nodePos, "Y");
194  SetNodeValue(doc, nodePosY, indMotor->GetPointList()[0].m_y);
195  auto parentID = AppendNode(doc, cadProp, "ParentID");
196  Bus* parent = static_cast<Bus*>(indMotor->GetParentList()[0]);
197  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
198 
199  IndMotorElectricalData data = indMotor->GetElectricalData();
200  auto electricalProp = AppendNode(doc, indMotorNode, "ElectricalProperties");
201  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
202  SetNodeValue(doc, isOnline, indMotor->IsOnline());
203  auto name = AppendNode(doc, electricalProp, "Name");
204  SetNodeValue(doc, name, data.name);
205  auto activePower = AppendNode(doc, electricalProp, "ActivePower");
206  SetNodeValue(doc, activePower, data.activePower);
207  SetNodeAttribute(doc, activePower, "UnitID", data.activePowerUnit);
208  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
209  SetNodeValue(doc, reactivePower, data.reactivePower);
210  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
211  } //}
212 
213  //{ Inductor
214  auto inductorsNode = AppendNode(doc, elementsNode, "InductorList");
215  auto inductorList = allElements.GetInductorList();
216  for(int i = 0; i < (int)inductorList.size(); i++) {
217  Inductor* inductor = inductorList[i];
218  auto inductorNode = AppendNode(doc, inductorsNode, "Inductor");
219  SetNodeAttribute(doc, inductorNode, "ID", i);
220  auto cadProp = AppendNode(doc, inductorNode, "CADProperties");
221  auto position = AppendNode(doc, cadProp, "Position");
222  auto posX = AppendNode(doc, position, "X");
223  SetNodeValue(doc, posX, inductor->GetPosition().m_x);
224  auto posY = AppendNode(doc, position, "Y");
225  SetNodeValue(doc, posY, inductor->GetPosition().m_y);
226  auto size = AppendNode(doc, cadProp, "Size");
227  auto width = AppendNode(doc, size, "Width");
228  SetNodeValue(doc, width, inductor->GetWidth());
229  auto height = AppendNode(doc, size, "Height");
230  SetNodeValue(doc, height, inductor->GetHeight());
231  auto angle = AppendNode(doc, cadProp, "Angle");
232  SetNodeValue(doc, angle, inductor->GetAngle());
233  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
234  auto nodePosX = AppendNode(doc, nodePos, "X");
235  SetNodeValue(doc, nodePosX, inductor->GetPointList()[0].m_x);
236  auto nodePosY = AppendNode(doc, nodePos, "Y");
237  SetNodeValue(doc, nodePosY, inductor->GetPointList()[0].m_y);
238  auto parentID = AppendNode(doc, cadProp, "ParentID");
239  Bus* parent = static_cast<Bus*>(inductor->GetParentList()[0]);
240  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
241 
242  InductorElectricalData data = inductor->GetElectricalData();
243  auto electricalProp = AppendNode(doc, inductorNode, "ElectricalProperties");
244  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
245  SetNodeValue(doc, isOnline, inductor->IsOnline());
246  auto name = AppendNode(doc, electricalProp, "Name");
247  SetNodeValue(doc, name, data.name);
248  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
249  SetNodeValue(doc, reactivePower, data.reactivePower);
250  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
251 
252  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
253  SwitchingData swData = inductor->GetSwitchingData();
254  for(int j = 0; j < (int)swData.swType.size(); j++) {
255  auto switching = AppendNode(doc, switchingList, "Switching");
256  SetNodeAttribute(doc, switching, "ID", j);
257  auto swType = AppendNode(doc, switching, "Type");
258  SetNodeValue(doc, swType, swData.swType[j]);
259  auto swTime = AppendNode(doc, switching, "Time");
260  SetNodeValue(doc, swTime, swData.swTime[j]);
261  }
262  } //}
263 
264  //{ Line
265  auto linesNode = AppendNode(doc, elementsNode, "LineList");
266  auto lineList = allElements.GetLineList();
267  for(int i = 0; i < (int)lineList.size(); i++) {
268  Line* line = lineList[i];
269  auto lineNode = AppendNode(doc, linesNode, "Line");
270  SetNodeAttribute(doc, lineNode, "ID", i);
271  auto cadProp = AppendNode(doc, lineNode, "CADProperties");
272  auto nodeList = AppendNode(doc, cadProp, "NodeList");
273  auto ptList = line->GetPointList();
274  int nodeID = 0;
275  for(int j = 0; j < (int)ptList.size(); j++) {
276  if((j != 1) && (j != (int)ptList.size() - 2)) {
277  auto nodePos = AppendNode(doc, nodeList, "Node");
278  SetNodeAttribute(doc, nodePos, "ID", nodeID);
279  auto nodePosX = AppendNode(doc, nodePos, "X");
280  SetNodeValue(doc, nodePosX, ptList[j].m_x);
281  auto nodePosY = AppendNode(doc, nodePos, "Y");
282  SetNodeValue(doc, nodePosY, ptList[j].m_y);
283  nodeID++;
284  }
285  }
286 
287  auto parentIDList = AppendNode(doc, cadProp, "ParentIDList");
288  for(int j = 0; j < (int)line->GetParentList().size(); j++) {
289  Bus* parent = static_cast<Bus*>(line->GetParentList()[j]);
290  if(parent) {
291  auto parentID = AppendNode(doc, parentIDList, "ParentID");
292  SetNodeAttribute(doc, parentID, "ID", j);
293  SetNodeValue(doc, parentID, parent->GetElectricalData().number);
294  }
295  }
296 
297  LineElectricalData data = line->GetElectricalData();
298  auto electricalProp = AppendNode(doc, lineNode, "ElectricalProperties");
299  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
300  SetNodeValue(doc, isOnline, line->IsOnline());
301  auto name = AppendNode(doc, electricalProp, "Name");
302  SetNodeValue(doc, name, data.name);
303  auto nominalVoltage = AppendNode(doc, electricalProp, "NominalVoltage");
304  SetNodeValue(doc, nominalVoltage, data.nominalVoltage);
305  SetNodeAttribute(doc, nominalVoltage, "UnitID", data.nominalVoltageUnit);
306  auto nominalPower = AppendNode(doc, electricalProp, "NominalPower");
307  SetNodeValue(doc, nominalPower, data.nominalPower);
308  SetNodeAttribute(doc, nominalPower, "UnitID", data.nominalPowerUnit);
309  auto resistance = AppendNode(doc, electricalProp, "Resistance");
310  SetNodeValue(doc, resistance, data.resistance);
311  SetNodeAttribute(doc, resistance, "UnitID", data.resistanceUnit);
312  auto indReactance = AppendNode(doc, electricalProp, "IndReactance");
313  SetNodeValue(doc, indReactance, data.indReactance);
314  SetNodeAttribute(doc, indReactance, "UnitID", data.indReactanceUnit);
315  auto capSusceptance = AppendNode(doc, electricalProp, "CapSusceptance");
316  SetNodeValue(doc, capSusceptance, data.capSusceptance);
317  SetNodeAttribute(doc, capSusceptance, "UnitID", data.capSusceptanceUnit);
318  auto lineSize = AppendNode(doc, electricalProp, "LineSize");
319  SetNodeValue(doc, lineSize, data.lineSize);
320  auto useLinePower = AppendNode(doc, electricalProp, "UseLinePower");
321  SetNodeValue(doc, useLinePower, data.useLinePower);
322 
323  auto fault = AppendNode(doc, electricalProp, "Fault");
324  auto zeroResistance = AppendNode(doc, fault, "ZeroResistance");
325  SetNodeValue(doc, zeroResistance, data.zeroResistance);
326  auto zeroIndReactance = AppendNode(doc, fault, "ZeroIndReactance");
327  SetNodeValue(doc, zeroIndReactance, data.zeroIndReactance);
328  auto zeroCapSusceptance = AppendNode(doc, fault, "ZeroCapSusceptance");
329  SetNodeValue(doc, zeroCapSusceptance, data.zeroCapSusceptance);
330 
331  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
332  SwitchingData swData = line->GetSwitchingData();
333  for(int j = 0; j < (int)swData.swType.size(); j++) {
334  auto switching = AppendNode(doc, switchingList, "Switching");
335  SetNodeAttribute(doc, switching, "ID", j);
336  auto swType = AppendNode(doc, switching, "Type");
337  SetNodeValue(doc, swType, swData.swType[j]);
338  auto swTime = AppendNode(doc, switching, "Time");
339  SetNodeValue(doc, swTime, swData.swTime[j]);
340  }
341  } //}
342 
343  //{ Load
344  auto loadsNode = AppendNode(doc, elementsNode, "LoadList");
345  auto loadList = allElements.GetLoadList();
346  for(int i = 0; i < (int)loadList.size(); i++) {
347  Load* load = loadList[i];
348  auto loadNode = AppendNode(doc, loadsNode, "Load");
349  SetNodeAttribute(doc, loadNode, "ID", i);
350  auto cadProp = AppendNode(doc, loadNode, "CADProperties");
351  auto position = AppendNode(doc, cadProp, "Position");
352  auto posX = AppendNode(doc, position, "X");
353  SetNodeValue(doc, posX, load->GetPosition().m_x);
354  auto posY = AppendNode(doc, position, "Y");
355  SetNodeValue(doc, posY, load->GetPosition().m_y);
356  auto size = AppendNode(doc, cadProp, "Size");
357  auto width = AppendNode(doc, size, "Width");
358  SetNodeValue(doc, width, load->GetWidth());
359  auto height = AppendNode(doc, size, "Height");
360  SetNodeValue(doc, height, load->GetHeight());
361  auto angle = AppendNode(doc, cadProp, "Angle");
362  SetNodeValue(doc, angle, load->GetAngle());
363  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
364  auto nodePosX = AppendNode(doc, nodePos, "X");
365  SetNodeValue(doc, nodePosX, load->GetPointList()[0].m_x);
366  auto nodePosY = AppendNode(doc, nodePos, "Y");
367  SetNodeValue(doc, nodePosY, load->GetPointList()[0].m_y);
368  auto parentID = AppendNode(doc, cadProp, "ParentID");
369  Bus* parent = static_cast<Bus*>(load->GetParentList()[0]);
370  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
371 
372  LoadElectricalData data = load->GetElectricalData();
373  auto electricalProp = AppendNode(doc, loadNode, "ElectricalProperties");
374  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
375  SetNodeValue(doc, isOnline, load->IsOnline());
376  auto name = AppendNode(doc, electricalProp, "Name");
377  SetNodeValue(doc, name, data.name);
378  auto activePower = AppendNode(doc, electricalProp, "ActivePower");
379  SetNodeValue(doc, activePower, data.activePower);
380  SetNodeAttribute(doc, activePower, "UnitID", data.activePowerUnit);
381  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
382  SetNodeValue(doc, reactivePower, data.reactivePower);
383  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
384  auto loadType = AppendNode(doc, electricalProp, "LoadType");
385  SetNodeValue(doc, loadType, data.loadType);
386 
387  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
388  SwitchingData swData = load->GetSwitchingData();
389  for(int j = 0; j < (int)swData.swType.size(); j++) {
390  auto switching = AppendNode(doc, switchingList, "Switching");
391  SetNodeAttribute(doc, switching, "ID", j);
392  auto swType = AppendNode(doc, switching, "Type");
393  SetNodeValue(doc, swType, swData.swType[j]);
394  auto swTime = AppendNode(doc, switching, "Time");
395  SetNodeValue(doc, swTime, swData.swTime[j]);
396  }
397  } //}
398 
399  //{ SyncGenerator
400  auto syncGeneratorsNode = AppendNode(doc, elementsNode, "SyncGeneratorList");
401  auto syncGeneratorList = allElements.GetSyncGeneratorList();
402  for(int i = 0; i < (int)syncGeneratorList.size(); i++) {
403  SyncGenerator* syncGenerator = syncGeneratorList[i];
404  auto syncGeneratorNode = AppendNode(doc, syncGeneratorsNode, "SyncGenerator");
405  SetNodeAttribute(doc, syncGeneratorNode, "ID", i);
406  auto cadProp = AppendNode(doc, syncGeneratorNode, "CADProperties");
407  auto position = AppendNode(doc, cadProp, "Position");
408  auto posX = AppendNode(doc, position, "X");
409  SetNodeValue(doc, posX, syncGenerator->GetPosition().m_x);
410  auto posY = AppendNode(doc, position, "Y");
411  SetNodeValue(doc, posY, syncGenerator->GetPosition().m_y);
412  auto size = AppendNode(doc, cadProp, "Size");
413  auto width = AppendNode(doc, size, "Width");
414  SetNodeValue(doc, width, syncGenerator->GetWidth());
415  auto height = AppendNode(doc, size, "Height");
416  SetNodeValue(doc, height, syncGenerator->GetHeight());
417  auto angle = AppendNode(doc, cadProp, "Angle");
418  SetNodeValue(doc, angle, syncGenerator->GetAngle());
419  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
420  auto nodePosX = AppendNode(doc, nodePos, "X");
421  SetNodeValue(doc, nodePosX, syncGenerator->GetPointList()[0].m_x);
422  auto nodePosY = AppendNode(doc, nodePos, "Y");
423  SetNodeValue(doc, nodePosY, syncGenerator->GetPointList()[0].m_y);
424  auto parentID = AppendNode(doc, cadProp, "ParentID");
425  Bus* parent = static_cast<Bus*>(syncGenerator->GetParentList()[0]);
426  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
427 
428  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
429  auto electricalProp = AppendNode(doc, syncGeneratorNode, "ElectricalProperties");
430  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
431  SetNodeValue(doc, isOnline, syncGenerator->IsOnline());
432  auto name = AppendNode(doc, electricalProp, "Name");
433  SetNodeValue(doc, name, data.name);
434  auto nominalPower = AppendNode(doc, electricalProp, "NominalPower");
435  SetNodeValue(doc, nominalPower, data.nominalPower);
436  SetNodeAttribute(doc, nominalPower, "UnitID", data.nominalPowerUnit);
437  auto nominalVoltage = AppendNode(doc, electricalProp, "NominalVoltage");
438  SetNodeValue(doc, nominalVoltage, data.nominalVoltage);
439  SetNodeAttribute(doc, nominalVoltage, "UnitID", data.nominalVoltageUnit);
440  auto activePower = AppendNode(doc, electricalProp, "ActivePower");
441  SetNodeValue(doc, activePower, data.activePower);
442  SetNodeAttribute(doc, activePower, "UnitID", data.activePowerUnit);
443  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
444  SetNodeValue(doc, reactivePower, data.reactivePower);
445  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
446  auto haveMaxReactive = AppendNode(doc, electricalProp, "HaveMaxReactive");
447  SetNodeValue(doc, haveMaxReactive, data.haveMaxReactive);
448  auto maxReactive = AppendNode(doc, electricalProp, "MaxReactive");
449  SetNodeValue(doc, maxReactive, data.maxReactive);
450  SetNodeAttribute(doc, maxReactive, "UnitID", data.maxReactiveUnit);
451  auto haveMinReactive = AppendNode(doc, electricalProp, "HaveMinReactive");
452  SetNodeValue(doc, haveMinReactive, data.haveMinReactive);
453  auto minReactive = AppendNode(doc, electricalProp, "MinReactive");
454  SetNodeValue(doc, minReactive, data.minReactive);
455  SetNodeAttribute(doc, minReactive, "UnitID", data.minReactiveUnit);
456  auto useMachineBase = AppendNode(doc, electricalProp, "UseMachineBase");
457  SetNodeValue(doc, useMachineBase, data.useMachineBase);
458 
459  auto fault = AppendNode(doc, electricalProp, "Fault");
460  auto positiveResistance = AppendNode(doc, fault, "PositiveResistance");
461  SetNodeValue(doc, positiveResistance, data.positiveResistance);
462  auto positiveReactance = AppendNode(doc, fault, "PositiveReactance");
463  SetNodeValue(doc, positiveReactance, data.positiveReactance);
464  auto negativeResistance = AppendNode(doc, fault, "NegativeResistance");
465  SetNodeValue(doc, negativeResistance, data.negativeResistance);
466  auto negativeReactance = AppendNode(doc, fault, "NegativeReactance");
467  SetNodeValue(doc, negativeReactance, data.negativeReactance);
468  auto zeroResistance = AppendNode(doc, fault, "ZeroResistance");
469  SetNodeValue(doc, zeroResistance, data.zeroResistance);
470  auto zeroReactance = AppendNode(doc, fault, "ZeroReactance");
471  SetNodeValue(doc, zeroReactance, data.zeroReactance);
472  auto groundResistance = AppendNode(doc, fault, "GroundResistance");
473  SetNodeValue(doc, groundResistance, data.groundResistance);
474  auto groundReactance = AppendNode(doc, fault, "GroundReactance");
475  SetNodeValue(doc, groundReactance, data.groundReactance);
476  auto groundNeutral = AppendNode(doc, fault, "GroundNeutral");
477  SetNodeValue(doc, groundNeutral, data.groundNeutral);
478 
479  auto stability = AppendNode(doc, electricalProp, "Stability");
480  auto plotSyncMachine = AppendNode(doc, stability, "PlotSyncMachine");
481  SetNodeValue(doc, plotSyncMachine, data.plotSyncMachine);
482  auto inertia = AppendNode(doc, stability, "Inertia");
483  SetNodeValue(doc, inertia, data.inertia);
484  auto damping = AppendNode(doc, stability, "Damping");
485  SetNodeValue(doc, damping, data.damping);
486  auto useAVR = AppendNode(doc, stability, "UseAVR");
487  SetNodeValue(doc, useAVR, data.useAVR);
488  auto useSpeedGovernor = AppendNode(doc, stability, "UseSpeedGovernor");
489  SetNodeValue(doc, useSpeedGovernor, data.useSpeedGovernor);
490  auto armResistance = AppendNode(doc, stability, "ArmResistance");
491  SetNodeValue(doc, armResistance, data.armResistance);
492  auto potierReactance = AppendNode(doc, stability, "PotierReactance");
493  SetNodeValue(doc, potierReactance, data.potierReactance);
494  auto satFactor = AppendNode(doc, stability, "SatFactor");
495  SetNodeValue(doc, satFactor, data.satFactor);
496  auto syncXd = AppendNode(doc, stability, "SyncXd");
497  SetNodeValue(doc, syncXd, data.syncXd);
498  auto syncXq = AppendNode(doc, stability, "SyncXq");
499  SetNodeValue(doc, syncXq, data.syncXq);
500  auto transXd = AppendNode(doc, stability, "TransXd");
501  SetNodeValue(doc, transXd, data.transXd);
502  auto transXq = AppendNode(doc, stability, "TransXq");
503  SetNodeValue(doc, transXq, data.transXq);
504  auto transTd0 = AppendNode(doc, stability, "TransTd0");
505  SetNodeValue(doc, transTd0, data.transTd0);
506  auto transTq0 = AppendNode(doc, stability, "TransTq0");
507  SetNodeValue(doc, transTq0, data.transTq0);
508  auto subXd = AppendNode(doc, stability, "SubXd");
509  SetNodeValue(doc, subXd, data.subXd);
510  auto subXq = AppendNode(doc, stability, "SubXq");
511  SetNodeValue(doc, subXq, data.subXq);
512  auto subTd0 = AppendNode(doc, stability, "SubTd0");
513  SetNodeValue(doc, subTd0, data.subTd0);
514  auto subTq0 = AppendNode(doc, stability, "SubTq0");
515  SetNodeValue(doc, subTq0, data.subTq0);
516 
517  auto avr = AppendNode(doc, stability, "AVR");
518  if(data.avr) SaveControlElements(doc, avr, data.avr);
519 
520  auto speedGov = AppendNode(doc, stability, "SpeedGovernor");
521  if(data.speedGov) SaveControlElements(doc, speedGov, data.speedGov);
522 
523  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
524  SwitchingData swData = syncGenerator->GetSwitchingData();
525  for(int j = 0; j < (int)swData.swType.size(); j++) {
526  auto switching = AppendNode(doc, switchingList, "Switching");
527  SetNodeAttribute(doc, switching, "ID", j);
528  auto swType = AppendNode(doc, switching, "Type");
529  SetNodeValue(doc, swType, swData.swType[j]);
530  auto swTime = AppendNode(doc, switching, "Time");
531  SetNodeValue(doc, swTime, swData.swTime[j]);
532  }
533  } //}
534 
535  //{ SyncMotor
536  auto syncMotorsNode = AppendNode(doc, elementsNode, "SyncMotorList");
537  auto syncMotorList = allElements.GetSyncMotorList();
538  for(int i = 0; i < (int)syncMotorList.size(); i++) {
539  SyncMotor* syncMotor = syncMotorList[i];
540  auto syncMotorNode = AppendNode(doc, syncMotorsNode, "SyncMotor");
541  SetNodeAttribute(doc, syncMotorNode, "ID", i);
542  auto cadProp = AppendNode(doc, syncMotorNode, "CADProperties");
543  auto position = AppendNode(doc, cadProp, "Position");
544  auto posX = AppendNode(doc, position, "X");
545  SetNodeValue(doc, posX, syncMotor->GetPosition().m_x);
546  auto posY = AppendNode(doc, position, "Y");
547  SetNodeValue(doc, posY, syncMotor->GetPosition().m_y);
548  auto size = AppendNode(doc, cadProp, "Size");
549  auto width = AppendNode(doc, size, "Width");
550  SetNodeValue(doc, width, syncMotor->GetWidth());
551  auto height = AppendNode(doc, size, "Height");
552  SetNodeValue(doc, height, syncMotor->GetHeight());
553  auto angle = AppendNode(doc, cadProp, "Angle");
554  SetNodeValue(doc, angle, syncMotor->GetAngle());
555  auto nodePos = AppendNode(doc, cadProp, "NodePosition");
556  auto nodePosX = AppendNode(doc, nodePos, "X");
557  SetNodeValue(doc, nodePosX, syncMotor->GetPointList()[0].m_x);
558  auto nodePosY = AppendNode(doc, nodePos, "Y");
559  SetNodeValue(doc, nodePosY, syncMotor->GetPointList()[0].m_y);
560  auto parentID = AppendNode(doc, cadProp, "ParentID");
561  Bus* parent = static_cast<Bus*>(syncMotor->GetParentList()[0]);
562  if(parent) SetNodeValue(doc, parentID, parent->GetElectricalData().number);
563 
564  SyncMotorElectricalData data = syncMotor->GetElectricalData();
565  auto electricalProp = AppendNode(doc, syncMotorNode, "ElectricalProperties");
566  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
567  SetNodeValue(doc, isOnline, syncMotor->IsOnline());
568  auto name = AppendNode(doc, electricalProp, "Name");
569  SetNodeValue(doc, name, data.name);
570  auto nominalPower = AppendNode(doc, electricalProp, "NominalPower");
571  SetNodeValue(doc, nominalPower, data.nominalPower);
572  SetNodeAttribute(doc, nominalPower, "UnitID", data.nominalPowerUnit);
573  // auto nominalVoltage = AppendNode(doc, electricalProp, "NominalVoltage");
574  // SetNodeValue(doc, nominalVoltage, data.nominalVoltage);
575  // SetNodeAttribute(doc, nominalVoltage, "UnitID", data.nominalVoltageUnit);
576  auto activePower = AppendNode(doc, electricalProp, "ActivePower");
577  SetNodeValue(doc, activePower, data.activePower);
578  SetNodeAttribute(doc, activePower, "UnitID", data.activePowerUnit);
579  auto reactivePower = AppendNode(doc, electricalProp, "ReactivePower");
580  SetNodeValue(doc, reactivePower, data.reactivePower);
581  SetNodeAttribute(doc, reactivePower, "UnitID", data.reactivePowerUnit);
582  auto haveMaxReactive = AppendNode(doc, electricalProp, "HaveMaxReactive");
583  SetNodeValue(doc, haveMaxReactive, data.haveMaxReactive);
584  auto maxReactive = AppendNode(doc, electricalProp, "MaxReactive");
585  SetNodeValue(doc, maxReactive, data.maxReactive);
586  SetNodeAttribute(doc, maxReactive, "UnitID", data.maxReactiveUnit);
587  auto haveMinReactive = AppendNode(doc, electricalProp, "HaveMinReactive");
588  SetNodeValue(doc, haveMinReactive, data.haveMinReactive);
589  auto minReactive = AppendNode(doc, electricalProp, "MinReactive");
590  SetNodeValue(doc, minReactive, data.minReactive);
591  SetNodeAttribute(doc, minReactive, "UnitID", data.minReactiveUnit);
592  auto useMachineBase = AppendNode(doc, electricalProp, "UseMachineBase");
593  SetNodeValue(doc, useMachineBase, data.useMachineBase);
594 
595  auto fault = AppendNode(doc, electricalProp, "Fault");
596  auto positiveResistance = AppendNode(doc, fault, "PositiveResistance");
597  SetNodeValue(doc, positiveResistance, data.positiveResistance);
598  auto positiveReactance = AppendNode(doc, fault, "PositiveReactance");
599  SetNodeValue(doc, positiveReactance, data.positiveReactance);
600  auto negativeResistance = AppendNode(doc, fault, "NegativeResistance");
601  SetNodeValue(doc, negativeResistance, data.negativeResistance);
602  auto negativeReactance = AppendNode(doc, fault, "NegativeReactance");
603  SetNodeValue(doc, negativeReactance, data.negativeReactance);
604  auto zeroResistance = AppendNode(doc, fault, "ZeroResistance");
605  SetNodeValue(doc, zeroResistance, data.zeroResistance);
606  auto zeroReactance = AppendNode(doc, fault, "ZeroReactance");
607  SetNodeValue(doc, zeroReactance, data.zeroReactance);
608  auto groundResistance = AppendNode(doc, fault, "GroundResistance");
609  SetNodeValue(doc, groundResistance, data.groundResistance);
610  auto groundReactance = AppendNode(doc, fault, "GroundReactance");
611  SetNodeValue(doc, groundReactance, data.groundReactance);
612  auto groundNeutral = AppendNode(doc, fault, "GroundNeutral");
613  SetNodeValue(doc, groundNeutral, data.groundNeutral);
614 
615  // To future use...
616  /*auto stability = AppendNode(doc, electricalProp, "Stability");
617  auto plotSyncMachine = AppendNode(doc, stability, "PlotSyncMotor");
618  SetNodeValue(doc, plotSyncMachine, data.plotSyncMachine);
619  auto inertia = AppendNode(doc, stability, "Inertia");
620  SetNodeValue(doc, inertia, data.inertia);
621  auto damping = AppendNode(doc, stability, "Damping");
622  SetNodeValue(doc, damping, data.damping);
623  auto useAVR = AppendNode(doc, stability, "UseAVR");
624  SetNodeValue(doc, useAVR, data.useAVR);
625  auto armResistance = AppendNode(doc, stability, "ArmResistance");
626  SetNodeValue(doc, armResistance, data.armResistance);
627  auto potierReactance = AppendNode(doc, stability, "PotierReactance");
628  SetNodeValue(doc, potierReactance, data.potierReactance);
629  auto satFactor = AppendNode(doc, stability, "SatFactor");
630  SetNodeValue(doc, satFactor, data.satFactor);
631  auto syncXd = AppendNode(doc, stability, "SyncXd");
632  SetNodeValue(doc, syncXd, data.syncXd);
633  auto syncXq = AppendNode(doc, stability, "SyncXq");
634  SetNodeValue(doc, syncXq, data.syncXq);
635  auto transXd = AppendNode(doc, stability, "TransXd");
636  SetNodeValue(doc, transXd, data.transXd);
637  auto transXq = AppendNode(doc, stability, "TransXq");
638  SetNodeValue(doc, transXq, data.transXq);
639  auto transTd0 = AppendNode(doc, stability, "TransTd0");
640  SetNodeValue(doc, transTd0, data.transTd0);
641  auto transTq0 = AppendNode(doc, stability, "TransTq0");
642  SetNodeValue(doc, transTq0, data.transTq0);
643  auto subXd = AppendNode(doc, stability, "SubXd");
644  SetNodeValue(doc, subXd, data.subXd);
645  auto subXq = AppendNode(doc, stability, "SubXq");
646  SetNodeValue(doc, subXq, data.subXq);
647  auto subTd0 = AppendNode(doc, stability, "SubTd0");
648  SetNodeValue(doc, subTd0, data.subTd0);
649  auto subTq0 = AppendNode(doc, stability, "SubTq0");
650  SetNodeValue(doc, subTq0, data.subTq0);
651 
652  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
653  SwitchingData swData = syncGenerator->GetSwitchingData();
654  for(int j = 0; j < (int)swData.swType.size(); j++) {
655  auto switching = AppendNode(doc, switchingList, "Switching");
656  SetNodeAttribute(doc, switching, "ID", j);
657  auto swType = AppendNode(doc, switching, "Type");
658  SetNodeValue(doc, swType, swData.swType[j]);
659  auto swTime = AppendNode(doc, switching, "Time");
660  SetNodeValue(doc, swTime, swData.swTime[j]);
661  }*/
662  } //}
663 
664  //{ Transfomer
665  auto transformersNode = AppendNode(doc, elementsNode, "TransformerList");
666  auto transformerList = allElements.GetTransformerList();
667  for(int i = 0; i < (int)transformerList.size(); i++) {
668  Transformer* transfomer = transformerList[i];
669  auto transformerNode = AppendNode(doc, transformersNode, "Transfomer");
670  SetNodeAttribute(doc, transformerNode, "ID", i);
671  auto cadProp = AppendNode(doc, transformerNode, "CADProperties");
672  auto position = AppendNode(doc, cadProp, "Position");
673  auto posX = AppendNode(doc, position, "X");
674  SetNodeValue(doc, posX, transfomer->GetPosition().m_x);
675  auto posY = AppendNode(doc, position, "Y");
676  SetNodeValue(doc, posY, transfomer->GetPosition().m_y);
677  auto size = AppendNode(doc, cadProp, "Size");
678  auto width = AppendNode(doc, size, "Width");
679  SetNodeValue(doc, width, transfomer->GetWidth());
680  auto height = AppendNode(doc, size, "Height");
681  SetNodeValue(doc, height, transfomer->GetHeight());
682  auto angle = AppendNode(doc, cadProp, "Angle");
683  SetNodeValue(doc, angle, transfomer->GetAngle());
684  auto nodeList = AppendNode(doc, cadProp, "NodeList");
685  auto nodePos1 = AppendNode(doc, nodeList, "Node");
686  SetNodeAttribute(doc, nodePos1, "ID", 0);
687  auto nodePosX1 = AppendNode(doc, nodePos1, "X");
688  SetNodeValue(doc, nodePosX1, transfomer->GetPointList()[0].m_x);
689  auto nodePosY1 = AppendNode(doc, nodePos1, "Y");
690  SetNodeValue(doc, nodePosY1, transfomer->GetPointList()[0].m_y);
691  auto nodePos2 = AppendNode(doc, nodeList, "Node");
692  SetNodeAttribute(doc, nodePos2, "ID", 1);
693  auto nodePosX2 = AppendNode(doc, nodePos2, "X");
694  SetNodeValue(doc, nodePosX2, transfomer->GetPointList()[transfomer->GetPointList().size() - 1].m_x);
695  auto nodePosY2 = AppendNode(doc, nodePos2, "Y");
696  SetNodeValue(doc, nodePosY2, transfomer->GetPointList()[transfomer->GetPointList().size() - 1].m_y);
697 
698  auto parentIDList = AppendNode(doc, cadProp, "ParentIDList");
699  for(int j = 0; j < (int)transfomer->GetParentList().size(); j++) {
700  Bus* parent = static_cast<Bus*>(transfomer->GetParentList()[j]);
701  if(parent) {
702  auto parentID = AppendNode(doc, parentIDList, "ParentID");
703  SetNodeAttribute(doc, parentID, "ID", j);
704  SetNodeValue(doc, parentID, parent->GetElectricalData().number);
705  }
706  }
707 
708  TransformerElectricalData data = transfomer->GetElectricalData();
709  auto electricalProp = AppendNode(doc, transformerNode, "ElectricalProperties");
710  auto isOnline = AppendNode(doc, electricalProp, "IsOnline");
711  SetNodeValue(doc, isOnline, transfomer->IsOnline());
712  auto name = AppendNode(doc, electricalProp, "Name");
713  SetNodeValue(doc, name, data.name);
714  auto primaryNominalVoltage = AppendNode(doc, electricalProp, "PrimaryNominalVoltage");
715  SetNodeValue(doc, primaryNominalVoltage, data.primaryNominalVoltage);
716  SetNodeAttribute(doc, primaryNominalVoltage, "UnitID", data.primaryNominalVoltageUnit);
717  auto secondaryNominalVoltage = AppendNode(doc, electricalProp, "SecondaryNominalVoltage");
718  SetNodeValue(doc, secondaryNominalVoltage, data.secondaryNominalVoltage);
719  SetNodeAttribute(doc, secondaryNominalVoltage, "UnitID", data.secondaryNominalVoltageUnit);
720  auto nominalPower = AppendNode(doc, electricalProp, "NominalPower");
721  SetNodeValue(doc, nominalPower, data.nominalPower);
722  SetNodeAttribute(doc, nominalPower, "UnitID", data.nominalPowerUnit);
723  auto resistance = AppendNode(doc, electricalProp, "Resistance");
724  SetNodeValue(doc, resistance, data.resistance);
725  SetNodeAttribute(doc, resistance, "UnitID", data.resistanceUnit);
726  auto indReactance = AppendNode(doc, electricalProp, "IndReactance");
727  SetNodeValue(doc, indReactance, data.indReactance);
728  SetNodeAttribute(doc, indReactance, "UnitID", data.indReactanceUnit);
729  auto connection = AppendNode(doc, electricalProp, "Connection");
730  SetNodeValue(doc, connection, data.connection);
731  auto turnsRatio = AppendNode(doc, electricalProp, "TurnsRatio");
732  SetNodeValue(doc, turnsRatio, data.turnsRatio);
733  auto phaseShift = AppendNode(doc, electricalProp, "PhaseShift");
734  SetNodeValue(doc, phaseShift, data.phaseShift);
735  auto useTransformerPower = AppendNode(doc, electricalProp, "UseTransfomerPower");
736  SetNodeValue(doc, useTransformerPower, data.useTransformerPower);
737 
738  auto fault = AppendNode(doc, electricalProp, "Fault");
739  auto zeroResistance = AppendNode(doc, fault, "ZeroResistance");
740  SetNodeValue(doc, zeroResistance, data.zeroResistance);
741  auto zeroIndReactance = AppendNode(doc, fault, "ZeroIndReactance");
742  SetNodeValue(doc, zeroIndReactance, data.zeroIndReactance);
743  auto primaryGrndResistance = AppendNode(doc, fault, "PrimaryGrndResistance");
744  SetNodeValue(doc, primaryGrndResistance, data.primaryGrndResistance);
745  auto primaryGrndReactance = AppendNode(doc, fault, "PrimaryGrndReactance");
746  SetNodeValue(doc, primaryGrndReactance, data.primaryGrndReactance);
747  auto secondaryGrndResistance = AppendNode(doc, fault, "SecondaryGrndResistance");
748  SetNodeValue(doc, secondaryGrndResistance, data.secondaryGrndResistance);
749  auto secondaryGrndReactance = AppendNode(doc, fault, "SecondaryGrndReactance");
750  SetNodeValue(doc, secondaryGrndReactance, data.secondaryGrndReactance);
751 
752  auto switchingList = AppendNode(doc, electricalProp, "SwitchingList");
753  SwitchingData swData = transfomer->GetSwitchingData();
754  for(int j = 0; j < (int)swData.swType.size(); j++) {
755  auto switching = AppendNode(doc, switchingList, "Switching");
756  SetNodeAttribute(doc, switching, "ID", j);
757  auto swType = AppendNode(doc, switching, "Type");
758  SetNodeValue(doc, swType, swData.swType[j]);
759  auto swTime = AppendNode(doc, switching, "Time");
760  SetNodeValue(doc, swTime, swData.swTime[j]);
761  }
762  } //}
763 
764  //{ Text
765  auto textsNode = AppendNode(doc, elementsNode, "TextList");
766  auto textList = m_workspace->GetTextList();
767  for(int i = 0; i < (int)textList.size(); i++) {
768  Text* text = textList[i];
769  auto textNode = AppendNode(doc, textsNode, "Text");
770  SetNodeAttribute(doc, textNode, "ID", i);
771  auto cadProp = AppendNode(doc, textNode, "CADProperties");
772  auto position = AppendNode(doc, cadProp, "Position");
773  auto posX = AppendNode(doc, position, "X");
774  SetNodeValue(doc, posX, text->GetPosition().m_x);
775  auto posY = AppendNode(doc, position, "Y");
776  SetNodeValue(doc, posY, text->GetPosition().m_y);
777  auto size = AppendNode(doc, cadProp, "Size");
778  auto width = AppendNode(doc, size, "Width");
779  SetNodeValue(doc, width, text->GetWidth());
780  auto height = AppendNode(doc, size, "Height");
781  SetNodeValue(doc, height, text->GetHeight());
782  auto angle = AppendNode(doc, cadProp, "Angle");
783  SetNodeValue(doc, angle, text->GetAngle());
784  auto textProperties = AppendNode(doc, textNode, "TextProperties");
785  auto elementType = AppendNode(doc, textProperties, "ElementType");
786  SetNodeValue(doc, elementType, text->GetElementType());
787  auto elementNumber = AppendNode(doc, textProperties, "ElementNumber");
788  SetNodeValue(doc, elementNumber, text->GetElementNumber());
789  auto dataType = AppendNode(doc, textProperties, "DataType");
790  SetNodeValue(doc, dataType, text->GetDataType());
791  auto dataUnit = AppendNode(doc, textProperties, "DataUnit");
792  SetNodeValue(doc, dataUnit, text->GetUnit());
793  auto direction = AppendNode(doc, textProperties, "Direction");
794  SetNodeValue(doc, direction, text->GetDirection());
795  auto decimalPlaces = AppendNode(doc, textProperties, "DecimalPlaces");
796  SetNodeValue(doc, decimalPlaces, text->GetDecimalPlaces());
797  }
798  //}
799 
800  std::ofstream writeXML(path.GetFullPath());
801  writeXML << doc;
802  writeXML.close();
803 }
804 
805 bool FileHanding::OpenProject(wxFileName path)
806 {
807  rapidxml::xml_document<> doc;
808  rapidxml::file<> xmlFile(path.GetFullPath().mb_str());
809 
810  doc.parse<0>(xmlFile.data());
811 
812  auto projectNode = doc.first_node("Project");
813  if(!projectNode) return false;
814  auto nameNode = projectNode->first_node("Name");
815  if(!nameNode) return false;
816  m_workspace->SetName(nameNode->value());
817 
818  // Open elements
819  auto elementsNode = projectNode->first_node("Elements");
820  if(!elementsNode) return false;
821  std::vector<Element*> elementList;
822  // Save lists individually to get parents
823  std::vector<Bus*> busList;
824  std::vector<Capacitor*> capacitorList;
825  std::vector<IndMotor*> indMotorList;
826  std::vector<Inductor*> inductorList;
827  std::vector<Line*> lineList;
828  std::vector<Load*> loadList;
829  std::vector<SyncGenerator*> syncGeneratorList;
830  std::vector<SyncMotor*> syncMotorList;
831  std::vector<Transformer*> transformerList;
832  std::vector<Text*> textList;
833 
834  //{ Bus
835  auto busListNode = elementsNode->first_node("BusList");
836  if(!busListNode) return false;
837  auto busNode = busListNode->first_node("Bus");
838  while(busNode) {
839  auto cadPropNode = busNode->first_node("CADProperties");
840  if(!cadPropNode) return false;
841 
842  auto position = cadPropNode->first_node("Position");
843  double posX = GetNodeValueDouble(position, "X");
844  double posY = GetNodeValueDouble(position, "Y");
845  Bus* bus = new Bus(wxPoint2DDouble(posX, posY));
846 
847  auto size = cadPropNode->first_node("Size");
848  double width = GetNodeValueDouble(size, "Width");
849  double height = GetNodeValueDouble(size, "Height");
850  double angle = GetNodeValueDouble(cadPropNode, "Angle");
851  bus->SetWidth(width);
852  bus->SetHeight(height);
853  bus->SetPosition(bus->GetPosition()); // Update bus rectangle.
854  int numRot = angle / bus->GetRotationAngle();
855  bool clockwise = true;
856  if(numRot < 0) {
857  numRot = std::abs(numRot);
858  clockwise = false;
859  }
860  for(int i = 0; i < numRot; i++) bus->Rotate(clockwise);
861 
862  BusElectricalData data = bus->GetElectricalData();
863  auto electricalProp = busNode->first_node("ElectricalProperties");
864  if(!electricalProp) return false;
865 
866  data.name = electricalProp->first_node("Name")->value();
867  data.nominalVoltage = GetNodeValueDouble(electricalProp, "NominalVoltage");
868  data.nominalVoltageUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalVoltage", "UnitID");
869  data.isVoltageControlled = GetNodeValueInt(electricalProp, "IsVoltageControlled");
870  data.controlledVoltage = GetNodeValueDouble(electricalProp, "ControlledVoltage");
871  data.controlledVoltageUnitChoice = GetAttributeValueInt(electricalProp, "ControlledVoltage", "Choice");
872  data.slackBus = GetNodeValueInt(electricalProp, "SlackBus");
873  auto fault = electricalProp->first_node("Fault");
874  data.hasFault = GetNodeValueInt(fault, "HasFault");
875  data.faultType = (FaultData)GetNodeValueInt(fault, "Type");
876  data.faultLocation = (FaultData)GetNodeValueInt(fault, "Location");
877  data.faultResistance = GetNodeValueDouble(fault, "Resistance");
878  data.faultReactance = GetNodeValueDouble(fault, "Reactance");
879  auto stability = electricalProp->first_node("Stability");
880  data.plotBus = GetNodeValueInt(stability, "Plot");
881  data.stabHasFault = GetNodeValueInt(stability, "HasFault");
882  data.stabFaultTime = GetNodeValueDouble(stability, "FaultTime");
883  data.stabFaultLength = GetNodeValueDouble(stability, "FaultLength");
884  data.stabFaultResistance = GetNodeValueDouble(stability, "FaultResistance");
885  data.stabFaultReactance = GetNodeValueDouble(stability, "FaultReactance");
886 
887  bus->SetElectricalData(data);
888 
889  if(data.stabHasFault) bus->SetDynamicEvent(true);
890 
891  elementList.push_back(bus);
892  busList.push_back(bus);
893  busNode = busNode->next_sibling("Bus");
894  } //}
895 
896  //{ Capacitor
897  auto capacitorListNode = elementsNode->first_node("CapacitorList");
898  if(!capacitorListNode) return false;
899  auto capacitorNode = capacitorListNode->first_node("Capacitor");
900  while(capacitorNode) {
901  Capacitor* capacitor = new Capacitor();
902 
903  auto cadPropNode = capacitorNode->first_node("CADProperties");
904  if(!cadPropNode) return false;
905 
906  auto position = cadPropNode->first_node("Position");
907  double posX = GetNodeValueDouble(position, "X");
908  double posY = GetNodeValueDouble(position, "Y");
909  auto size = cadPropNode->first_node("Size");
910  double width = GetNodeValueDouble(size, "Width");
911  double height = GetNodeValueDouble(size, "Height");
912  double angle = GetNodeValueDouble(cadPropNode, "Angle");
913  auto nodePosition = cadPropNode->first_node("NodePosition");
914  double nodePosX = GetNodeValueDouble(nodePosition, "X");
915  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
916  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
917  if(parentID == -1) {
918  // If the element has no parent, create a temporary one, remove and delete.
919  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
920  capacitor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
921  capacitor->StartMove(capacitor->GetPosition());
922  capacitor->Move(wxPoint2DDouble(posX, posY));
923  capacitor->RemoveParent(parent);
924  delete parent;
925  } else {
926  Bus* parent = busList[parentID];
927  capacitor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
928  capacitor->StartMove(capacitor->GetPosition());
929  capacitor->Move(wxPoint2DDouble(posX, posY));
930  }
931  capacitor->SetWidth(width);
932  capacitor->SetHeight(height);
933 
934  int numRot = angle / capacitor->GetRotationAngle();
935  bool clockwise = true;
936  if(numRot < 0) {
937  numRot = std::abs(numRot);
938  clockwise = false;
939  }
940  for(int i = 0; i < numRot; i++) capacitor->Rotate(clockwise);
941 
942  auto electricalProp = capacitorNode->first_node("ElectricalProperties");
943  if(!electricalProp) return false;
944 
945  capacitor->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
946  CapacitorElectricalData data = capacitor->GetElectricalData();
947  data.name = electricalProp->first_node("Name")->value();
948  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
949  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
950 
951  SwitchingData swData;
952  auto switchingList = electricalProp->first_node("SwitchingList");
953  if(!switchingList) return false;
954  auto swNode = switchingList->first_node("Switching");
955  while(swNode) {
956  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
957  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
958  swNode = swNode->next_sibling("Switching");
959  }
960  capacitor->SetSwitchingData(swData);
961 
962  capacitor->SetElectricalData(data);
963 
964  if(swData.swTime.size() != 0) capacitor->SetDynamicEvent(true);
965 
966  elementList.push_back(capacitor);
967  capacitorList.push_back(capacitor);
968  capacitorNode = capacitorNode->next_sibling("Capacitor");
969  } //}
970 
971  //{ IndMotor
972  auto indMotorListNode = elementsNode->first_node("IndMotorList");
973  if(!indMotorListNode) return false;
974  auto indMotorNode = indMotorListNode->first_node("IndMotor");
975  while(indMotorNode) {
976  IndMotor* indMotor = new IndMotor();
977 
978  auto cadPropNode = indMotorNode->first_node("CADProperties");
979  if(!cadPropNode) return false;
980 
981  auto position = cadPropNode->first_node("Position");
982  double posX = GetNodeValueDouble(position, "X");
983  double posY = GetNodeValueDouble(position, "Y");
984  auto size = cadPropNode->first_node("Size");
985  double width = GetNodeValueDouble(size, "Width");
986  double height = GetNodeValueDouble(size, "Height");
987  double angle = GetNodeValueDouble(cadPropNode, "Angle");
988  auto nodePosition = cadPropNode->first_node("NodePosition");
989  double nodePosX = GetNodeValueDouble(nodePosition, "X");
990  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
991  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
992  if(parentID == -1) {
993  // If the element has no parent, create a temporary one, remove and delete.
994  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
995  indMotor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
996  indMotor->StartMove(indMotor->GetPosition());
997  indMotor->Move(wxPoint2DDouble(posX, posY));
998  indMotor->RemoveParent(parent);
999  delete parent;
1000  } else {
1001  Bus* parent = busList[parentID];
1002  indMotor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1003  indMotor->StartMove(indMotor->GetPosition());
1004  indMotor->Move(wxPoint2DDouble(posX, posY));
1005  }
1006  indMotor->SetWidth(width);
1007  indMotor->SetHeight(height);
1008 
1009  int numRot = angle / indMotor->GetRotationAngle();
1010  bool clockwise = true;
1011  if(numRot < 0) {
1012  numRot = std::abs(numRot);
1013  clockwise = false;
1014  }
1015  for(int i = 0; i < numRot; i++) indMotor->Rotate(clockwise);
1016 
1017  auto electricalProp = indMotorNode->first_node("ElectricalProperties");
1018  if(!electricalProp) return false;
1019 
1020  indMotor->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1021  IndMotorElectricalData data = indMotor->GetElectricalData();
1022  data.name = electricalProp->first_node("Name")->value();
1023  data.activePower = GetNodeValueDouble(electricalProp, "ActivePower");
1024  data.activePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ActivePower", "UnitID");
1025  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
1026  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
1027 
1028  indMotor->SetElectricalData(data);
1029  elementList.push_back(indMotor);
1030  indMotorList.push_back(indMotor);
1031  indMotorNode = indMotorNode->next_sibling("IndMotor");
1032  } //}
1033 
1034  //{ Inductor
1035  auto inductorListNode = elementsNode->first_node("InductorList");
1036  if(!inductorListNode) return false;
1037  auto inductorNode = inductorListNode->first_node("Inductor");
1038  while(inductorNode) {
1039  Inductor* inductor = new Inductor();
1040 
1041  auto cadPropNode = inductorNode->first_node("CADProperties");
1042  if(!cadPropNode) return false;
1043 
1044  auto position = cadPropNode->first_node("Position");
1045  double posX = GetNodeValueDouble(position, "X");
1046  double posY = GetNodeValueDouble(position, "Y");
1047  auto size = cadPropNode->first_node("Size");
1048  double width = GetNodeValueDouble(size, "Width");
1049  double height = GetNodeValueDouble(size, "Height");
1050  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1051  auto nodePosition = cadPropNode->first_node("NodePosition");
1052  double nodePosX = GetNodeValueDouble(nodePosition, "X");
1053  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
1054  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
1055  if(parentID == -1) {
1056  // If the element has no parent, create a temporary one, remove and delete.
1057  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
1058  inductor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1059  inductor->StartMove(inductor->GetPosition());
1060  inductor->Move(wxPoint2DDouble(posX, posY));
1061  inductor->RemoveParent(parent);
1062  delete parent;
1063  } else {
1064  Bus* parent = busList[parentID];
1065  inductor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1066  inductor->StartMove(inductor->GetPosition());
1067  inductor->Move(wxPoint2DDouble(posX, posY));
1068  }
1069  inductor->SetWidth(width);
1070  inductor->SetHeight(height);
1071 
1072  int numRot = angle / inductor->GetRotationAngle();
1073  bool clockwise = true;
1074  if(numRot < 0) {
1075  numRot = std::abs(numRot);
1076  clockwise = false;
1077  }
1078  for(int i = 0; i < numRot; i++) inductor->Rotate(clockwise);
1079 
1080  auto electricalProp = inductorNode->first_node("ElectricalProperties");
1081  if(!electricalProp) return false;
1082 
1083  inductor->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1084  InductorElectricalData data = inductor->GetElectricalData();
1085  data.name = electricalProp->first_node("Name")->value();
1086  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
1087  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
1088 
1089  SwitchingData swData;
1090  auto switchingList = electricalProp->first_node("SwitchingList");
1091  if(!switchingList) return false;
1092  auto swNode = switchingList->first_node("Switching");
1093  while(swNode) {
1094  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1095  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1096  swNode = swNode->next_sibling("Switching");
1097  }
1098  inductor->SetSwitchingData(swData);
1099 
1100  inductor->SetElectricalData(data);
1101 
1102  if(swData.swTime.size() != 0) inductor->SetDynamicEvent(true);
1103 
1104  elementList.push_back(inductor);
1105  inductorList.push_back(inductor);
1106  inductorNode = inductorNode->next_sibling("Inductor");
1107  } //}
1108 
1109  //{ Line
1110  auto lineListNode = elementsNode->first_node("LineList");
1111  if(!lineListNode) return false;
1112  auto lineNode = lineListNode->first_node("Line");
1113  while(lineNode) {
1114  Line* line = new Line();
1115 
1116  auto cadPropNode = lineNode->first_node("CADProperties");
1117  if(!cadPropNode) return false;
1118 
1119  // Get nodes points
1120  std::vector<wxPoint2DDouble> ptsList;
1121  auto nodePosList = cadPropNode->first_node("NodeList");
1122  if(!nodePosList) return false;
1123  auto nodePos = nodePosList->first_node("Node");
1124  while(nodePos) {
1125  double nodePosX = GetNodeValueDouble(nodePos, "X");
1126  double nodePosY = GetNodeValueDouble(nodePos, "Y");
1127  ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
1128  nodePos = nodePos->next_sibling("Node");
1129  }
1130 
1131  // Get parents IDs
1132  auto parentIDList = cadPropNode->first_node("ParentIDList");
1133  if(!parentIDList) return false;
1134  auto parentNode = parentIDList->first_node("ParentID");
1135  long parentID[2] = {-1, -1};
1136  while(parentNode) {
1137  long index = 0;
1138  wxString(parentNode->first_attribute("ID")->value()).ToLong(&index);
1139  wxString(parentNode->value()).ToCLong(&parentID[index]);
1140  parentNode = parentNode->next_sibling("ParentID");
1141  }
1142 
1143  // Set parents (if have)
1144  Bus *parent1, *parent2;
1145  if(parentID[0] == -1) {
1146  parent1 = new Bus(ptsList[0]);
1147  line->AddParent(parent1, ptsList[0]);
1148  } else {
1149  parent1 = busList[parentID[0]];
1150  line->AddParent(parent1, ptsList[0]);
1151  }
1152  if(parentID[1] == -1) {
1153  parent2 = new Bus(ptsList[ptsList.size() - 1]);
1154  line->AddParent(parent2, ptsList[ptsList.size() - 1]);
1155  } else {
1156  parent2 = busList[parentID[1]];
1157  line->AddParent(parent2, ptsList[ptsList.size() - 1]);
1158  }
1159 
1160  // Add the others nodes (if have)
1161  std::vector<wxPoint2DDouble> midPts;
1162  for(int i = 1; i < (int)ptsList.size() - 1; i++) midPts.push_back(ptsList[i]);
1163  std::vector<wxPoint2DDouble> edgesPts = line->GetPointList();
1164  edgesPts.insert(edgesPts.begin() + 2, midPts.begin(), midPts.end());
1165  line->SetPointList(edgesPts);
1166 
1167  if(parentID[0] == -1) {
1168  line->RemoveParent(parent1);
1169  delete parent1;
1170  }
1171  if(parentID[1] == -1) {
1172  line->RemoveParent(parent2);
1173  delete parent2;
1174  }
1175 
1176  auto electricalProp = lineNode->first_node("ElectricalProperties");
1177  if(!electricalProp) return false;
1178 
1179  line->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1180  LineElectricalData data = line->GetElectricalData();
1181  data.name = electricalProp->first_node("Name")->value();
1182  data.nominalVoltage = GetNodeValueDouble(electricalProp, "NominalVoltage");
1183  data.nominalVoltageUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalVoltage", "UnitID");
1184  data.nominalPower = GetNodeValueDouble(electricalProp, "NominalPower");
1185  data.nominalPowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalPower", "UnitID");
1186  data.resistance = GetNodeValueDouble(electricalProp, "Resistance");
1187  data.resistanceUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "Resistance", "UnitID");
1188  data.indReactance = GetNodeValueDouble(electricalProp, "IndReactance");
1189  data.indReactanceUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "IndReactance", "UnitID");
1190  data.capSusceptance = GetNodeValueDouble(electricalProp, "CapSusceptance");
1191  data.capSusceptanceUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "CapSusceptance", "UnitID");
1192  data.lineSize = GetNodeValueDouble(electricalProp, "LineSize");
1193  data.useLinePower = GetNodeValueInt(electricalProp, "UseLinePower");
1194 
1195  auto fault = electricalProp->first_node("Fault");
1196  data.zeroResistance = GetNodeValueDouble(fault, "ZeroResistance");
1197  data.zeroIndReactance = GetNodeValueDouble(fault, "ZeroIndReactance");
1198  data.zeroCapSusceptance = GetNodeValueDouble(fault, "ZeroCapSusceptance");
1199 
1200  SwitchingData swData;
1201  auto switchingList = electricalProp->first_node("SwitchingList");
1202  if(!switchingList) return false;
1203  auto swNode = switchingList->first_node("Switching");
1204  while(swNode) {
1205  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1206  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1207  swNode = swNode->next_sibling("Switching");
1208  }
1209  line->SetSwitchingData(swData);
1210 
1211  line->SetElectricalData(data);
1212 
1213  if(swData.swTime.size() != 0) line->SetDynamicEvent(true);
1214 
1215  elementList.push_back(line);
1216  lineList.push_back(line);
1217  lineNode = lineNode->next_sibling("Line");
1218  } //}
1219 
1220  //{ Load
1221  auto loadListNode = elementsNode->first_node("LoadList");
1222  if(!loadListNode) return false;
1223  auto loadNode = loadListNode->first_node("Load");
1224  while(loadNode) {
1225  Load* load = new Load();
1226 
1227  auto cadPropNode = loadNode->first_node("CADProperties");
1228  if(!cadPropNode) return false;
1229 
1230  auto position = cadPropNode->first_node("Position");
1231  double posX = GetNodeValueDouble(position, "X");
1232  double posY = GetNodeValueDouble(position, "Y");
1233  auto size = cadPropNode->first_node("Size");
1234  double width = GetNodeValueDouble(size, "Width");
1235  double height = GetNodeValueDouble(size, "Height");
1236  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1237  auto nodePosition = cadPropNode->first_node("NodePosition");
1238  double nodePosX = GetNodeValueDouble(nodePosition, "X");
1239  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
1240  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
1241  if(parentID == -1) {
1242  // If the element has no parent, create a temporary one, remove and delete.
1243  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
1244  load->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1245  load->StartMove(load->GetPosition());
1246  load->Move(wxPoint2DDouble(posX, posY));
1247  load->RemoveParent(parent);
1248  delete parent;
1249  } else {
1250  Bus* parent = busList[parentID];
1251  load->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1252  load->StartMove(load->GetPosition());
1253  load->Move(wxPoint2DDouble(posX, posY));
1254  }
1255  load->SetWidth(width);
1256  load->SetHeight(height);
1257 
1258  int numRot = angle / load->GetRotationAngle();
1259  bool clockwise = true;
1260  if(numRot < 0) {
1261  numRot = std::abs(numRot);
1262  clockwise = false;
1263  }
1264  for(int i = 0; i < numRot; i++) load->Rotate(clockwise);
1265 
1266  auto electricalProp = loadNode->first_node("ElectricalProperties");
1267  if(!electricalProp) return false;
1268 
1269  load->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1270  LoadElectricalData data = load->GetElectricalData();
1271  data.name = electricalProp->first_node("Name")->value();
1272  data.activePower = GetNodeValueDouble(electricalProp, "ActivePower");
1273  data.activePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ActivePower", "UnitID");
1274  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
1275  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
1276  data.loadType = (LoadType)GetNodeValueInt(electricalProp, "LoadType");
1277 
1278  SwitchingData swData;
1279  auto switchingList = electricalProp->first_node("SwitchingList");
1280  if(!switchingList) return false;
1281  auto swNode = switchingList->first_node("Switching");
1282  while(swNode) {
1283  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1284  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1285  swNode = swNode->next_sibling("Switching");
1286  }
1287  load->SetSwitchingData(swData);
1288 
1289  load->SetElectricalData(data);
1290 
1291  if(swData.swTime.size() != 0) load->SetDynamicEvent(true);
1292 
1293  elementList.push_back(load);
1294  loadList.push_back(load);
1295  loadNode = loadNode->next_sibling("Load");
1296  } //}
1297 
1298  //{ SyncGenerator
1299  auto syncGeneratorListNode = elementsNode->first_node("SyncGeneratorList");
1300  if(!syncGeneratorListNode) return false;
1301  auto syncGeneratorNode = syncGeneratorListNode->first_node("SyncGenerator");
1302  while(syncGeneratorNode) {
1303  SyncGenerator* syncGenerator = new SyncGenerator();
1304 
1305  auto cadPropNode = syncGeneratorNode->first_node("CADProperties");
1306  if(!cadPropNode) return false;
1307 
1308  auto position = cadPropNode->first_node("Position");
1309  double posX = GetNodeValueDouble(position, "X");
1310  double posY = GetNodeValueDouble(position, "Y");
1311  auto size = cadPropNode->first_node("Size");
1312  double width = GetNodeValueDouble(size, "Width");
1313  double height = GetNodeValueDouble(size, "Height");
1314  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1315  auto nodePosition = cadPropNode->first_node("NodePosition");
1316  double nodePosX = GetNodeValueDouble(nodePosition, "X");
1317  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
1318  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
1319  if(parentID == -1) {
1320  // If the element has no parent, create a temporary one, remove and delete.
1321  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
1322  syncGenerator->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1323  syncGenerator->StartMove(syncGenerator->GetPosition());
1324  syncGenerator->Move(wxPoint2DDouble(posX, posY));
1325  syncGenerator->RemoveParent(parent);
1326  delete parent;
1327  } else {
1328  Bus* parent = busList[parentID];
1329  syncGenerator->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1330  syncGenerator->StartMove(syncGenerator->GetPosition());
1331  syncGenerator->Move(wxPoint2DDouble(posX, posY));
1332  }
1333  syncGenerator->SetWidth(width);
1334  syncGenerator->SetHeight(height);
1335 
1336  int numRot = angle / syncGenerator->GetRotationAngle();
1337  bool clockwise = true;
1338  if(numRot < 0) {
1339  numRot = std::abs(numRot);
1340  clockwise = false;
1341  }
1342  for(int i = 0; i < numRot; i++) syncGenerator->Rotate(clockwise);
1343 
1344  auto electricalProp = syncGeneratorNode->first_node("ElectricalProperties");
1345  if(!electricalProp) return false;
1346 
1347  syncGenerator->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1348  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
1349  data.name = electricalProp->first_node("Name")->value();
1350  data.nominalPower = GetNodeValueDouble(electricalProp, "NominalPower");
1351  data.nominalPowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalPower", "UnitID");
1352  data.nominalVoltage = GetNodeValueDouble(electricalProp, "NominalVoltage");
1353  data.nominalVoltageUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalVoltage", "UnitID");
1354  data.activePower = GetNodeValueDouble(electricalProp, "ActivePower");
1355  data.activePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ActivePower", "UnitID");
1356  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
1357  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
1358  data.haveMaxReactive = GetNodeValueInt(electricalProp, "HaveMaxReactive");
1359  data.maxReactive = GetNodeValueDouble(electricalProp, "MaxReactive");
1360  data.maxReactiveUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "MaxReactive", "UnitID");
1361  data.haveMinReactive = GetNodeValueInt(electricalProp, "HaveMinReactive");
1362  data.minReactive = GetNodeValueDouble(electricalProp, "MinReactive");
1363  data.minReactiveUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "MinReactive", "UnitID");
1364  data.useMachineBase = GetNodeValueInt(electricalProp, "UseMachineBase");
1365 
1366  auto fault = electricalProp->first_node("Fault");
1367  if(!fault) return false;
1368  data.positiveResistance = GetNodeValueDouble(fault, "PositiveResistance");
1369  data.positiveReactance = GetNodeValueDouble(fault, "PositiveReactance");
1370  data.negativeResistance = GetNodeValueDouble(fault, "NegativeResistance");
1371  data.negativeReactance = GetNodeValueDouble(fault, "NegativeReactance");
1372  data.zeroResistance = GetNodeValueDouble(fault, "ZeroResistance");
1373  data.zeroReactance = GetNodeValueDouble(fault, "ZeroReactance");
1374  data.groundResistance = GetNodeValueDouble(fault, "GroundResistance");
1375  data.groundReactance = GetNodeValueDouble(fault, "GroundReactance");
1376  data.groundNeutral = GetNodeValueInt(fault, "GroundNeutral");
1377 
1378  auto stability = electricalProp->first_node("Stability");
1379  if(!stability) return false;
1380  data.plotSyncMachine = GetNodeValueInt(stability, "PlotSyncMachine");
1381  data.inertia = GetNodeValueDouble(stability, "Inertia");
1382  data.damping = GetNodeValueDouble(stability, "Damping");
1383  data.useAVR = GetNodeValueInt(stability, "UseAVR");
1384  data.useSpeedGovernor = GetNodeValueInt(stability, "UseSpeedGovernor");
1385  data.armResistance = GetNodeValueDouble(stability, "ArmResistance");
1386  data.potierReactance = GetNodeValueDouble(stability, "PotierReactance");
1387  data.satFactor = GetNodeValueDouble(stability, "SatFactor");
1388  data.syncXd = GetNodeValueDouble(stability, "SyncXd");
1389  data.syncXq = GetNodeValueDouble(stability, "SyncXq");
1390  data.transXd = GetNodeValueDouble(stability, "TransXd");
1391  data.transXq = GetNodeValueDouble(stability, "TransXq");
1392  data.transTd0 = GetNodeValueDouble(stability, "TransTd0");
1393  data.transTq0 = GetNodeValueDouble(stability, "TransTq0");
1394  data.subXd = GetNodeValueDouble(stability, "SubXd");
1395  data.subXq = GetNodeValueDouble(stability, "SubXq");
1396  data.subTd0 = GetNodeValueDouble(stability, "SubTd0");
1397  data.subTq0 = GetNodeValueDouble(stability, "SubTq0");
1398 
1399  auto avr = stability->first_node("AVR");
1400  if(!avr) return false;
1401  if(!OpenControlElements(doc, avr, data.avr)) return false;
1402 
1403  auto speedGov = stability->first_node("SpeedGovernor");
1404  if(!speedGov) return false;
1405  if(!OpenControlElements(doc, speedGov, data.speedGov)) return false;
1406 
1407  SwitchingData swData;
1408  auto switchingList = electricalProp->first_node("SwitchingList");
1409  if(!switchingList) return false;
1410  auto swNode = switchingList->first_node("Switching");
1411  while(swNode) {
1412  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1413  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1414  swNode = swNode->next_sibling("Switching");
1415  }
1416  syncGenerator->SetSwitchingData(swData);
1417 
1418  syncGenerator->SetElectricalData(data);
1419 
1420  if(swData.swTime.size() != 0) syncGenerator->SetDynamicEvent(true);
1421 
1422  elementList.push_back(syncGenerator);
1423  syncGeneratorList.push_back(syncGenerator);
1424  syncGeneratorNode = syncGeneratorNode->next_sibling("SyncGenerator");
1425  } //}
1426 
1427  //{ SyncMotor
1428  auto syncMotorListNode = elementsNode->first_node("SyncMotorList");
1429  if(!syncMotorListNode) return false;
1430  auto syncMotorNode = syncMotorListNode->first_node("SyncMotor");
1431  while(syncMotorNode) {
1432  SyncMotor* syncMotor = new SyncMotor();
1433 
1434  auto cadPropNode = syncMotorNode->first_node("CADProperties");
1435  if(!cadPropNode) return false;
1436 
1437  auto position = cadPropNode->first_node("Position");
1438  double posX = GetNodeValueDouble(position, "X");
1439  double posY = GetNodeValueDouble(position, "Y");
1440  auto size = cadPropNode->first_node("Size");
1441  double width = GetNodeValueDouble(size, "Width");
1442  double height = GetNodeValueDouble(size, "Height");
1443  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1444  auto nodePosition = cadPropNode->first_node("NodePosition");
1445  double nodePosX = GetNodeValueDouble(nodePosition, "X");
1446  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
1447  int parentID = GetNodeValueInt(cadPropNode, "ParentID");
1448  if(parentID == -1) {
1449  // If the element has no parent, create a temporary one, remove and delete.
1450  Bus* parent = new Bus(wxPoint2DDouble(nodePosX, nodePosY));
1451  syncMotor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1452  syncMotor->StartMove(syncMotor->GetPosition());
1453  syncMotor->Move(wxPoint2DDouble(posX, posY));
1454  syncMotor->RemoveParent(parent);
1455  delete parent;
1456  } else {
1457  Bus* parent = busList[parentID];
1458  syncMotor->AddParent(parent, wxPoint2DDouble(nodePosX, nodePosY));
1459  syncMotor->StartMove(syncMotor->GetPosition());
1460  syncMotor->Move(wxPoint2DDouble(posX, posY));
1461  }
1462  syncMotor->SetWidth(width);
1463  syncMotor->SetHeight(height);
1464 
1465  int numRot = angle / syncMotor->GetRotationAngle();
1466  bool clockwise = true;
1467  if(numRot < 0) {
1468  numRot = std::abs(numRot);
1469  clockwise = false;
1470  }
1471  for(int i = 0; i < numRot; i++) syncMotor->Rotate(clockwise);
1472 
1473  auto electricalProp = syncMotorNode->first_node("ElectricalProperties");
1474  if(!electricalProp) return false;
1475 
1476  syncMotor->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1477  SyncMotorElectricalData data = syncMotor->GetElectricalData();
1478  data.name = electricalProp->first_node("Name")->value();
1479  data.nominalPower = GetNodeValueDouble(electricalProp, "NominalPower");
1480  data.nominalPowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalPower", "UnitID");
1481  // data.nominalVoltage = GetNodeValueDouble(electricalProp, "NominalVoltage");
1482  // data.nominalVoltageUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalVoltage", "UnitID");
1483  data.activePower = GetNodeValueDouble(electricalProp, "ActivePower");
1484  data.activePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ActivePower", "UnitID");
1485  data.reactivePower = GetNodeValueDouble(electricalProp, "ReactivePower");
1486  data.reactivePowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID");
1487  data.haveMaxReactive = GetNodeValueInt(electricalProp, "HaveMaxReactive");
1488  data.maxReactive = GetNodeValueDouble(electricalProp, "MaxReactive");
1489  data.maxReactiveUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "MaxReactive", "UnitID");
1490  data.haveMinReactive = GetNodeValueInt(electricalProp, "HaveMinReactive");
1491  data.minReactive = GetNodeValueDouble(electricalProp, "MinReactive");
1492  data.minReactiveUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "MinReactive", "UnitID");
1493  data.useMachineBase = GetNodeValueInt(electricalProp, "UseMachineBase");
1494 
1495  auto fault = electricalProp->first_node("Fault");
1496  if(!fault) return false;
1497  data.positiveResistance = GetNodeValueDouble(fault, "PositiveResistance");
1498  data.positiveReactance = GetNodeValueDouble(fault, "PositiveReactance");
1499  data.negativeResistance = GetNodeValueDouble(fault, "NegativeResistance");
1500  data.negativeReactance = GetNodeValueDouble(fault, "NegativeReactance");
1501  data.zeroResistance = GetNodeValueDouble(fault, "ZeroResistance");
1502  data.zeroReactance = GetNodeValueDouble(fault, "ZeroReactance");
1503  data.groundResistance = GetNodeValueDouble(fault, "GroundResistance");
1504  data.groundReactance = GetNodeValueDouble(fault, "GroundReactance");
1505  data.groundNeutral = GetNodeValueInt(fault, "GroundNeutral");
1506 
1507  /*SwitchingData swData;
1508  auto switchingList = electricalProp->first_node("SwitchingList");
1509  if(!switchingList) return false;
1510  auto swNode = switchingList->first_node("Switching");
1511  while(swNode) {
1512  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1513  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1514  swNode = swNode->next_sibling("Switching");
1515  }
1516  syncMotor->SetSwitchingData(swData);*/
1517 
1518  syncMotor->SetElectricalData(data);
1519  elementList.push_back(syncMotor);
1520  syncMotorList.push_back(syncMotor);
1521  syncMotorNode = syncMotorNode->next_sibling("SyncMotor");
1522  } //}
1523 
1524  //{ Transformer
1525  auto transformerListNode = elementsNode->first_node("TransformerList");
1526  if(!transformerListNode) return false;
1527  auto transfomerNode = transformerListNode->first_node("Transfomer");
1528  while(transfomerNode) {
1529  Transformer* transformer = new Transformer();
1530 
1531  auto cadPropNode = transfomerNode->first_node("CADProperties");
1532  if(!cadPropNode) return false;
1533 
1534  auto position = cadPropNode->first_node("Position");
1535  double posX = GetNodeValueDouble(position, "X");
1536  double posY = GetNodeValueDouble(position, "Y");
1537  auto size = cadPropNode->first_node("Size");
1538  double width = GetNodeValueDouble(size, "Width");
1539  double height = GetNodeValueDouble(size, "Height");
1540  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1541 
1542  // Get nodes points
1543  std::vector<wxPoint2DDouble> ptsList;
1544  auto nodePosList = cadPropNode->first_node("NodeList");
1545  if(!nodePosList) return false;
1546  auto nodePos = nodePosList->first_node("Node");
1547  while(nodePos) {
1548  double nodePosX = GetNodeValueDouble(nodePos, "X");
1549  double nodePosY = GetNodeValueDouble(nodePos, "Y");
1550  ptsList.push_back(wxPoint2DDouble(nodePosX, nodePosY));
1551  nodePos = nodePos->next_sibling("Node");
1552  }
1553 
1554  // Get parents IDs
1555  auto parentIDList = cadPropNode->first_node("ParentIDList");
1556  if(!parentIDList) return false;
1557  auto parentNode = parentIDList->first_node("ParentID");
1558  long parentID[2] = {-1, -1};
1559  while(parentNode) {
1560  long index = 0;
1561  wxString(parentNode->first_attribute("ID")->value()).ToLong(&index);
1562  wxString(parentNode->value()).ToCLong(&parentID[index]);
1563  parentNode = parentNode->next_sibling("ParentID");
1564  }
1565 
1566  // Set parents (if have)
1567  Bus *parent1, *parent2;
1568  if(parentID[0] == -1) {
1569  parent1 = new Bus(ptsList[0]);
1570  transformer->AddParent(parent1, ptsList[0]);
1571  } else {
1572  parent1 = busList[parentID[0]];
1573  transformer->AddParent(parent1, ptsList[0]);
1574  }
1575  if(parentID[1] == -1) {
1576  parent2 = new Bus(ptsList[ptsList.size() - 1]);
1577  transformer->AddParent(parent2, ptsList[ptsList.size() - 1]);
1578  } else {
1579  parent2 = busList[parentID[1]];
1580  transformer->AddParent(parent2, ptsList[ptsList.size() - 1]);
1581  }
1582 
1583  transformer->StartMove(transformer->GetPosition());
1584  transformer->Move(wxPoint2DDouble(posX, posY));
1585 
1586  if(parentID[0] == -1) {
1587  transformer->RemoveParent(parent1);
1588  delete parent1;
1589  }
1590  if(parentID[1] == -1) {
1591  transformer->RemoveParent(parent2);
1592  delete parent2;
1593  }
1594 
1595  transformer->SetWidth(width);
1596  transformer->SetHeight(height);
1597 
1598  int numRot = angle / transformer->GetRotationAngle();
1599  bool clockwise = true;
1600  if(numRot < 0) {
1601  numRot = std::abs(numRot);
1602  clockwise = false;
1603  }
1604  for(int i = 0; i < numRot; i++) transformer->Rotate(clockwise);
1605 
1606  auto electricalProp = transfomerNode->first_node("ElectricalProperties");
1607  if(!electricalProp) return false;
1608 
1609  transformer->SetOnline(GetNodeValueInt(electricalProp, "IsOnline"));
1610  TransformerElectricalData data = transformer->GetElectricalData();
1611  data.name = electricalProp->first_node("Name")->value();
1612  data.primaryNominalVoltage = GetNodeValueDouble(electricalProp, "PrimaryNominalVoltage");
1613  data.primaryNominalVoltageUnit =
1614  (ElectricalUnit)GetAttributeValueInt(electricalProp, "PrimaryNominalVoltage", "UnitID");
1615  data.secondaryNominalVoltage = GetNodeValueDouble(electricalProp, "SecondaryNominalVoltage");
1616  data.secondaryNominalVoltageUnit =
1617  (ElectricalUnit)GetAttributeValueInt(electricalProp, "SecondaryNominalVoltage", "UnitID");
1618  data.nominalPower = GetNodeValueDouble(electricalProp, "NominalPower");
1619  data.nominalPowerUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "NominalPower", "UnitID");
1620  data.resistance = GetNodeValueDouble(electricalProp, "Resistance");
1621  data.resistanceUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "Resistance", "UnitID");
1622  data.indReactance = GetNodeValueDouble(electricalProp, "IndReactance");
1623  data.indReactanceUnit = (ElectricalUnit)GetAttributeValueInt(electricalProp, "IndReactance", "UnitID");
1624  data.connection = (TransformerConnection)GetNodeValueInt(electricalProp, "Connection");
1625  data.turnsRatio = GetNodeValueDouble(electricalProp, "TurnsRatio");
1626  data.phaseShift = GetNodeValueDouble(electricalProp, "PhaseShift");
1627  data.useTransformerPower = GetNodeValueInt(electricalProp, "UseTransfomerPower");
1628 
1629  auto fault = electricalProp->first_node("Fault");
1630  data.zeroResistance = GetNodeValueDouble(fault, "ZeroResistance");
1631  data.zeroIndReactance = GetNodeValueDouble(fault, "ZeroIndReactance");
1632  data.primaryGrndResistance = GetNodeValueDouble(fault, "PrimaryGrndResistance");
1633  data.primaryGrndReactance = GetNodeValueDouble(fault, "PrimaryGrndReactance");
1634  data.secondaryGrndResistance = GetNodeValueDouble(fault, "SecondaryGrndResistance");
1635  data.secondaryGrndReactance = GetNodeValueDouble(fault, "SecondaryGrndReactance");
1636 
1637  SwitchingData swData;
1638  auto switchingList = electricalProp->first_node("SwitchingList");
1639  if(!switchingList) return false;
1640  auto swNode = switchingList->first_node("Switching");
1641  while(swNode) {
1642  swData.swType.push_back((SwitchingType)GetNodeValueInt(swNode, "Type"));
1643  swData.swTime.push_back(GetNodeValueDouble(swNode, "Time"));
1644  swNode = swNode->next_sibling("Switching");
1645  }
1646  transformer->SetSwitchingData(swData);
1647 
1648  transformer->SetElectricaData(data);
1649 
1650  if(swData.swTime.size() != 0) transformer->SetDynamicEvent(true);
1651 
1652  elementList.push_back(transformer);
1653  transformerList.push_back(transformer);
1654  transfomerNode = transfomerNode->next_sibling("Transfomer");
1655  } //}
1656 
1657  m_workspace->SetElementList(elementList);
1658 
1659  //{ Text
1660  auto textListNode = elementsNode->first_node("TextList");
1661  if(!textListNode) return false;
1662  auto textNode = textListNode->first_node("Text");
1663  while(textNode) {
1664  auto cadPropNode = textNode->first_node("CADProperties");
1665  if(!cadPropNode) return false;
1666 
1667  auto position = cadPropNode->first_node("Position");
1668  double posX = GetNodeValueDouble(position, "X");
1669  double posY = GetNodeValueDouble(position, "Y");
1670  auto size = cadPropNode->first_node("Size");
1671  double width = GetNodeValueDouble(size, "Width");
1672  double height = GetNodeValueDouble(size, "Height");
1673  double angle = GetNodeValueDouble(cadPropNode, "Angle");
1674 
1675  Text* text = new Text(wxPoint2DDouble(posX, posY));
1676 
1677  text->SetWidth(width);
1678  text->SetHeight(height);
1679 
1680  auto textProperties = textNode->first_node("TextProperties");
1681  if(!textProperties) return false;
1682 
1683  text->SetElementType((ElementType)GetNodeValueDouble(textProperties, "ElementType"));
1684  text->SetDataType((DataType)GetNodeValueDouble(textProperties, "DataType"));
1685  text->SetUnit((ElectricalUnit)GetNodeValueDouble(textProperties, "DataUnit"));
1686  text->SetDirection(GetNodeValueDouble(textProperties, "Direction"));
1687  text->SetDecimalPlaces(GetNodeValueDouble(textProperties, "DecimalPlaces"));
1688 
1689  text->SetElementNumber(GetNodeValueInt(textProperties, "ElementNumber"));
1690  switch(text->GetElementType()) {
1691  case TYPE_NONE:
1692  break;
1693  case TYPE_BUS: {
1694  Bus* bus = busList[text->GetElementNumber()];
1695  text->SetElement(bus);
1696  } break;
1697  case TYPE_CAPACITOR: {
1698  Capacitor* capacitor = capacitorList[text->GetElementNumber()];
1699  text->SetElement(capacitor);
1700  } break;
1701  case TYPE_IND_MOTOR: {
1702  IndMotor* indMotor = indMotorList[text->GetElementNumber()];
1703  text->SetElement(indMotor);
1704  } break;
1705  case TYPE_INDUCTOR: {
1706  Inductor* inductor = inductorList[text->GetElementNumber()];
1707  text->SetElement(inductor);
1708  } break;
1709  case TYPE_LINE: {
1710  Line* line = lineList[text->GetElementNumber()];
1711  text->SetElement(line);
1712  } break;
1713  case TYPE_LOAD: {
1714  Load* load = loadList[text->GetElementNumber()];
1715  text->SetElement(load);
1716  } break;
1717  case TYPE_SYNC_GENERATOR: {
1718  SyncGenerator* syncGenerator = syncGeneratorList[text->GetElementNumber()];
1719  text->SetElement(syncGenerator);
1720  } break;
1721  case TYPE_SYNC_MOTOR: {
1722  SyncMotor* syncMotor = syncMotorList[text->GetElementNumber()];
1723  text->SetElement(syncMotor);
1724  } break;
1725  case TYPE_TRANSFORMER: {
1726  Transformer* transformer = transformerList[text->GetElementNumber()];
1727  text->SetElement(transformer);
1728  } break;
1729  }
1730 
1731  int numRot = angle / text->GetRotationAngle();
1732  bool clockwise = true;
1733  if(numRot < 0) {
1734  numRot = std::abs(numRot);
1735  clockwise = false;
1736  }
1737  for(int i = 0; i < numRot; i++) text->Rotate(clockwise);
1738 
1739  textList.push_back(text);
1740  textNode = textNode->next_sibling("Text");
1741  } //}
1742 
1743  m_workspace->SetTextList(textList);
1744  return true;
1745 }
1746 
1747 void FileHanding::SaveControl(wxFileName path)
1748 {
1749  // Same process present in SaveProject():
1750  std::ofstream writeProjectsFile(path.GetFullPath());
1751  writeProjectsFile.close();
1752 
1753  rapidxml::xml_document<> doc;
1754  rapidxml::file<> xmlFile(path.GetFullPath().mb_str());
1755  doc.parse<0>(xmlFile.data());
1756 
1757  rapidxml::xml_node<>* decl = doc.allocate_node(rapidxml::node_declaration);
1758  rapidxml::xml_attribute<>* ver = doc.allocate_attribute("version", "1.0");
1759  rapidxml::xml_attribute<>* encoding = doc.allocate_attribute("encoding", "utf-8");
1760  decl->append_attribute(ver);
1761  decl->append_attribute(encoding);
1762  doc.append_node(decl);
1763 
1764  rapidxml::xml_node<>* rootNode = doc.allocate_node(rapidxml::node_element, "Control");
1765  doc.append_node(rootNode);
1766 
1767  rapidxml::xml_node<>* projectNameNode = AppendNode(doc, rootNode, "Name");
1768  SetNodeValue(doc, projectNameNode, path.GetName());
1769 
1770  auto elementsNode = AppendNode(doc, rootNode, "ControlElements");
1771  SaveControlElements(doc, elementsNode);
1772  std::ofstream writeXML(path.GetFullPath());
1773  writeXML << doc;
1774  writeXML.close();
1775 }
1776 
1777 bool FileHanding::OpenControl(wxFileName path,
1778  std::vector<ControlElement*>& ctrlElementList,
1779  std::vector<ConnectionLine*>& ctrlConnectionList)
1780 {
1781  rapidxml::xml_document<> doc;
1782  rapidxml::file<> xmlFile(path.GetFullPath().mb_str());
1783 
1784  doc.parse<0>(xmlFile.data());
1785 
1786  auto projectNode = doc.first_node("Control");
1787  if(!projectNode) return false;
1788  // auto nameNode = projectNode->first_node("Name");
1789  // if(!nameNode) return false;
1790  // m_controlEditor->SetName(nameNode->value());
1791 
1792  // Open elements
1793  auto elementsNode = projectNode->first_node("ControlElements");
1794  if(!elementsNode) return false;
1795 
1796  // auto elementsNode = AppendNode(doc, rootNode, "ControlElements");
1797  ControlElementContainer* ctrlElementContainer = new ControlElementContainer();
1798  if(!OpenControlElements(doc, elementsNode, ctrlElementContainer)) return false;
1799  ctrlElementList = ctrlElementContainer->GetControlElementsList();
1800  ctrlConnectionList = ctrlElementContainer->GetConnectionLineList();
1801  return true;
1802 }
1803 
1804 void FileHanding::SaveControlElements(rapidxml::xml_document<>& doc,
1805  rapidxml::xml_node<>* elementsNode,
1806  ControlElementContainer* ctrlContainer)
1807 {
1808  if(!ctrlContainer) {
1809  ctrlContainer = new ControlElementContainer();
1810  ctrlContainer->FillContainer(m_controlEditor);
1811  }
1812 
1813  //{ Constant
1814  auto constsNode = AppendNode(doc, elementsNode, "ConstantList");
1815  auto constList = ctrlContainer->GetConstantList();
1816  for(auto it = constList.begin(), itEnd = constList.end(); it != itEnd; ++it) {
1817  Constant* constant = *it;
1818  auto constNode = AppendNode(doc, constsNode, "Constant");
1819  SetNodeAttribute(doc, constNode, "ID", constant->GetID());
1820  auto cadProp = AppendNode(doc, constNode, "CADProperties");
1821  auto position = AppendNode(doc, cadProp, "Position");
1822  auto posX = AppendNode(doc, position, "X");
1823  SetNodeValue(doc, posX, constant->GetPosition().m_x);
1824  auto posY = AppendNode(doc, position, "Y");
1825  SetNodeValue(doc, posY, constant->GetPosition().m_y);
1826  auto size = AppendNode(doc, cadProp, "Size");
1827  auto width = AppendNode(doc, size, "Width");
1828  SetNodeValue(doc, width, constant->GetWidth());
1829  auto height = AppendNode(doc, size, "Height");
1830  SetNodeValue(doc, height, constant->GetHeight());
1831  auto angle = AppendNode(doc, cadProp, "Angle");
1832  SetNodeValue(doc, angle, constant->GetAngle());
1833 
1834  // Nodes
1835  auto nodeList = AppendNode(doc, constNode, "NodeList");
1836  SaveControlNodes(doc, nodeList, constant->GetNodeList());
1837 
1838  // Control properties
1839  auto value = AppendNode(doc, constNode, "Value");
1840  SetNodeValue(doc, value, constant->GetValue());
1841  } //}
1842 
1843  //{ Exponential
1844  auto expsNode = AppendNode(doc, elementsNode, "ExponentialList");
1845  auto expList = ctrlContainer->GetExponentialList();
1846  for(auto it = expList.begin(), itEnd = expList.end(); it != itEnd; ++it) {
1847  Exponential* exponential = *it;
1848  auto expNode = AppendNode(doc, expsNode, "Exponential");
1849  SetNodeAttribute(doc, expNode, "ID", exponential->GetID());
1850  auto cadProp = AppendNode(doc, expNode, "CADProperties");
1851  auto position = AppendNode(doc, cadProp, "Position");
1852  auto posX = AppendNode(doc, position, "X");
1853  SetNodeValue(doc, posX, exponential->GetPosition().m_x);
1854  auto posY = AppendNode(doc, position, "Y");
1855  SetNodeValue(doc, posY, exponential->GetPosition().m_y);
1856  auto size = AppendNode(doc, cadProp, "Size");
1857  auto width = AppendNode(doc, size, "Width");
1858  SetNodeValue(doc, width, exponential->GetWidth());
1859  auto height = AppendNode(doc, size, "Height");
1860  SetNodeValue(doc, height, exponential->GetHeight());
1861  auto angle = AppendNode(doc, cadProp, "Angle");
1862  SetNodeValue(doc, angle, exponential->GetAngle());
1863 
1864  // Nodes
1865  auto nodeList = AppendNode(doc, expNode, "NodeList");
1866  SaveControlNodes(doc, nodeList, exponential->GetNodeList());
1867 
1868  // Control properties
1869  double a, b;
1870  exponential->GetValues(a, b);
1871  auto value = AppendNode(doc, expNode, "Value");
1872  auto aValue = AppendNode(doc, value, "A");
1873  SetNodeValue(doc, aValue, a);
1874  auto bValue = AppendNode(doc, value, "B");
1875  SetNodeValue(doc, bValue, b);
1876  } //}
1877 
1878  //{ Gain
1879  auto gainsNode = AppendNode(doc, elementsNode, "GainList");
1880  auto gainList = ctrlContainer->GetGainList();
1881  for(auto it = gainList.begin(), itEnd = gainList.end(); it != itEnd; ++it) {
1882  Gain* gain = *it;
1883  auto gainNode = AppendNode(doc, gainsNode, "Gain");
1884  SetNodeAttribute(doc, gainNode, "ID", gain->GetID());
1885  auto cadProp = AppendNode(doc, gainNode, "CADProperties");
1886  auto position = AppendNode(doc, cadProp, "Position");
1887  auto posX = AppendNode(doc, position, "X");
1888  SetNodeValue(doc, posX, gain->GetPosition().m_x);
1889  auto posY = AppendNode(doc, position, "Y");
1890  SetNodeValue(doc, posY, gain->GetPosition().m_y);
1891  auto size = AppendNode(doc, cadProp, "Size");
1892  auto width = AppendNode(doc, size, "Width");
1893  SetNodeValue(doc, width, gain->GetWidth());
1894  auto height = AppendNode(doc, size, "Height");
1895  SetNodeValue(doc, height, gain->GetHeight());
1896  auto angle = AppendNode(doc, cadProp, "Angle");
1897  SetNodeValue(doc, angle, gain->GetAngle());
1898 
1899  // Nodes
1900  auto nodeList = AppendNode(doc, gainNode, "NodeList");
1901  SaveControlNodes(doc, nodeList, gain->GetNodeList());
1902 
1903  // Control properties
1904  auto value = AppendNode(doc, gainNode, "Value");
1905  SetNodeValue(doc, value, gain->GetValue());
1906  } //}
1907 
1908  //{ IO
1909  auto iosNode = AppendNode(doc, elementsNode, "IOList");
1910  auto ioList = ctrlContainer->GetIOControlList();
1911  for(auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
1912  IOControl* io = *it;
1913  auto ioNode = AppendNode(doc, iosNode, "IO");
1914  SetNodeAttribute(doc, ioNode, "ID", io->GetID());
1915  auto cadProp = AppendNode(doc, ioNode, "CADProperties");
1916  auto position = AppendNode(doc, cadProp, "Position");
1917  auto posX = AppendNode(doc, position, "X");
1918  SetNodeValue(doc, posX, io->GetPosition().m_x);
1919  auto posY = AppendNode(doc, position, "Y");
1920  SetNodeValue(doc, posY, io->GetPosition().m_y);
1921  auto size = AppendNode(doc, cadProp, "Size");
1922  auto width = AppendNode(doc, size, "Width");
1923  SetNodeValue(doc, width, io->GetWidth());
1924  auto height = AppendNode(doc, size, "Height");
1925  SetNodeValue(doc, height, io->GetHeight());
1926  auto angle = AppendNode(doc, cadProp, "Angle");
1927  SetNodeValue(doc, angle, io->GetAngle());
1928 
1929  // Nodes
1930  auto nodeList = AppendNode(doc, ioNode, "NodeList");
1931  SaveControlNodes(doc, nodeList, io->GetNodeList());
1932 
1933  // Control properties
1934  auto value = AppendNode(doc, ioNode, "Value");
1935  SetNodeValue(doc, value, io->GetValue());
1936  auto ioFlags = AppendNode(doc, ioNode, "IOFlags");
1937  SetNodeValue(doc, ioFlags, io->GetIOFlags());
1938  } //}
1939 
1940  //{ Limiter
1941  auto limitersNode = AppendNode(doc, elementsNode, "LimiterList");
1942  auto limiterList = ctrlContainer->GetLimiterList();
1943  for(auto it = limiterList.begin(), itEnd = limiterList.end(); it != itEnd; ++it) {
1944  Limiter* limiter = *it;
1945  auto limiterNode = AppendNode(doc, limitersNode, "Limiter");
1946  SetNodeAttribute(doc, limiterNode, "ID", limiter->GetID());
1947  auto cadProp = AppendNode(doc, limiterNode, "CADProperties");
1948  auto position = AppendNode(doc, cadProp, "Position");
1949  auto posX = AppendNode(doc, position, "X");
1950  SetNodeValue(doc, posX, limiter->GetPosition().m_x);
1951  auto posY = AppendNode(doc, position, "Y");
1952  SetNodeValue(doc, posY, limiter->GetPosition().m_y);
1953  auto size = AppendNode(doc, cadProp, "Size");
1954  auto width = AppendNode(doc, size, "Width");
1955  SetNodeValue(doc, width, limiter->GetWidth());
1956  auto height = AppendNode(doc, size, "Height");
1957  SetNodeValue(doc, height, limiter->GetHeight());
1958  auto angle = AppendNode(doc, cadProp, "Angle");
1959  SetNodeValue(doc, angle, limiter->GetAngle());
1960 
1961  // Nodes
1962  auto nodeList = AppendNode(doc, limiterNode, "NodeList");
1963  SaveControlNodes(doc, nodeList, limiter->GetNodeList());
1964 
1965  // Control properties
1966  auto upLimit = AppendNode(doc, limiterNode, "UpperLimit");
1967  SetNodeValue(doc, upLimit, limiter->GetUpLimit());
1968  auto lowLimit = AppendNode(doc, limiterNode, "LowerLimit");
1969  SetNodeValue(doc, lowLimit, limiter->GetLowLimit());
1970  } //}
1971 
1972  //{ Multiplier
1973  auto multipliersNode = AppendNode(doc, elementsNode, "MultiplierList");
1974  auto multiplierList = ctrlContainer->GetMultiplierList();
1975  for(auto it = multiplierList.begin(), itEnd = multiplierList.end(); it != itEnd; ++it) {
1976  Multiplier* multiplier = *it;
1977  auto multiplierNode = AppendNode(doc, multipliersNode, "Multiplier");
1978  SetNodeAttribute(doc, multiplierNode, "ID", multiplier->GetID());
1979  auto cadProp = AppendNode(doc, multiplierNode, "CADProperties");
1980  auto position = AppendNode(doc, cadProp, "Position");
1981  auto posX = AppendNode(doc, position, "X");
1982  SetNodeValue(doc, posX, multiplier->GetPosition().m_x);
1983  auto posY = AppendNode(doc, position, "Y");
1984  SetNodeValue(doc, posY, multiplier->GetPosition().m_y);
1985  auto size = AppendNode(doc, cadProp, "Size");
1986  auto width = AppendNode(doc, size, "Width");
1987  SetNodeValue(doc, width, multiplier->GetWidth());
1988  auto height = AppendNode(doc, size, "Height");
1989  SetNodeValue(doc, height, multiplier->GetHeight());
1990  auto angle = AppendNode(doc, cadProp, "Angle");
1991  SetNodeValue(doc, angle, multiplier->GetAngle());
1992 
1993  // Nodes
1994  auto nodeList = AppendNode(doc, multiplierNode, "NodeList");
1995  SaveControlNodes(doc, nodeList, multiplier->GetNodeList());
1996  } //}
1997 
1998  //{ Rate limiter
1999  auto rateLimitersNode = AppendNode(doc, elementsNode, "RateLimiterList");
2000  auto rateLimiterList = ctrlContainer->GetRateLimiterList();
2001  for(auto it = rateLimiterList.begin(), itEnd = rateLimiterList.end(); it != itEnd; ++it) {
2002  RateLimiter* rateLimiter = *it;
2003  auto rateLimiterNode = AppendNode(doc, rateLimitersNode, "RateLimiter");
2004  SetNodeAttribute(doc, rateLimiterNode, "ID", rateLimiter->GetID());
2005  auto cadProp = AppendNode(doc, rateLimiterNode, "CADProperties");
2006  auto position = AppendNode(doc, cadProp, "Position");
2007  auto posX = AppendNode(doc, position, "X");
2008  SetNodeValue(doc, posX, rateLimiter->GetPosition().m_x);
2009  auto posY = AppendNode(doc, position, "Y");
2010  SetNodeValue(doc, posY, rateLimiter->GetPosition().m_y);
2011  auto size = AppendNode(doc, cadProp, "Size");
2012  auto width = AppendNode(doc, size, "Width");
2013  SetNodeValue(doc, width, rateLimiter->GetWidth());
2014  auto height = AppendNode(doc, size, "Height");
2015  SetNodeValue(doc, height, rateLimiter->GetHeight());
2016  auto angle = AppendNode(doc, cadProp, "Angle");
2017  SetNodeValue(doc, angle, rateLimiter->GetAngle());
2018 
2019  // Nodes
2020  auto nodeList = AppendNode(doc, rateLimiterNode, "NodeList");
2021  SaveControlNodes(doc, nodeList, rateLimiter->GetNodeList());
2022 
2023  // Control properties
2024  auto upLimit = AppendNode(doc, rateLimiterNode, "UpperLimit");
2025  SetNodeValue(doc, upLimit, rateLimiter->GetUpLimit());
2026  auto lowLimit = AppendNode(doc, rateLimiterNode, "LowerLimit");
2027  SetNodeValue(doc, lowLimit, rateLimiter->GetLowLimit());
2028  } //}
2029 
2030  //{ Sum
2031  auto sumsNode = AppendNode(doc, elementsNode, "SumList");
2032  auto sumList = ctrlContainer->GetSumList();
2033  for(auto it = sumList.begin(), itEnd = sumList.end(); it != itEnd; ++it) {
2034  Sum* sum = *it;
2035  auto sumNode = AppendNode(doc, sumsNode, "Sum");
2036  SetNodeAttribute(doc, sumNode, "ID", sum->GetID());
2037  auto cadProp = AppendNode(doc, sumNode, "CADProperties");
2038  auto position = AppendNode(doc, cadProp, "Position");
2039  auto posX = AppendNode(doc, position, "X");
2040  SetNodeValue(doc, posX, sum->GetPosition().m_x);
2041  auto posY = AppendNode(doc, position, "Y");
2042  SetNodeValue(doc, posY, sum->GetPosition().m_y);
2043  auto size = AppendNode(doc, cadProp, "Size");
2044  auto width = AppendNode(doc, size, "Width");
2045  SetNodeValue(doc, width, sum->GetWidth());
2046  auto height = AppendNode(doc, size, "Height");
2047  SetNodeValue(doc, height, sum->GetHeight());
2048  auto angle = AppendNode(doc, cadProp, "Angle");
2049  SetNodeValue(doc, angle, sum->GetAngle());
2050 
2051  // Nodes
2052  auto nodeList = AppendNode(doc, sumNode, "NodeList");
2053  SaveControlNodes(doc, nodeList, sum->GetNodeList());
2054 
2055  // Control properties
2056  auto signsNode = AppendNode(doc, sumNode, "Signs");
2057  auto signs = sum->GetSignalList();
2058  for(int i = 0; i < (int)signs.size(); ++i) {
2059  auto value = AppendNode(doc, signsNode, "Value");
2060  SetNodeValue(doc, value, static_cast<int>(signs[i]));
2061  }
2062 
2063  } //}
2064 
2065  //{ Transfer function
2066  auto tfsNode = AppendNode(doc, elementsNode, "TransferFunctionList");
2067  auto tfList = ctrlContainer->GetTFList();
2068  for(auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
2069  TransferFunction* tf = *it;
2070  auto tfNode = AppendNode(doc, tfsNode, "TransferFunction");
2071  SetNodeAttribute(doc, tfNode, "ID", tf->GetID());
2072  auto cadProp = AppendNode(doc, tfNode, "CADProperties");
2073  auto position = AppendNode(doc, cadProp, "Position");
2074  auto posX = AppendNode(doc, position, "X");
2075  SetNodeValue(doc, posX, tf->GetPosition().m_x);
2076  auto posY = AppendNode(doc, position, "Y");
2077  SetNodeValue(doc, posY, tf->GetPosition().m_y);
2078  auto size = AppendNode(doc, cadProp, "Size");
2079  auto width = AppendNode(doc, size, "Width");
2080  SetNodeValue(doc, width, tf->GetWidth());
2081  auto height = AppendNode(doc, size, "Height");
2082  SetNodeValue(doc, height, tf->GetHeight());
2083  auto angle = AppendNode(doc, cadProp, "Angle");
2084  SetNodeValue(doc, angle, tf->GetAngle());
2085 
2086  // Nodes
2087  auto nodeList = AppendNode(doc, tfNode, "NodeList");
2088  SaveControlNodes(doc, nodeList, tf->GetNodeList());
2089 
2090  // Control properties
2091  auto numeratorNode = AppendNode(doc, tfNode, "Numerator");
2092  auto numerator = tf->GetNumerator();
2093  for(int i = 0; i < (int)numerator.size(); ++i) {
2094  auto value = AppendNode(doc, numeratorNode, "Value");
2095  SetNodeValue(doc, value, numerator[i]);
2096  }
2097  auto denominatorNode = AppendNode(doc, tfNode, "Denominator");
2098  auto denominator = tf->GetDenominator();
2099  for(int i = 0; i < (int)denominator.size(); ++i) {
2100  auto value = AppendNode(doc, denominatorNode, "Value");
2101  SetNodeValue(doc, value, denominator[i]);
2102  }
2103  } //}
2104 
2105  //{ Connection line
2106  auto cLinesNode = AppendNode(doc, elementsNode, "ConnectionList");
2107  auto connLineList = ctrlContainer->GetConnectionLineList();
2108  for(auto it = connLineList.begin(), itEnd = connLineList.end(); it != itEnd; ++it) {
2109  ConnectionLine* cLine = *it;
2110  auto cLineNode = AppendNode(doc, cLinesNode, "Connection");
2111  SetNodeAttribute(doc, cLineNode, "ID", cLine->GetID());
2112 
2113  // CAD properties
2114  auto cadProp = AppendNode(doc, cLineNode, "CADProperties");
2115  auto offset = AppendNode(doc, cadProp, "Offset");
2116  SetNodeValue(doc, offset, cLine->GetOffset());
2117 
2118  // Parent list
2119  auto parentsNode = AppendNode(doc, cLineNode, "ParentList");
2120  auto parentList = cLine->GetParentList();
2121  int nodeIndex = 0;
2122  for(auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
2123  Element* parent = *itP;
2124  auto parentNode = AppendNode(doc, parentsNode, "Parent");
2125  auto elementID = AppendNode(doc, parentNode, "ElementID");
2126  SetNodeValue(doc, elementID, parent->GetID());
2127  auto nodeID = AppendNode(doc, parentNode, "NodeID");
2128  SetNodeValue(doc, nodeID, cLine->GetNodeList()[nodeIndex]->GetID());
2129  nodeIndex++;
2130  }
2131 
2132  auto parentLine = AppendNode(doc, cLineNode, "ParentLine");
2133  if(cLine->GetParentLine()) {
2134  ConnectionLine* parent = cLine->GetParentLine();
2135  SetNodeAttribute(doc, parentLine, "ID", parent->GetID());
2136  } else {
2137  SetNodeAttribute(doc, parentLine, "ID", -1);
2138  }
2139  } //}
2140 }
2141 
2142 bool FileHanding::OpenControlElements(rapidxml::xml_document<>& doc,
2143  rapidxml::xml_node<>* elementsNode,
2144  ControlElementContainer* ctrlContainer)
2145 {
2146  std::vector<ControlElement*> elementList;
2147  std::vector<ConnectionLine*> connectionList;
2148 
2149  //{ Constant
2150  auto constListNode = elementsNode->first_node("ConstantList");
2151  if(!constListNode) return false;
2152  auto constNode = constListNode->first_node("Constant");
2153  while(constNode) {
2154  int id = GetAttributeValueInt(constNode, "ID");
2155  Constant* constant = new Constant(id);
2156 
2157  auto cadPropNode = constNode->first_node("CADProperties");
2158  if(!cadPropNode) return false;
2159 
2160  auto position = cadPropNode->first_node("Position");
2161  double posX = GetNodeValueDouble(position, "X");
2162  double posY = GetNodeValueDouble(position, "Y");
2163  auto size = cadPropNode->first_node("Size");
2164  double width = GetNodeValueDouble(size, "Width");
2165  double height = GetNodeValueDouble(size, "Height");
2166  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2167 
2168  double value = GetNodeValueDouble(constNode, "Value");
2169 
2170  constant->SetWidth(width);
2171  constant->SetHeight(height);
2172  constant->SetAngle(angle);
2173  constant->SetPosition(wxPoint2DDouble(posX, posY));
2174  constant->StartMove(constant->GetPosition());
2175 
2176  constant->SetValue(value);
2177 
2178  std::vector<Node*> nodeVector;
2179  if(!OpenControlNodeList(constNode, nodeVector)) return false;
2180 
2181  constant->SetNodeList(nodeVector);
2182  constant->UpdatePoints();
2183  elementList.push_back(constant);
2184 
2185  constNode = constNode->next_sibling("Constant");
2186  } //}
2187 
2188  //{ Exponential
2189  auto expListNode = elementsNode->first_node("ExponentialList");
2190  if(!expListNode) return false;
2191  auto expNode = expListNode->first_node("Exponential");
2192  while(expNode) {
2193  int id = GetAttributeValueInt(expNode, "ID");
2194  Exponential* exponential = new Exponential(id);
2195 
2196  auto cadPropNode = expNode->first_node("CADProperties");
2197  if(!cadPropNode) return false;
2198 
2199  auto position = cadPropNode->first_node("Position");
2200  double posX = GetNodeValueDouble(position, "X");
2201  double posY = GetNodeValueDouble(position, "Y");
2202  auto size = cadPropNode->first_node("Size");
2203  double width = GetNodeValueDouble(size, "Width");
2204  double height = GetNodeValueDouble(size, "Height");
2205  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2206 
2207  auto value = expNode->first_node("Value");
2208  double a = GetNodeValueDouble(value, "A");
2209  double b = GetNodeValueDouble(value, "B");
2210 
2211  exponential->SetWidth(width);
2212  exponential->SetHeight(height);
2213  exponential->SetAngle(angle);
2214  exponential->SetPosition(wxPoint2DDouble(posX, posY));
2215  exponential->StartMove(exponential->GetPosition());
2216 
2217  exponential->SetValues(a, b);
2218 
2219  std::vector<Node*> nodeVector;
2220  if(!OpenControlNodeList(expNode, nodeVector)) return false;
2221 
2222  exponential->SetNodeList(nodeVector);
2223  exponential->UpdatePoints();
2224  elementList.push_back(exponential);
2225 
2226  expNode = expNode->next_sibling("Exponential");
2227  } //}
2228 
2229  //{ Gain
2230  auto gainListNode = elementsNode->first_node("GainList");
2231  if(!gainListNode) return false;
2232  auto gainNode = gainListNode->first_node("Gain");
2233  while(gainNode) {
2234  int id = GetAttributeValueInt(gainNode, "ID");
2235  Gain* gain = new Gain(id);
2236 
2237  auto cadPropNode = gainNode->first_node("CADProperties");
2238  if(!cadPropNode) return false;
2239 
2240  auto position = cadPropNode->first_node("Position");
2241  double posX = GetNodeValueDouble(position, "X");
2242  double posY = GetNodeValueDouble(position, "Y");
2243  auto size = cadPropNode->first_node("Size");
2244  double width = GetNodeValueDouble(size, "Width");
2245  double height = GetNodeValueDouble(size, "Height");
2246  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2247 
2248  double value = GetNodeValueDouble(gainNode, "Value");
2249 
2250  gain->SetWidth(width);
2251  gain->SetHeight(height);
2252  gain->SetAngle(angle);
2253  gain->SetPosition(wxPoint2DDouble(posX, posY));
2254  gain->SetValue(value);
2255  gain->StartMove(gain->GetPosition());
2256 
2257  std::vector<Node*> nodeVector;
2258  if(!OpenControlNodeList(gainNode, nodeVector)) return false;
2259 
2260  gain->SetNodeList(nodeVector);
2261  gain->UpdatePoints();
2262  elementList.push_back(gain);
2263 
2264  gainNode = gainNode->next_sibling("Gain");
2265  }
2266  //}
2267 
2268  //{ IO
2269  auto ioListNode = elementsNode->first_node("IOList");
2270  if(!ioListNode) return false;
2271  auto ioNode = ioListNode->first_node("IO");
2272  while(ioNode) {
2273  int id = GetAttributeValueInt(ioNode, "ID");
2274 
2275  auto cadPropNode = ioNode->first_node("CADProperties");
2276  if(!cadPropNode) return false;
2277 
2278  auto position = cadPropNode->first_node("Position");
2279  double posX = GetNodeValueDouble(position, "X");
2280  double posY = GetNodeValueDouble(position, "Y");
2281  auto size = cadPropNode->first_node("Size");
2282  double width = GetNodeValueDouble(size, "Width");
2283  double height = GetNodeValueDouble(size, "Height");
2284  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2285 
2286  std::vector<Node*> nodeVector;
2287  if(!OpenControlNodeList(ioNode, nodeVector)) return false;
2288 
2289  IOControl::IOFlags value = static_cast<IOControl::IOFlags>(GetNodeValueInt(ioNode, "Value"));
2290  int ioFlags = GetNodeValueInt(ioNode, "IOFlags");
2291 
2292  IOControl* io = new IOControl(ioFlags, id);
2293 
2294  io->SetWidth(width);
2295  io->SetHeight(height);
2296  io->SetAngle(angle);
2297  io->SetPosition(wxPoint2DDouble(posX, posY));
2298  io->SetValue(value);
2299  io->StartMove(io->GetPosition());
2300  io->SetNodeList(nodeVector);
2301  io->UpdatePoints();
2302  elementList.push_back(io);
2303 
2304  ioNode = ioNode->next_sibling("IO");
2305  }
2306  //}
2307 
2308  //{ Limiter
2309  auto limiterListNode = elementsNode->first_node("LimiterList");
2310  if(!limiterListNode) return false;
2311  auto limiterNode = limiterListNode->first_node("Limiter");
2312  while(limiterNode) {
2313  int id = GetAttributeValueInt(limiterNode, "ID");
2314  Limiter* limiter = new Limiter(id);
2315 
2316  auto cadPropNode = limiterNode->first_node("CADProperties");
2317  if(!cadPropNode) return false;
2318 
2319  auto position = cadPropNode->first_node("Position");
2320  double posX = GetNodeValueDouble(position, "X");
2321  double posY = GetNodeValueDouble(position, "Y");
2322  auto size = cadPropNode->first_node("Size");
2323  double width = GetNodeValueDouble(size, "Width");
2324  double height = GetNodeValueDouble(size, "Height");
2325  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2326 
2327  double upLimit = GetNodeValueDouble(limiterNode, "UpperLimit");
2328  double lowLimit = GetNodeValueDouble(limiterNode, "LowerLimit");
2329 
2330  std::vector<Node*> nodeVector;
2331  if(!OpenControlNodeList(limiterNode, nodeVector)) return false;
2332 
2333  limiter->SetWidth(width);
2334  limiter->SetHeight(height);
2335  limiter->SetAngle(angle);
2336  limiter->SetPosition(wxPoint2DDouble(posX, posY));
2337  limiter->SetUpLimit(upLimit);
2338  limiter->SetLowLimit(lowLimit);
2339 
2340  limiter->StartMove(limiter->GetPosition());
2341  limiter->SetNodeList(nodeVector);
2342  limiter->UpdatePoints();
2343  elementList.push_back(limiter);
2344 
2345  limiterNode = limiterNode->next_sibling("Limiter");
2346  }
2347  //}
2348 
2349  //{ Multiplier
2350  auto multiplierListNode = elementsNode->first_node("MultiplierList");
2351  if(!multiplierListNode) return false;
2352  auto multiplierNode = multiplierListNode->first_node("Multiplier");
2353  while(multiplierNode) {
2354  int id = GetAttributeValueInt(multiplierNode, "ID");
2355  Multiplier* multiplier = new Multiplier(id);
2356 
2357  auto cadPropNode = multiplierNode->first_node("CADProperties");
2358  if(!cadPropNode) return false;
2359 
2360  auto position = cadPropNode->first_node("Position");
2361  double posX = GetNodeValueDouble(position, "X");
2362  double posY = GetNodeValueDouble(position, "Y");
2363  auto size = cadPropNode->first_node("Size");
2364  double width = GetNodeValueDouble(size, "Width");
2365  double height = GetNodeValueDouble(size, "Height");
2366  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2367 
2368  std::vector<Node*> nodeVector;
2369  if(!OpenControlNodeList(multiplierNode, nodeVector)) return false;
2370 
2371  multiplier->SetWidth(width);
2372  multiplier->SetHeight(height);
2373  multiplier->SetAngle(angle);
2374  multiplier->SetPosition(wxPoint2DDouble(posX, posY));
2375 
2376  multiplier->StartMove(multiplier->GetPosition());
2377  multiplier->SetNodeList(nodeVector);
2378  multiplier->UpdatePoints();
2379  elementList.push_back(multiplier);
2380 
2381  multiplierNode = multiplierNode->next_sibling("Multiplier");
2382  }
2383  //}
2384 
2385  //{ Rate limiter
2386  auto rateLimiterListNode = elementsNode->first_node("RateLimiterList");
2387  if(!rateLimiterListNode) return false;
2388  auto rateLimiterNode = rateLimiterListNode->first_node("RateLimiter");
2389  while(rateLimiterNode) {
2390  int id = GetAttributeValueInt(rateLimiterNode, "ID");
2391  RateLimiter* limiter = new RateLimiter(id);
2392 
2393  auto cadPropNode = rateLimiterNode->first_node("CADProperties");
2394  if(!cadPropNode) return false;
2395 
2396  auto position = cadPropNode->first_node("Position");
2397  double posX = GetNodeValueDouble(position, "X");
2398  double posY = GetNodeValueDouble(position, "Y");
2399  auto size = cadPropNode->first_node("Size");
2400  double width = GetNodeValueDouble(size, "Width");
2401  double height = GetNodeValueDouble(size, "Height");
2402  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2403 
2404  double upLimit = GetNodeValueDouble(rateLimiterNode, "UpperLimit");
2405  double lowLimit = GetNodeValueDouble(rateLimiterNode, "LowerLimit");
2406 
2407  std::vector<Node*> nodeVector;
2408  if(!OpenControlNodeList(rateLimiterNode, nodeVector)) return false;
2409 
2410  limiter->SetWidth(width);
2411  limiter->SetHeight(height);
2412  limiter->SetAngle(angle);
2413  limiter->SetPosition(wxPoint2DDouble(posX, posY));
2414  limiter->SetUpLimit(upLimit);
2415  limiter->SetLowLimit(lowLimit);
2416 
2417  limiter->StartMove(limiter->GetPosition());
2418  limiter->SetNodeList(nodeVector);
2419  limiter->UpdatePoints();
2420  elementList.push_back(limiter);
2421 
2422  rateLimiterNode = rateLimiterNode->next_sibling("RateLimiter");
2423  }
2424  //}
2425 
2426  //{ Sum
2427  auto sumListNode = elementsNode->first_node("SumList");
2428  if(!sumListNode) return false;
2429  auto sumNode = sumListNode->first_node("Sum");
2430  while(sumNode) {
2431  int id = GetAttributeValueInt(sumNode, "ID");
2432  Sum* sum = new Sum(id);
2433 
2434  auto cadPropNode = sumNode->first_node("CADProperties");
2435  if(!cadPropNode) return false;
2436 
2437  auto position = cadPropNode->first_node("Position");
2438  double posX = GetNodeValueDouble(position, "X");
2439  double posY = GetNodeValueDouble(position, "Y");
2440  auto size = cadPropNode->first_node("Size");
2441  double width = GetNodeValueDouble(size, "Width");
2442  double height = GetNodeValueDouble(size, "Height");
2443  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2444 
2445  std::vector<Sum::Signal> signs;
2446  auto signsNode = sumNode->first_node("Signs");
2447  auto sign = signsNode->first_node("Value");
2448  while(sign) {
2449  long value;
2450  wxString(sign->value()).ToCLong(&value);
2451  signs.push_back(static_cast<Sum::Signal>(value));
2452  sign = sign->next_sibling("Value");
2453  }
2454  sum->SetSignalList(signs);
2455 
2456  std::vector<Node*> nodeVector;
2457  if(!OpenControlNodeList(sumNode, nodeVector)) return false;
2458 
2459  sum->SetWidth(width);
2460  sum->SetHeight(height);
2461  sum->SetAngle(angle);
2462  sum->SetPosition(wxPoint2DDouble(posX, posY));
2463 
2464  sum->StartMove(sum->GetPosition());
2465  sum->SetNodeList(nodeVector);
2466  sum->UpdatePoints();
2467  elementList.push_back(sum);
2468 
2469  sumNode = sumNode->next_sibling("Sum");
2470  }
2471  //}
2472 
2473  //{ Transfer function
2474  auto tfListNode = elementsNode->first_node("TransferFunctionList");
2475  if(!tfListNode) return false;
2476  auto tfNode = tfListNode->first_node("TransferFunction");
2477  while(tfNode) {
2478  int id = GetAttributeValueInt(tfNode, "ID");
2479  TransferFunction* tf = new TransferFunction(id);
2480 
2481  auto cadPropNode = tfNode->first_node("CADProperties");
2482  if(!cadPropNode) return false;
2483 
2484  auto position = cadPropNode->first_node("Position");
2485  double posX = GetNodeValueDouble(position, "X");
2486  double posY = GetNodeValueDouble(position, "Y");
2487  auto size = cadPropNode->first_node("Size");
2488  double width = GetNodeValueDouble(size, "Width");
2489  double height = GetNodeValueDouble(size, "Height");
2490  double angle = GetNodeValueDouble(cadPropNode, "Angle");
2491 
2492  std::vector<double> numerator, denominator;
2493  auto numeratorNode = tfNode->first_node("Numerator");
2494  auto nValue = numeratorNode->first_node("Value");
2495  while(nValue) {
2496  double value = 0.0;
2497  wxString(nValue->value()).ToCDouble(&value);
2498  numerator.push_back(value);
2499  nValue = nValue->next_sibling("Value");
2500  }
2501  auto denominatorNode = tfNode->first_node("Denominator");
2502  auto dValue = denominatorNode->first_node("Value");
2503  while(dValue) {
2504  double value = 0.0;
2505  wxString(dValue->value()).ToCDouble(&value);
2506  denominator.push_back(value);
2507  dValue = dValue->next_sibling("Value");
2508  }
2509 
2510  std::vector<Node*> nodeVector;
2511  if(!OpenControlNodeList(tfNode, nodeVector)) return false;
2512 
2513  tf->SetWidth(width);
2514  tf->SetHeight(height);
2515  tf->SetAngle(angle);
2516  tf->SetPosition(wxPoint2DDouble(posX, posY));
2517 
2518  tf->SetNumerator(numerator);
2519  tf->SetDenominator(denominator);
2520 
2521  tf->StartMove(tf->GetPosition());
2522  tf->SetNodeList(nodeVector);
2523 
2524  tf->UpdateTFText();
2525 
2526  elementList.push_back(tf);
2527 
2528  tfNode = tfNode->next_sibling("TransferFunction");
2529  }
2530  //}
2531 
2532  // Connection line
2533  auto connectionListNode = elementsNode->first_node("ConnectionList");
2534  if(!connectionListNode) return false;
2535  auto connNode = connectionListNode->first_node("Connection");
2536  while(connNode) {
2537  ConnectionLine* cLine = NULL;
2538  int id = GetAttributeValueInt(connNode, "ID");
2539 
2540  auto cadPropNode = connNode->first_node("CADProperties");
2541  if(!cadPropNode) return false;
2542  double offset = GetNodeValueDouble(cadPropNode, "Offset");
2543 
2544  auto parentList = connNode->first_node("ParentList");
2545  if(!parentList) return false;
2546 
2547  auto parentNode = parentList->first_node("Parent");
2548  bool firstNode = true;
2549  while(parentNode) {
2550  int elementID = GetNodeValueInt(parentNode, "ElementID");
2551  int nodeID = GetNodeValueInt(parentNode, "NodeID");
2552 
2553  ControlElement* element = GetControlElementFromID(elementList, elementID);
2554  Node* node = element->GetNodeList()[nodeID];
2555 
2556  if(firstNode) cLine = new ConnectionLine(node, id);
2557  cLine->AddParent(element);
2558  element->AddChild(cLine);
2559  if(!firstNode) cLine->AppendNode(node, element);
2560 
2561  if(firstNode) firstNode = false;
2562  parentNode = parentNode->next_sibling("Parent");
2563  }
2564 
2565  auto parentLine = connNode->first_node("ParentLine");
2566  if(!parentLine) return false;
2567  int parentLineID = GetAttributeValueInt(parentLine, "ID");
2568  if(parentLineID != -1) {
2569  for(auto it = connectionList.begin(), itEnd = connectionList.end(); it != itEnd; ++it) {
2570  ConnectionLine* parent = *it;
2571  if(parent->GetID() == parentLineID) {
2572  cLine->SetParentLine(parent);
2573  parent->AddChild(cLine);
2574  }
2575  }
2576  }
2577 
2578  cLine->SetOffset(offset);
2579  cLine->UpdatePoints();
2580  connectionList.push_back(cLine);
2581  connNode = connNode->next_sibling("Connection");
2582  }
2583  ctrlContainer->FillContainer(elementList, connectionList);
2584  return true;
2585 }
2586 
2587 void FileHanding::SaveControlNodes(rapidxml::xml_document<>& doc,
2588  rapidxml::xml_node<>* nodesN,
2589  std::vector<Node*> nodeList)
2590 {
2591  int id = 0;
2592  for(auto it = nodeList.begin(), itEnd = nodeList.end(); it != itEnd; ++it) {
2593  Node* node = *it;
2594  node->SetID(id);
2595  auto nodeN = AppendNode(doc, nodesN, "Node");
2596  SetNodeAttribute(doc, nodeN, "ID", id);
2597  auto nodePosition = AppendNode(doc, nodeN, "Position");
2598  auto posNodeX = AppendNode(doc, nodePosition, "X");
2599  SetNodeValue(doc, posNodeX, node->GetPosition().m_x);
2600  auto posNodeY = AppendNode(doc, nodePosition, "Y");
2601  SetNodeValue(doc, posNodeY, node->GetPosition().m_y);
2602  auto angle = AppendNode(doc, nodeN, "Angle");
2603  SetNodeValue(doc, angle, node->GetAngle());
2604  auto nodeType = AppendNode(doc, nodeN, "Type");
2605  SetNodeValue(doc, nodeType, node->GetNodeType());
2606  id++;
2607  }
2608 }
2609 
2610 ControlElement* FileHanding::GetControlElementFromID(std::vector<ControlElement*> elementList, int id)
2611 {
2612  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
2613  ControlElement* element = *it;
2614  if(element->GetID() == id) return element;
2615  }
2616  return NULL;
2617 }
2618 
2619 bool FileHanding::OpenControlNodeList(rapidxml::xml_node<>* elementNode, std::vector<Node*>& nodeVector)
2620 {
2621  auto nodeList = elementNode->first_node("NodeList");
2622  if(!nodeList) return false;
2623  auto nodeN = nodeList->first_node("Node");
2624  while(nodeN) {
2625  auto nodePosition = nodeN->first_node("Position");
2626  double nodePosX = GetNodeValueDouble(nodePosition, "X");
2627  double nodePosY = GetNodeValueDouble(nodePosition, "Y");
2628  double nodeAngle = GetNodeValueDouble(nodeN, "Angle");
2629  Node::NodeType nodeType = (Node::NodeType)GetNodeValueInt(nodeN, "Type");
2630  Node* node = new Node(wxPoint2DDouble(nodePosX, nodePosY), nodeType, 2.0);
2631  node->SetAngle(nodeAngle);
2632  nodeVector.push_back(node);
2633  nodeN = nodeN->next_sibling("Node");
2634  }
2635  return true;
2636 }
2637 
2638 rapidxml::xml_node<>* FileHanding::AppendNode(rapidxml::xml_document<>& doc,
2639  rapidxml::xml_node<>* parentNode,
2640  const char* name,
2641  rapidxml::node_type nodeType)
2642 {
2643  rapidxml::xml_node<>* node = doc.allocate_node(nodeType, name);
2644  parentNode->append_node(node);
2645  return node;
2646 }
2647 
2648 void FileHanding::SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, wxString value)
2649 {
2650  node->value(doc.allocate_string(value.mb_str()));
2651 }
2652 
2653 void FileHanding::SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, int value)
2654 {
2655  node->value(doc.allocate_string(wxString::Format("%d", value).mb_str()));
2656 }
2657 
2658 void FileHanding::SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, double value)
2659 {
2660  node->value(doc.allocate_string(wxString::FromCDouble(value, 13).mb_str()));
2661 }
2662 
2663 void FileHanding::SetNodeAttribute(rapidxml::xml_document<>& doc,
2664  rapidxml::xml_node<>* node,
2665  const char* atrName,
2666  wxString value)
2667 {
2668  node->append_attribute(doc.allocate_attribute(atrName, doc.allocate_string(value.mb_str())));
2669 }
2670 
2671 void FileHanding::SetNodeAttribute(rapidxml::xml_document<>& doc,
2672  rapidxml::xml_node<>* node,
2673  const char* atrName,
2674  int value)
2675 {
2676  node->append_attribute(
2677  doc.allocate_attribute(atrName, doc.allocate_string(wxString::Format("%d", value).mb_str())));
2678 }
2679 
2680 void FileHanding::SetNodeAttribute(rapidxml::xml_document<>& doc,
2681  rapidxml::xml_node<>* node,
2682  const char* atrName,
2683  double value)
2684 {
2685  node->append_attribute(
2686  doc.allocate_attribute(atrName, doc.allocate_string(wxString::FromCDouble(value, 13).mb_str())));
2687 }
2688 
2689 double FileHanding::GetNodeValueDouble(rapidxml::xml_node<>* parent, const char* nodeName)
2690 {
2691  double dValue = 0.0;
2692  if(parent) {
2693  auto node = parent->first_node(nodeName);
2694  if(node) wxString(node->value()).ToCDouble(&dValue);
2695  }
2696  return dValue;
2697 }
2698 
2699 int FileHanding::GetNodeValueInt(rapidxml::xml_node<>* parent, const char* nodeName)
2700 {
2701  long iValue = -1;
2702  if(parent) {
2703  auto node = parent->first_node(nodeName);
2704  if(node) wxString(node->value()).ToCLong(&iValue);
2705  }
2706  return (int)iValue;
2707 }
2708 
2709 int FileHanding::GetAttributeValueInt(rapidxml::xml_node<>* parent, const char* nodeName, const char* atrName)
2710 {
2711  long iValue = -1;
2712  if(parent) {
2713  auto node = parent->first_node(nodeName);
2714  if(node) {
2715  auto atr = node->first_attribute(atrName);
2716  if(atr) wxString(atr->value()).ToCLong(&iValue);
2717  }
2718  }
2719  return (int)iValue;
2720 }
2721 
2722 int FileHanding::GetAttributeValueInt(rapidxml::xml_node<>* node, const char* atrName)
2723 {
2724  long intValue;
2725  auto atr = node->first_attribute(atrName);
2726  if(!atr) return false;
2727  wxString(atr->value()).ToCLong(&intValue);
2728  return (int)intValue;
2729 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
-
Definition: Text.h:65
+
Element that shows power element informations in workspace.
Definition: Text.h:72
Multiplies two inputs.
Definition: Multiplier.h:32
std::vector< double > swTime
Definition: PowerElement.h:95
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Machines.cpp:146
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Branch.cpp:105
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
const std::vector< Transformer * > GetTransformerList() const
Get the transformers of the system (use GetElementsFromList first).
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Text.cpp:162
-
Definition: Sum.h:26
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
void SetWidth(double width)
Set element width.
Definition: Element.h:151
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
FaultData
Information about fault (type and location).
Definition: PowerElement.h:55
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Capacitor.cpp:115
Node of a control element. This class manages the user interaction with the connection and control el...
@@ -114,7 +114,7 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
Limits the input value by superior and inferior values.
Definition: Limiter.h:32
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Inductor.cpp:113
- +
Synchronous generator power element.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Machines.cpp:111
const std::vector< Bus * > GetBusList() const
Get the buses of the system (use GetElementsFromList first).
@@ -127,12 +127,12 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
virtual void Move(wxPoint2DDouble position)
Move the element other position.
const std::vector< Inductor * > GetInductorList() const
Get the inductors of the system (use GetElementsFromList first).
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Element.h:240
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Inductor.cpp:24
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
- +
Switching data of power elements.
Definition: PowerElement.h:93
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Shunt.cpp:32
-
Generates an output following an exponential function. .
Definition: Exponential.h:33
+
Generates an output following an exponential function.
Definition: Exponential.h:32
void SetAngle(double angle)
Set element angle.
Definition: Element.h:156
double GetWidth() const
Get the element width.
Definition: Element.h:207
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Line.cpp:136
@@ -140,9 +140,9 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
const std::vector< Capacitor * > GetCapacitorList() const
Get the capacitors of the system (use GetElementsFromList first).
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Machines.cpp:25
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
-
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
double GetHeight() const
Get the element height.
Definition: Element.h:197
virtual std::vector< wxPoint2DDouble > GetPointList() const
Get the list of points that connect the element to bus.
Definition: Element.h:232
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
@@ -150,7 +150,7 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
const std::vector< Load * > GetLoadList() const
Get the loads of the system (use GetElementsFromList first).
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Machines.cpp:232
virtual void SetPointList(std::vector< wxPoint2DDouble > pointList)
Set the list of points that connect the element to the bus.
Definition: Line.cpp:492
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Bus.cpp:184
@@ -158,21 +158,21 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
Connection between two control elements or other connection line and an element.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Shunt.cpp:67
SwitchingType
Type of switching.
Definition: PowerElement.h:69
- - +
Calculates the time response by a frequency domain transfer function.
+
Induction motor power element.
Definition: IndMotor.h:40
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Transformer.cpp:39
const std::vector< SyncMotor * > GetSyncMotorList() const
Get the synchronous motors of the system (use GetElementsFromList first).
virtual int GetID() const
Get the element ID.
Definition: Element.h:272
- +
Shunt capactior power element.
Definition: Capacitor.h:38
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Load.cpp:23
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Machines.cpp:165
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
- +
Inductor shunt power element.
Definition: Inductor.h:38
virtual void GetElementsFromList(std::vector< Element *> elementList)
Separate the power elements from a generic list.
- +
Base class of electric calculations, with general methods.
A control element that provides a constant value.
Definition: Constant.h:35
This class manages the graphical and power elements. It is responsible for handling the user&#39;s intera...
Definition: Workspace.h:81
@@ -180,7 +180,7 @@ $(document).ready(function(){initNavTree('_file_handing_8cpp_source.html','');})
double GetRotationAngle() const
Get the angle of rotation.
Definition: Element.h:217
const std::vector< Line * > GetLineList() const
Get the lines of the system (use GetElementsFromList first).
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Capacitor.cpp:24
- +
Two-winding transformer power element.
Definition: Transformer.h:78
void SetHeight(double height)
Set element height.
Definition: Element.h:135
diff --git a/docs/doxygen/html/_file_handing_8h.html b/docs/doxygen/html/_file_handing_8h.html index 12d632c..8b51868 100644 --- a/docs/doxygen/html/_file_handing_8h.html +++ b/docs/doxygen/html/_file_handing_8h.html @@ -97,7 +97,7 @@ $(document).ready(function(){initNavTree('_file_handing_8h.html','');}); #include "ControlEditor.h"
#include "ControlElementContainer.h"
#include "ElectricCalculation.h"
-#include "Text.h"
+#include "Text.h"
#include "rapidXML/rapidxml.hpp"
#include "rapidXML/rapidxml_print.hpp"
#include "rapidXML/rapidxml_utils.hpp"
diff --git a/docs/doxygen/html/_file_handing_8h_source.html b/docs/doxygen/html/_file_handing_8h_source.html index 4f8f3ab..08ec41e 100644 --- a/docs/doxygen/html/_file_handing_8h_source.html +++ b/docs/doxygen/html/_file_handing_8h_source.html @@ -88,11 +88,12 @@ $(document).ready(function(){initNavTree('_file_handing_8h_source.html','');});
FileHanding.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef FILEHANDING_H
19 #define FILEHANDING_H
20 
21 #include <wx/string.h>
22 #include <fstream>
23 #include <sstream>
24 
25 #include "Workspace.h"
26 #include "ControlEditor.h"
28 #include "ElectricCalculation.h"
29 #include "Text.h"
30 
31 #include "rapidXML/rapidxml.hpp"
32 // Modified: http://stackoverflow.com/questions/14113923/rapidxml-print-header-has-undefined-methods
33 #include "rapidXML/rapidxml_print.hpp"
34 #include "rapidXML/rapidxml_utils.hpp"
35 
44 {
45 public:
46  FileHanding();
47  FileHanding(Workspace* workspace);
48  FileHanding(ControlEditor* controlEditor);
49  ~FileHanding();
50 
51  void SetWorkspace(Workspace* workspace) { m_workspace = workspace; }
52  void SetControlEditor(ControlEditor* controlEditor) { m_controlEditor = controlEditor; }
53 
54  void SaveProject(wxFileName path);
55  bool OpenProject(wxFileName path);
56 
57  void SaveControl(wxFileName path);
58  bool OpenControl(wxFileName path, std::vector<ControlElement*>& ctrlElementList, std::vector<ConnectionLine*>& ctrlConnectionList);
59 
60  void SaveControlElements(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementsNode, ControlElementContainer* ctrlContainer = NULL);
61  bool OpenControlElements(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementsNode, ControlElementContainer* ctrlContainer = NULL);
62 
63 protected:
64  Workspace* m_workspace = NULL;
65  ControlEditor* m_controlEditor = NULL;
66 
67  rapidxml::xml_node<>* AppendNode(rapidxml::xml_document<>& doc,
68  rapidxml::xml_node<>* parentNode,
69  const char* name,
70  rapidxml::node_type nodeType = rapidxml::node_element);
71  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, wxString value);
72  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, int value);
73  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, double value);
74  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, wxString value);
75  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, int value);
76  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, double value);
77  double GetNodeValueDouble(rapidxml::xml_node<>* parent, const char* nodeName);
78  int GetNodeValueInt(rapidxml::xml_node<>* parent, const char* nodeName);
79  int GetAttributeValueInt(rapidxml::xml_node<>* parent, const char* nodeName, const char* atrName);
80  int GetAttributeValueInt(rapidxml::xml_node<>* node, const char* atrName);
81 
82  void SaveControlNodes(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* nodesN, std::vector<Node*> nodeList);
83  ControlElement* GetControlElementFromID(std::vector<ControlElement*> elementList, int id);
84  bool OpenControlNodeList(rapidxml::xml_node<>* elementNode, std::vector<Node*>& nodeVector);
85 };
86 
87 #endif // FILEHANDING_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef FILEHANDING_H
19 #define FILEHANDING_H
20 
21 #include <wx/string.h>
22 #include <fstream>
23 #include <sstream>
24 
25 #include "Workspace.h"
26 #include "ControlEditor.h"
28 #include "ElectricCalculation.h"
29 #include "Text.h"
30 
31 #include "rapidXML/rapidxml.hpp"
32 // Modified: http://stackoverflow.com/questions/14113923/rapidxml-print-header-has-undefined-methods
33 #include "rapidXML/rapidxml_print.hpp"
34 #include "rapidXML/rapidxml_utils.hpp"
35 
44 {
45 public:
46  FileHanding();
47  FileHanding(Workspace* workspace);
48  FileHanding(ControlEditor* controlEditor);
49  ~FileHanding();
50 
51  void SetWorkspace(Workspace* workspace) { m_workspace = workspace; }
52  void SetControlEditor(ControlEditor* controlEditor) { m_controlEditor = controlEditor; }
53 
54  void SaveProject(wxFileName path);
55  bool OpenProject(wxFileName path);
56 
57  void SaveControl(wxFileName path);
58  bool OpenControl(wxFileName path, std::vector<ControlElement*>& ctrlElementList, std::vector<ConnectionLine*>& ctrlConnectionList);
59 
60  void SaveControlElements(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementsNode, ControlElementContainer* ctrlContainer = NULL);
61  bool OpenControlElements(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementsNode, ControlElementContainer* ctrlContainer = NULL);
62 
63 protected:
64  Workspace* m_workspace = NULL;
65  ControlEditor* m_controlEditor = NULL;
66 
67  rapidxml::xml_node<>* AppendNode(rapidxml::xml_document<>& doc,
68  rapidxml::xml_node<>* parentNode,
69  const char* name,
70  rapidxml::node_type nodeType = rapidxml::node_element);
71  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, wxString value);
72  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, int value);
73  void SetNodeValue(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, double value);
74  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, wxString value);
75  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, int value);
76  void SetNodeAttribute(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* node, const char* atrName, double value);
77  double GetNodeValueDouble(rapidxml::xml_node<>* parent, const char* nodeName);
78  int GetNodeValueInt(rapidxml::xml_node<>* parent, const char* nodeName);
79  int GetAttributeValueInt(rapidxml::xml_node<>* parent, const char* nodeName, const char* atrName);
80  int GetAttributeValueInt(rapidxml::xml_node<>* node, const char* atrName);
81 
82  void SaveControlNodes(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* nodesN, std::vector<Node*> nodeList);
83  ControlElement* GetControlElementFromID(std::vector<ControlElement*> elementList, int id);
84  bool OpenControlNodeList(rapidxml::xml_node<>* elementNode, std::vector<Node*>& nodeVector);
85 };
86 
87 #endif // FILEHANDING_H
Save and opens the projects created on disk.
Definition: FileHanding.h:43
-
Base class of electric calculations, with general methods.
+
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
+ diff --git a/docs/doxygen/html/_gain_8cpp_source.html b/docs/doxygen/html/_gain_8cpp_source.html index 853f21f..e1bc08a 100644 --- a/docs/doxygen/html/_gain_8cpp_source.html +++ b/docs/doxygen/html/_gain_8cpp_source.html @@ -88,16 +88,17 @@ $(document).ready(function(){initNavTree('_gain_8cpp_source.html','');});
Gain.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Gain.h"
19 #include "GainForm.h"
20 
21 Gain::Gain(int id) : ControlElement(id)
22 {
23  m_triPts.resize(3);
24  SetValue(m_value);
25  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize);
26  nodeIn->StartMove(m_position);
27  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
28  nodeOut->SetAngle(180.0);
29  nodeOut->StartMove(m_position);
30  m_nodeList.push_back(nodeIn);
31  m_nodeList.push_back(nodeOut);
32 }
33 
34 Gain::~Gain() {}
35 void Gain::Draw(wxPoint2DDouble translation, double scale) const
36 {
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  std::vector<wxPoint2DDouble> m_triSelectedPts;
41  if(m_angle == 0.0) {
42  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize / 2, borderSize / 1.5));
43  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(borderSize / 2, -borderSize / 1.5));
44  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(-borderSize, 0));
45  } else if(m_angle == 90.0) {
46  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize / 1.5, borderSize / 2));
47  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 1.5, borderSize / 2));
48  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(0, -borderSize));
49  } else if(m_angle == 180.0) {
50  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize, 0));
51  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 2, borderSize / 1.5));
52  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(-borderSize / 2, -borderSize / 1.5));
53  } else if(m_angle == 270.0) {
54  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(0, borderSize));
55  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 1.5, -borderSize / 2));
56  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(borderSize / 1.5, -borderSize / 2));
57  }
58  DrawTriangle(m_triSelectedPts);
59  }
60  glLineWidth(1.0);
61  glColor4d(1.0, 1.0, 1.0, 1.0);
62  DrawTriangle(m_triPts);
63  glColor4d(0.0, 0.0, 0.0, 1.0);
64  DrawTriangle(m_triPts, GL_LINE_LOOP);
65 
66  // Plot number.
67  glEnable(GL_TEXTURE_2D);
68  glColor4d(0.0, 0.0, 0.0, 1.0);
69  m_glStringValue->bind();
70  if(m_angle == 0.0)
71  m_glStringValue->render(m_position.m_x - m_width / 2 + m_glStringValue->getWidth() / 2 + 2 + m_borderSize,
72  m_position.m_y);
73  else if(m_angle == 90.0)
74  m_glStringValue->render(m_position.m_x,
75  m_position.m_y - m_height / 2 + m_glStringValue->getheight() / 2 + 2 + m_borderSize);
76  else if(m_angle == 180.0)
77  m_glStringValue->render(m_position.m_x + m_width / 2 - m_glStringValue->getWidth() / 2 - 2 - m_borderSize,
78  m_position.m_y);
79  else if(m_angle == 270.0)
80  m_glStringValue->render(m_position.m_x,
81  m_position.m_y + m_height / 2 - m_glStringValue->getheight() / 2 - 2 - m_borderSize);
82  glDisable(GL_TEXTURE_2D);
83 
84  glColor4d(0.0, 0.0, 0.0, 1.0);
85  DrawNodes();
86 }
87 
88 bool Gain::ShowForm(wxWindow* parent, Element* element)
89 {
90  GainForm* form = new GainForm(parent, this);
91  if(form->ShowModal() == wxID_OK) {
92  form->Destroy();
93  return true;
94  }
95  form->Destroy();
96  return false;
97 }
98 
99 void Gain::Rotate(bool clockwise)
100 {
101  if(clockwise)
102  m_angle += 90.0;
103  else
104  m_angle -= 90.0;
105  if(m_angle >= 360.0)
106  m_angle = 0.0;
107  else if(m_angle < 0)
108  m_angle = 270.0;
109 
110  UpdatePoints();
111 
112  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
113  Node* node = *it;
114  node->Rotate(clockwise);
115  }
116 }
117 
118 void Gain::SetValue(double value)
119 {
120  m_value = value;
121  wxString text = "";
122  if(std::abs(m_value) > 1e3 || std::abs(m_value) < 1e-3)
123  text = wxString::Format("%g", m_value);
124  else
125  text = StringFromDouble(m_value);
126 
127  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
128  wxScreenDC dc;
129 
130  if(m_glStringValue) {
131  delete m_glStringValue;
132  m_glStringValue = NULL;
133  }
134  m_glStringValue = new wxGLString(text);
135  m_glStringValue->setFont(font);
136  m_glStringValue->consolidate(&dc);
137 
138  m_width = m_glStringValue->getWidth() + 18 + 2 * m_borderSize;
139  m_height = m_glStringValue->getheight() + 18 + 2 * m_borderSize;
140 
141  if(m_width > m_height)
142  m_height = m_width;
143  else
144  m_width = m_height;
145 
146  SetPosition(m_position); // Update rectangle.
147 
148  UpdatePoints();
149 }
150 
151 void Gain::UpdatePoints()
152 {
153  if(m_nodeList.size() != 0) {
154  if(m_angle == 0.0) {
155  m_triPts[0] = m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize);
156  m_triPts[1] = m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize);
157  m_triPts[2] = m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0);
158  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
159  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
160  } else if(m_angle == 90.0) {
161  m_triPts[0] = m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize);
162  m_triPts[1] = m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize);
163  m_triPts[2] = m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize);
164  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
165  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
166  } else if(m_angle == 180.0) {
167  m_triPts[0] = m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0);
168  m_triPts[1] = m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize);
169  m_triPts[2] = m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize);
170  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
171  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2 + 2, 0));
172  } else if(m_angle == 270.0) {
173  m_triPts[0] = m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize);
174  m_triPts[1] = m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize);
175  m_triPts[2] = m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize);
176  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
177  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2 + 2));
178  }
179  }
180 }
181 
182 void Gain::Move(wxPoint2DDouble position)
183 {
184  SetPosition(m_movePos + position - m_moveStartPt);
185  UpdatePoints();
186 }
187 
188 bool Gain::Solve(double input, double timeStep)
189 {
190  m_output = input * m_value;
191  return true;
192 }
193 
195 {
196  Gain* copy = new Gain(m_elementID);
197  *copy = *this;
198  m_glStringValue = NULL;
199  SetValue(m_value);
200  return copy;
201 }
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Gain.cpp:182
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Gain.h"
19 #include "GainForm.h"
20 
21 Gain::Gain(int id) : ControlElement(id)
22 {
23  m_triPts.resize(3);
24  SetValue(m_value);
25  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize);
26  nodeIn->StartMove(m_position);
27  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
28  nodeOut->SetAngle(180.0);
29  nodeOut->StartMove(m_position);
30  m_nodeList.push_back(nodeIn);
31  m_nodeList.push_back(nodeOut);
32 }
33 
34 Gain::~Gain() {}
35 void Gain::Draw(wxPoint2DDouble translation, double scale) const
36 {
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  std::vector<wxPoint2DDouble> m_triSelectedPts;
41  if(m_angle == 0.0) {
42  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize / 2, borderSize / 1.5));
43  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(borderSize / 2, -borderSize / 1.5));
44  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(-borderSize, 0));
45  } else if(m_angle == 90.0) {
46  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize / 1.5, borderSize / 2));
47  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 1.5, borderSize / 2));
48  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(0, -borderSize));
49  } else if(m_angle == 180.0) {
50  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(borderSize, 0));
51  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 2, borderSize / 1.5));
52  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(-borderSize / 2, -borderSize / 1.5));
53  } else if(m_angle == 270.0) {
54  m_triSelectedPts.push_back(m_triPts[0] - wxPoint2DDouble(0, borderSize));
55  m_triSelectedPts.push_back(m_triPts[1] - wxPoint2DDouble(-borderSize / 1.5, -borderSize / 2));
56  m_triSelectedPts.push_back(m_triPts[2] - wxPoint2DDouble(borderSize / 1.5, -borderSize / 2));
57  }
58  DrawTriangle(m_triSelectedPts);
59  }
60  glLineWidth(1.0);
61  glColor4d(1.0, 1.0, 1.0, 1.0);
62  DrawTriangle(m_triPts);
63  glColor4d(0.0, 0.0, 0.0, 1.0);
64  DrawTriangle(m_triPts, GL_LINE_LOOP);
65 
66  // Plot number.
67  glEnable(GL_TEXTURE_2D);
68  glColor4d(0.0, 0.0, 0.0, 1.0);
69  m_glStringValue->bind();
70  if(m_angle == 0.0)
71  m_glStringValue->render(m_position.m_x - m_width / 2 + m_glStringValue->getWidth() / 2 + 2 + m_borderSize,
72  m_position.m_y);
73  else if(m_angle == 90.0)
74  m_glStringValue->render(m_position.m_x,
75  m_position.m_y - m_height / 2 + m_glStringValue->getheight() / 2 + 2 + m_borderSize);
76  else if(m_angle == 180.0)
77  m_glStringValue->render(m_position.m_x + m_width / 2 - m_glStringValue->getWidth() / 2 - 2 - m_borderSize,
78  m_position.m_y);
79  else if(m_angle == 270.0)
80  m_glStringValue->render(m_position.m_x,
81  m_position.m_y + m_height / 2 - m_glStringValue->getheight() / 2 - 2 - m_borderSize);
82  glDisable(GL_TEXTURE_2D);
83 
84  glColor4d(0.0, 0.0, 0.0, 1.0);
85  DrawNodes();
86 }
87 
88 bool Gain::ShowForm(wxWindow* parent, Element* element)
89 {
90  GainForm* form = new GainForm(parent, this);
91  if(form->ShowModal() == wxID_OK) {
92  form->Destroy();
93  return true;
94  }
95  form->Destroy();
96  return false;
97 }
98 
99 void Gain::Rotate(bool clockwise)
100 {
101  if(clockwise)
102  m_angle += 90.0;
103  else
104  m_angle -= 90.0;
105  if(m_angle >= 360.0)
106  m_angle = 0.0;
107  else if(m_angle < 0)
108  m_angle = 270.0;
109 
110  UpdatePoints();
111 
112  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
113  Node* node = *it;
114  node->Rotate(clockwise);
115  }
116 }
117 
118 void Gain::SetValue(double value)
119 {
120  m_value = value;
121  wxString text = "";
122  if(std::abs(m_value) > 1e3 || std::abs(m_value) < 1e-3)
123  text = wxString::Format("%g", m_value);
124  else
125  text = StringFromDouble(m_value);
126 
127  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
128  wxScreenDC dc;
129 
130  if(m_glStringValue) {
131  delete m_glStringValue;
132  m_glStringValue = NULL;
133  }
134  m_glStringValue = new wxGLString(text);
135  m_glStringValue->setFont(font);
136  m_glStringValue->consolidate(&dc);
137 
138  m_width = m_glStringValue->getWidth() + 18 + 2 * m_borderSize;
139  m_height = m_glStringValue->getheight() + 18 + 2 * m_borderSize;
140 
141  if(m_width > m_height)
142  m_height = m_width;
143  else
144  m_width = m_height;
145 
146  SetPosition(m_position); // Update rectangle.
147 
148  UpdatePoints();
149 }
150 
151 void Gain::UpdatePoints()
152 {
153  if(m_nodeList.size() != 0) {
154  if(m_angle == 0.0) {
155  m_triPts[0] = m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize);
156  m_triPts[1] = m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize);
157  m_triPts[2] = m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0);
158  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
159  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
160  } else if(m_angle == 90.0) {
161  m_triPts[0] = m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize);
162  m_triPts[1] = m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize);
163  m_triPts[2] = m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize);
164  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
165  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
166  } else if(m_angle == 180.0) {
167  m_triPts[0] = m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0);
168  m_triPts[1] = m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize);
169  m_triPts[2] = m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize);
170  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
171  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2 + 2, 0));
172  } else if(m_angle == 270.0) {
173  m_triPts[0] = m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize);
174  m_triPts[1] = m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize);
175  m_triPts[2] = m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize);
176  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
177  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2 + 2));
178  }
179  }
180 }
181 
182 void Gain::Move(wxPoint2DDouble position)
183 {
184  SetPosition(m_movePos + position - m_moveStartPt);
185  UpdatePoints();
186 }
187 
188 bool Gain::Solve(double input, double timeStep)
189 {
190  m_output = input * m_value;
191  return true;
192 }
193 
195 {
196  Gain* copy = new Gain(m_elementID);
197  *copy = *this;
198  m_glStringValue = NULL;
199  SetValue(m_value);
200  return copy;
201 }
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Gain.cpp:182
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
Node of a control element. This class manages the user interaction with the connection and control el...
virtual Element * GetCopy()
Get a the element copy.
Definition: Gain.cpp:194
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Gain.cpp:88
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Gain.cpp:99
Form to edit the gain control data.
Definition: GainForm.h:31
+
virtual bool Solve(double input, double timeStep)
Multiply the input by a constant.
Definition: Gain.cpp:188
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Gain.cpp:35
diff --git a/docs/doxygen/html/_gain_8h.html b/docs/doxygen/html/_gain_8h.html index 0f255cc..f732cac 100644 --- a/docs/doxygen/html/_gain_8h.html +++ b/docs/doxygen/html/_gain_8h.html @@ -99,7 +99,7 @@ $(document).ready(function(){initNavTree('_gain_8h.html','');});

Classes

class  Gain - Provide an output multiplying the input by a constant. \( output = K \cdot input \). More...
+ Provide an output multiplying the input by a constant. More...
 
diff --git a/docs/doxygen/html/_gain_8h_source.html b/docs/doxygen/html/_gain_8h_source.html index 41069c4..99cf636 100644 --- a/docs/doxygen/html/_gain_8h_source.html +++ b/docs/doxygen/html/_gain_8h_source.html @@ -88,16 +88,17 @@ $(document).ready(function(){initNavTree('_gain_8h_source.html','');});
Gain.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GAIN_H
19 #define GAIN_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class GainForm;
27 
36 class Gain : public ControlElement
37 {
38  public:
39  Gain(int id);
40  ~Gain();
41 
42  virtual void Draw(wxPoint2DDouble translation, double scale) const;
43  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
44  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
45  virtual bool ShowForm(wxWindow* parent, Element* element);
46  virtual void Rotate(bool clockwise = true);
47  virtual void Move(wxPoint2DDouble position);
48  virtual void UpdateText() { SetValue(m_value); }
49  virtual void SetValue(double value);
50  virtual double GetValue() const { return m_value; }
51  virtual void UpdatePoints();
52 
53  virtual bool Solve(double input, double timeStep);
54 
55  virtual Element* GetCopy();
56 
57  protected:
58  double m_value = 1.0;
59 
60  wxGLString* m_glStringValue = NULL;
61  int m_fontSize = 10;
62 
63  std::vector<wxPoint2DDouble> m_triPts;
64 };
65 
66 #endif // GAIN_H
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Gain.cpp:182
- -
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GAIN_H
19 #define GAIN_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class GainForm;
27 
35 class Gain : public ControlElement
36 {
37  public:
38  Gain(int id);
39  ~Gain();
40 
41  virtual void Draw(wxPoint2DDouble translation, double scale) const;
42  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
43  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
44  virtual bool ShowForm(wxWindow* parent, Element* element);
45  virtual void Rotate(bool clockwise = true);
46  virtual void Move(wxPoint2DDouble position);
47  virtual void UpdateText() { SetValue(m_value); }
48  virtual void SetValue(double value);
49  virtual double GetValue() const { return m_value; }
50  virtual void UpdatePoints();
59  virtual bool Solve(double input, double timeStep);
60 
61  virtual Element* GetCopy();
62 
63  protected:
64  double m_value = 1.0;
65 
66  wxGLString* m_glStringValue = NULL;
67  int m_fontSize = 10;
68 
69  std::vector<wxPoint2DDouble> m_triPts;
70 };
71 
72 #endif // GAIN_H
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Gain.cpp:182
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
virtual Element * GetCopy()
Get a the element copy.
Definition: Gain.cpp:194
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Gain.h:44
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Gain.h:43
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Gain.cpp:88
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Gain.cpp:99
Form to edit the gain control data.
Definition: GainForm.h:31
Base class of a control element. Provide general methods to other control classes.
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Gain.h:43
+
virtual bool Solve(double input, double timeStep)
Multiply the input by a constant.
Definition: Gain.cpp:188
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Gain.h:42
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Gain.cpp:35
diff --git a/docs/doxygen/html/_gain_form_8cpp_source.html b/docs/doxygen/html/_gain_form_8cpp_source.html index 92381b2..aa3d409 100644 --- a/docs/doxygen/html/_gain_form_8cpp_source.html +++ b/docs/doxygen/html/_gain_form_8cpp_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_gain_form_8cpp_source.html','');});
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GainForm.h"
19 #include "Gain.h"
20 
21 GainForm::GainForm(wxWindow* parent, Gain* gain) : GainFormBase(parent)
22 {
23  SetSize(GetBestSize());
24 
25  m_parent = parent;
26  m_gain = gain;
27 
28  m_textCtrlValue->SetValue(m_gain->StringFromDouble(m_gain->GetValue()));
29 }
30 
31 GainForm::~GainForm() {}
32 void GainForm::OnOKButtonClick(wxCommandEvent& event)
33 {
34  if(ValidateData()) EndModal(wxID_OK);
35 }
36 
37 bool GainForm::ValidateData()
38 {
39  double value;
40  if(!m_gain->DoubleFromString(this, m_textCtrlValue->GetValue(), value,
41  _("Value entered incorrectly in the field \"Gain value\".")))
42  return false;
43 
44  m_gain->SetValue(value);
45  return true;
46 }
-
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
diff --git a/docs/doxygen/html/_gain_form_8h_source.html b/docs/doxygen/html/_gain_form_8h_source.html index e0eb282..a6399b8 100644 --- a/docs/doxygen/html/_gain_form_8h_source.html +++ b/docs/doxygen/html/_gain_form_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_gain_form_8h_source.html','');});
GainForm.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GAINFORM_H
19 #define GAINFORM_H
20 #include "ElementForm.h"
21 
22 class Gain;
23 
31 class GainForm : public GainFormBase
32 {
33  public:
34  GainForm(wxWindow* parent, Gain* gain);
35  virtual ~GainForm();
36 
37  virtual bool ValidateData();
38 
39  protected:
40  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
41  virtual void OnOKButtonClick(wxCommandEvent& event);
42 
43  wxWindow* m_parent;
44  Gain* m_gain;
45 };
46 #endif // GAINFORM_H
Provide an output multiplying the input by a constant. .
Definition: Gain.h:36
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GAINFORM_H
19 #define GAINFORM_H
20 #include "ElementForm.h"
21 
22 class Gain;
23 
31 class GainForm : public GainFormBase
32 {
33  public:
34  GainForm(wxWindow* parent, Gain* gain);
35  virtual ~GainForm();
36 
37  virtual bool ValidateData();
38 
39  protected:
40  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
41  virtual void OnOKButtonClick(wxCommandEvent& event);
42 
43  wxWindow* m_parent;
44  Gain* m_gain;
45 };
46 #endif // GAINFORM_H
Provide an output multiplying the input by a constant.
Definition: Gain.h:35
Form to edit the gain control data.
Definition: GainForm.h:31
diff --git a/docs/doxygen/html/_general_properties_form_8cpp_source.html b/docs/doxygen/html/_general_properties_form_8cpp_source.html index 0eacf1c..614eac2 100644 --- a/docs/doxygen/html/_general_properties_form_8cpp_source.html +++ b/docs/doxygen/html/_general_properties_form_8cpp_source.html @@ -88,7 +88,8 @@ $(document).ready(function(){initNavTree('_general_properties_form_8cpp_source.h
GeneralPropertiesForm.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneralPropertiesForm.h"
19 #include "PropertiesData.h"
20 
21 GeneralPropertiesForm::GeneralPropertiesForm(wxWindow* parent, PropertiesData* properties)
23 {
24  m_properties = properties;
25  auto data = m_properties->GetGeneralPropertiesData();
26 
27  // Clear the choices and rebuild to set the correct translations.
28  m_choiceLanguage->Clear();
29  m_choiceLanguage->Insert(_("English"), 0);
30  m_choiceLanguage->Insert(_("Portuguese"), 1);
31  m_choiceTheme->Clear();
32  m_choiceTheme->Insert(_("Light"), 0);
33  m_choiceTheme->Insert(_("Dark"), 1);
34 
35  switch(data.language) {
36  case wxLANGUAGE_ENGLISH: {
37  m_choiceLanguage->SetSelection(0);
38  } break;
39  case wxLANGUAGE_PORTUGUESE_BRAZILIAN: {
40  m_choiceLanguage->SetSelection(1);
41  } break;
42  default: {
43  m_choiceLanguage->SetSelection(wxNOT_FOUND);
44  } break;
45  }
46  switch(data.theme) {
47  case THEME_LIGHT: {
48  m_choiceTheme->SetSelection(0);
49  } break;
50  case THEME_DARK: {
51  m_choiceTheme->SetSelection(1);
52  } break;
53  }
54 }
55 
56 GeneralPropertiesForm::~GeneralPropertiesForm() {}
57 void GeneralPropertiesForm::OnButtonOKClick(wxCommandEvent& event)
58 {
59  if(ValidateData()) EndModal(wxID_OK);
60 }
61 
62 bool GeneralPropertiesForm::ValidateData()
63 {
64  auto data = m_properties->GetGeneralPropertiesData();
65  auto checkData = m_properties->GetGeneralPropertiesData();
66  bool hasChanges = false;
67 
68  wxTextFile file("config.ini");
69  if(!file.Create()) {
70  if(!file.Open()) {
71  // Fail to access the file.
72  wxMessageDialog msgDialog(this,
73  _("It was not possible to access the init file.\nThe settings won't be applied."),
74  _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
75  msgDialog.ShowModal();
76  }
77  file.Clear();
78  }
79 
80  wxString line = "lang=";
81  switch(m_choiceLanguage->GetSelection()) {
82  case 0: {
83  line += "en";
84  data.language = wxLANGUAGE_ENGLISH;
85  } break;
86  case 1: {
87  line += "pt-br";
88  data.language = wxLANGUAGE_PORTUGUESE_BRAZILIAN;
89  } break;
90  }
91  file.AddLine(line);
92  if(data.language != checkData.language) hasChanges = true;
93 
94  line = "theme=";
95  switch(m_choiceTheme->GetSelection()) {
96  case 0: {
97  line += "light";
98  data.theme = THEME_LIGHT;
99  } break;
100  case 1: {
101  line += "dark";
102  data.theme = THEME_DARK;
103  } break;
104  }
105  file.AddLine(line);
106  if(data.theme != checkData.theme) hasChanges = true;
107 
108  file.Write();
109  file.Close();
110 
111  if(hasChanges) {
112  wxMessageDialog msgDialog(this, _("The application must be restarted to settings changes be applied."),
113  _("Info"), wxOK | wxCENTRE | wxICON_INFORMATION);
114  msgDialog.ShowModal();
115  }
116  m_properties->SetGeneralPropertiesData(data);
117  return true;
118 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneralPropertiesForm.h"
19 #include "PropertiesData.h"
20 
21 GeneralPropertiesForm::GeneralPropertiesForm(wxWindow* parent, PropertiesData* properties)
23 {
24  m_properties = properties;
25  auto data = m_properties->GetGeneralPropertiesData();
26 
27  // Clear the choices and rebuild to set the correct translations.
28  m_choiceLanguage->Clear();
29  m_choiceLanguage->Insert(_("English"), 0);
30  m_choiceLanguage->Insert(_("Portuguese"), 1);
31  m_choiceTheme->Clear();
32  m_choiceTheme->Insert(_("Light"), 0);
33  m_choiceTheme->Insert(_("Dark"), 1);
34 
35  switch(data.language) {
36  case wxLANGUAGE_ENGLISH: {
37  m_choiceLanguage->SetSelection(0);
38  } break;
39  case wxLANGUAGE_PORTUGUESE_BRAZILIAN: {
40  m_choiceLanguage->SetSelection(1);
41  } break;
42  default: {
43  m_choiceLanguage->SetSelection(wxNOT_FOUND);
44  } break;
45  }
46  switch(data.theme) {
47  case THEME_LIGHT: {
48  m_choiceTheme->SetSelection(0);
49  } break;
50  case THEME_DARK: {
51  m_choiceTheme->SetSelection(1);
52  } break;
53  }
54 }
55 
56 GeneralPropertiesForm::~GeneralPropertiesForm() {}
57 void GeneralPropertiesForm::OnButtonOKClick(wxCommandEvent& event)
58 {
59  if(ValidateData()) EndModal(wxID_OK);
60 }
61 
62 bool GeneralPropertiesForm::ValidateData()
63 {
64  auto data = m_properties->GetGeneralPropertiesData();
65  auto checkData = m_properties->GetGeneralPropertiesData();
66  bool hasChanges = false;
67 
68  wxTextFile file("config.ini");
69  if(!file.Create()) {
70  if(!file.Open()) {
71  // Fail to access the file.
72  wxMessageDialog msgDialog(this,
73  _("It was not possible to access the init file.\nThe settings won't be applied."),
74  _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
75  msgDialog.ShowModal();
76  }
77  file.Clear();
78  }
79 
80  wxString line = "lang=";
81  switch(m_choiceLanguage->GetSelection()) {
82  case 0: {
83  line += "en";
84  data.language = wxLANGUAGE_ENGLISH;
85  } break;
86  case 1: {
87  line += "pt-br";
88  data.language = wxLANGUAGE_PORTUGUESE_BRAZILIAN;
89  } break;
90  }
91  file.AddLine(line);
92  if(data.language != checkData.language) hasChanges = true;
93 
94  line = "theme=";
95  switch(m_choiceTheme->GetSelection()) {
96  case 0: {
97  line += "light";
98  data.theme = THEME_LIGHT;
99  } break;
100  case 1: {
101  line += "dark";
102  data.theme = THEME_DARK;
103  } break;
104  }
105  file.AddLine(line);
106  if(data.theme != checkData.theme) hasChanges = true;
107 
108  file.Write();
109  file.Close();
110 
111  if(hasChanges) {
112  wxMessageDialog msgDialog(this, _("The application must be restarted to settings changes be applied."),
113  _("Info"), wxOK | wxCENTRE | wxICON_INFORMATION);
114  msgDialog.ShowModal();
115  }
116  m_properties->SetGeneralPropertiesData(data);
117  return true;
118 }
General and simulation data manager.
+
diff --git a/docs/doxygen/html/_general_properties_form_8h_source.html b/docs/doxygen/html/_general_properties_form_8h_source.html index 63f2c24..fa7496f 100644 --- a/docs/doxygen/html/_general_properties_form_8h_source.html +++ b/docs/doxygen/html/_general_properties_form_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_general_properties_form_8h_source.htm
GeneralPropertiesForm.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GENERALPROPERTIESFORM_H
19 #define GENERALPROPERTIESFORM_H
20 
21 #include "PropertiesForm.h"
22 
23 #include <wx/textfile.h>
24 #include <wx/msgdlg.h>
25 
26 class PropertiesData;
27 
36 {
37  public:
38  GeneralPropertiesForm(wxWindow* parent, PropertiesData* properties);
39  virtual ~GeneralPropertiesForm();
40 
41  protected:
42  virtual void OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
43  virtual void OnButtonOKClick(wxCommandEvent& event);
44  virtual bool ValidateData();
45 
46  PropertiesData* m_properties = NULL;
47 };
48 #endif // GENERALPROPERTIESFORM_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GENERALPROPERTIESFORM_H
19 #define GENERALPROPERTIESFORM_H
20 
21 #include "PropertiesForm.h"
22 
23 #include <wx/textfile.h>
24 #include <wx/msgdlg.h>
25 
26 class PropertiesData;
27 
36 {
37  public:
38  GeneralPropertiesForm(wxWindow* parent, PropertiesData* properties);
39  virtual ~GeneralPropertiesForm();
40 
41  protected:
42  virtual void OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
43  virtual void OnButtonOKClick(wxCommandEvent& event);
44  virtual bool ValidateData();
45 
46  PropertiesData* m_properties = NULL;
47 };
48 #endif // GENERALPROPERTIESFORM_H
General and simulation data manager.
Form to edit the software&#39;s general data.
diff --git a/docs/doxygen/html/_generator_stab_form_8cpp_source.html b/docs/doxygen/html/_generator_stab_form_8cpp_source.html index bfb4afc..6b06c32 100644 --- a/docs/doxygen/html/_generator_stab_form_8cpp_source.html +++ b/docs/doxygen/html/_generator_stab_form_8cpp_source.html @@ -88,9 +88,10 @@ $(document).ready(function(){initNavTree('_generator_stab_form_8cpp_source.html'
GeneratorStabForm.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneratorStabForm.h"
19 #include "SwitchingForm.h"
20 #include "SyncGenerator.h"
21 #include "ControlEditor.h"
23 
24 GeneratorStabForm::GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator) : GeneratorStabFormBase(parent)
25 {
26  SetSize(GetBestSize());
27  m_syncGenerator = syncGenerator;
28  m_parent = parent;
29 
30  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
31 
32  m_checkBoxPlotSyncMachine->SetValue(data.plotSyncMachine);
33 
34  m_textCtrlInertia->SetValue(SyncGenerator::StringFromDouble(data.inertia));
35  m_textCtrlDamping->SetValue(SyncGenerator::StringFromDouble(data.damping));
36 
37  m_checkBoxUseAVR->SetValue(data.useAVR);
38  m_buttonEditAVR->Enable(data.useAVR);
39 
40  m_checkBoxUseSG->SetValue(data.useSpeedGovernor);
41  m_buttonEditSG->Enable(data.useSpeedGovernor);
42 
43  m_textCtrlRa->SetValue(SyncGenerator::StringFromDouble(data.armResistance));
44  m_textCtrlXp->SetValue(SyncGenerator::StringFromDouble(data.potierReactance));
45  m_textCtrlSat->SetValue(SyncGenerator::StringFromDouble(data.satFactor));
46 
47  m_textCtrlSyncXd->SetValue(SyncGenerator::StringFromDouble(data.syncXd));
48  m_textCtrlSyncXq->SetValue(SyncGenerator::StringFromDouble(data.syncXq));
49 
50  m_textCtrlTranXd->SetValue(SyncGenerator::StringFromDouble(data.transXd));
51  m_textCtrlTranXq->SetValue(SyncGenerator::StringFromDouble(data.transXq));
52  m_textCtrlTranTd0->SetValue(SyncGenerator::StringFromDouble(data.transTd0));
53  m_textCtrlTranTq0->SetValue(SyncGenerator::StringFromDouble(data.transTq0));
54 
55  m_textCtrlSubXd->SetValue(SyncGenerator::StringFromDouble(data.subXd));
56  m_textCtrlSubXq->SetValue(SyncGenerator::StringFromDouble(data.subXq));
57  m_textCtrlSubTd0->SetValue(SyncGenerator::StringFromDouble(data.subTd0));
58  m_textCtrlSubTq0->SetValue(SyncGenerator::StringFromDouble(data.subTq0));
59 }
60 
61 GeneratorStabForm::~GeneratorStabForm() {}
62 void GeneratorStabForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
63 void GeneratorStabForm::OnEditAVRButtonClick(wxCommandEvent& event)
64 {
65  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
66  if(!data.avr) {
67  data.avr = new ControlElementContainer();
68  m_syncGenerator->SetElectricalData(data);
69  }
70  ControlEditor* cEditor = new ControlEditor(m_parent, IOControl::IN_TERMINAL_VOLTAGE | IOControl::OUT_FIELD_VOLTAGE);
71  cEditor->SetElementsList(data.avr->GetControlElementsList());
72  cEditor->SetConnectionsList(data.avr->GetConnectionLineList());
73  cEditor->SetControlContainer(data.avr);
74  cEditor->Show();
75 }
76 
77 void GeneratorStabForm::OnOKButtonClick(wxCommandEvent& event)
78 {
79  if(ValidateData()) EndModal(wxID_OK);
80 }
81 
82 void GeneratorStabForm::OnSpeedGovernorButtonClick(wxCommandEvent& event)
83 {
84  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
85  if(!data.speedGov) {
86  data.speedGov = new ControlElementContainer();
87  m_syncGenerator->SetElectricalData(data);
88  }
89  ControlEditor* cEditor = new ControlEditor(m_parent, IOControl::IN_VELOCITY | IOControl::OUT_MEC_POWER);
90  cEditor->SetElementsList(data.speedGov->GetControlElementsList());
91  cEditor->SetConnectionsList(data.speedGov->GetConnectionLineList());
92  cEditor->SetControlContainer(data.speedGov);
93  cEditor->Show();
94 }
95 
96 void GeneratorStabForm::OnSwitchingButtonClick(wxCommandEvent& event)
97 {
98  if(ValidateData()) {
99  SwitchingForm swForm(m_parent, m_syncGenerator);
100  swForm.SetTitle(_("Synchronous generator: Switching"));
101  swForm.ShowModal();
102  EndModal(wxID_OK);
103  }
104 }
105 
106 bool GeneratorStabForm::ValidateData()
107 {
108  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
109 
110  data.plotSyncMachine = m_checkBoxPlotSyncMachine->GetValue();
111 
112  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlInertia->GetValue(), data.inertia,
113  _("Value entered incorrectly in the field \"Inertia\".")))
114  return false;
115 
116  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlDamping->GetValue(), data.damping,
117  _("Value entered incorrectly in the field \"Damping factor\".")))
118  return false;
119 
120  data.useAVR = m_checkBoxUseAVR->GetValue();
121  data.useSpeedGovernor = m_checkBoxUseSG->GetValue();
122 
123  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlRa->GetValue(), data.armResistance,
124  _("Value entered incorrectly in the field \"Armature resistance\".")))
125  return false;
126 
127  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlXp->GetValue(), data.potierReactance,
128  _("Value entered incorrectly in the field \"Potier reactance\".")))
129  return false;
130 
131  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlSat->GetValue(), data.satFactor,
132  _("Value entered incorrectly in the field \"Saturation factor\".")))
133  return false;
134 
135  if(!m_syncGenerator->DoubleFromString(
136  m_parent, m_textCtrlSyncXd->GetValue(), data.syncXd,
137  _("Value entered incorrectly in the field \"Synchronous direct-axis reactance\".")))
138  return false;
139 
140  if(!m_syncGenerator->DoubleFromString(
141  m_parent, m_textCtrlSyncXq->GetValue(), data.syncXq,
142  _("Value entered incorrectly in the field \"Synchronous quadrature-axis reactance\".")))
143  return false;
144 
145  if(!m_syncGenerator->DoubleFromString(
146  m_parent, m_textCtrlTranXd->GetValue(), data.transXd,
147  _("Value entered incorrectly in the field \"Transitory direct-axis reactance\".")))
148  return false;
149 
150  if(!m_syncGenerator->DoubleFromString(
151  m_parent, m_textCtrlTranXq->GetValue(), data.transXq,
152  _("Value entered incorrectly in the field \"Transitory quadrature-axis reactance\".")))
153  return false;
154 
155  if(!m_syncGenerator->DoubleFromString(
156  m_parent, m_textCtrlTranTd0->GetValue(), data.transTd0,
157  _("Value entered incorrectly in the field \"Transitory direct-axis time constant\".")))
158  return false;
159 
160  if(!m_syncGenerator->DoubleFromString(
161  m_parent, m_textCtrlTranTq0->GetValue(), data.transTq0,
162  _("Value entered incorrectly in the field \"Transitory quadrature-axis time constant\".")))
163  return false;
164 
165  if(!m_syncGenerator->DoubleFromString(
166  m_parent, m_textCtrlSubXd->GetValue(), data.subXd,
167  _("Value entered incorrectly in the field \"Subtransitory direct-axis reactance\".")))
168  return false;
169 
170  if(!m_syncGenerator->DoubleFromString(
171  m_parent, m_textCtrlSubXq->GetValue(), data.subXq,
172  _("Value entered incorrectly in the field \"Subtransitory quadrature-axis reactance\".")))
173  return false;
174 
175  if(!m_syncGenerator->DoubleFromString(
176  m_parent, m_textCtrlSubTd0->GetValue(), data.subTd0,
177  _("Value entered incorrectly in the field \"Subtransitory direct-axis time constant\".")))
178  return false;
179 
180  if(!m_syncGenerator->DoubleFromString(
181  m_parent, m_textCtrlSubTq0->GetValue(), data.subTq0,
182  _("Value entered incorrectly in the field \"Subtransitory quadrature-axis time constant\".")))
183  return false;
184 
185  m_syncGenerator->SetElectricalData(data);
186 
187  return true;
188 }
189 void GeneratorStabForm::UseAVRClick(wxCommandEvent& event) { m_buttonEditAVR->Enable(m_checkBoxUseAVR->GetValue()); }
190 void GeneratorStabForm::UseSGClick(wxCommandEvent& event) { m_buttonEditSG->Enable(m_checkBoxUseSG->GetValue()); }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneratorStabForm.h"
19 #include "SwitchingForm.h"
20 #include "SyncGenerator.h"
21 #include "ControlEditor.h"
23 
24 GeneratorStabForm::GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator) : GeneratorStabFormBase(parent)
25 {
26  SetSize(GetBestSize());
27  m_syncGenerator = syncGenerator;
28  m_parent = parent;
29 
30  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
31 
32  m_checkBoxPlotSyncMachine->SetValue(data.plotSyncMachine);
33 
34  m_textCtrlInertia->SetValue(SyncGenerator::StringFromDouble(data.inertia));
35  m_textCtrlDamping->SetValue(SyncGenerator::StringFromDouble(data.damping));
36 
37  m_checkBoxUseAVR->SetValue(data.useAVR);
38  m_buttonEditAVR->Enable(data.useAVR);
39 
40  m_checkBoxUseSG->SetValue(data.useSpeedGovernor);
41  m_buttonEditSG->Enable(data.useSpeedGovernor);
42 
43  m_textCtrlRa->SetValue(SyncGenerator::StringFromDouble(data.armResistance));
44  m_textCtrlXp->SetValue(SyncGenerator::StringFromDouble(data.potierReactance));
45  m_textCtrlSat->SetValue(SyncGenerator::StringFromDouble(data.satFactor));
46 
47  m_textCtrlSyncXd->SetValue(SyncGenerator::StringFromDouble(data.syncXd));
48  m_textCtrlSyncXq->SetValue(SyncGenerator::StringFromDouble(data.syncXq));
49 
50  m_textCtrlTranXd->SetValue(SyncGenerator::StringFromDouble(data.transXd));
51  m_textCtrlTranXq->SetValue(SyncGenerator::StringFromDouble(data.transXq));
52  m_textCtrlTranTd0->SetValue(SyncGenerator::StringFromDouble(data.transTd0));
53  m_textCtrlTranTq0->SetValue(SyncGenerator::StringFromDouble(data.transTq0));
54 
55  m_textCtrlSubXd->SetValue(SyncGenerator::StringFromDouble(data.subXd));
56  m_textCtrlSubXq->SetValue(SyncGenerator::StringFromDouble(data.subXq));
57  m_textCtrlSubTd0->SetValue(SyncGenerator::StringFromDouble(data.subTd0));
58  m_textCtrlSubTq0->SetValue(SyncGenerator::StringFromDouble(data.subTq0));
59 }
60 
61 GeneratorStabForm::~GeneratorStabForm() {}
62 void GeneratorStabForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
63 void GeneratorStabForm::OnEditAVRButtonClick(wxCommandEvent& event)
64 {
65  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
66  if(!data.avr) {
67  data.avr = new ControlElementContainer();
68  m_syncGenerator->SetElectricalData(data);
69  }
70  ControlEditor* cEditor = new ControlEditor(m_parent, IOControl::IN_TERMINAL_VOLTAGE | IOControl::OUT_FIELD_VOLTAGE);
71  cEditor->SetElementsList(data.avr->GetControlElementsList());
72  cEditor->SetConnectionsList(data.avr->GetConnectionLineList());
73  cEditor->SetControlContainer(data.avr);
74  cEditor->Show();
75 }
76 
77 void GeneratorStabForm::OnOKButtonClick(wxCommandEvent& event)
78 {
79  if(ValidateData()) EndModal(wxID_OK);
80 }
81 
82 void GeneratorStabForm::OnSpeedGovernorButtonClick(wxCommandEvent& event)
83 {
84  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
85  if(!data.speedGov) {
86  data.speedGov = new ControlElementContainer();
87  m_syncGenerator->SetElectricalData(data);
88  }
89  ControlEditor* cEditor = new ControlEditor(m_parent, IOControl::IN_VELOCITY | IOControl::OUT_MEC_POWER);
90  cEditor->SetElementsList(data.speedGov->GetControlElementsList());
91  cEditor->SetConnectionsList(data.speedGov->GetConnectionLineList());
92  cEditor->SetControlContainer(data.speedGov);
93  cEditor->Show();
94 }
95 
96 void GeneratorStabForm::OnSwitchingButtonClick(wxCommandEvent& event)
97 {
98  if(ValidateData()) {
99  SwitchingForm swForm(m_parent, m_syncGenerator);
100  swForm.SetTitle(_("Synchronous generator: Switching"));
101  swForm.ShowModal();
102  EndModal(wxID_OK);
103  }
104 }
105 
106 bool GeneratorStabForm::ValidateData()
107 {
108  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
109 
110  data.plotSyncMachine = m_checkBoxPlotSyncMachine->GetValue();
111 
112  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlInertia->GetValue(), data.inertia,
113  _("Value entered incorrectly in the field \"Inertia\".")))
114  return false;
115 
116  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlDamping->GetValue(), data.damping,
117  _("Value entered incorrectly in the field \"Damping factor\".")))
118  return false;
119 
120  data.useAVR = m_checkBoxUseAVR->GetValue();
121  data.useSpeedGovernor = m_checkBoxUseSG->GetValue();
122 
123  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlRa->GetValue(), data.armResistance,
124  _("Value entered incorrectly in the field \"Armature resistance\".")))
125  return false;
126 
127  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlXp->GetValue(), data.potierReactance,
128  _("Value entered incorrectly in the field \"Potier reactance\".")))
129  return false;
130 
131  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlSat->GetValue(), data.satFactor,
132  _("Value entered incorrectly in the field \"Saturation factor\".")))
133  return false;
134 
135  if(!m_syncGenerator->DoubleFromString(
136  m_parent, m_textCtrlSyncXd->GetValue(), data.syncXd,
137  _("Value entered incorrectly in the field \"Synchronous direct-axis reactance\".")))
138  return false;
139 
140  if(!m_syncGenerator->DoubleFromString(
141  m_parent, m_textCtrlSyncXq->GetValue(), data.syncXq,
142  _("Value entered incorrectly in the field \"Synchronous quadrature-axis reactance\".")))
143  return false;
144 
145  if(!m_syncGenerator->DoubleFromString(
146  m_parent, m_textCtrlTranXd->GetValue(), data.transXd,
147  _("Value entered incorrectly in the field \"Transitory direct-axis reactance\".")))
148  return false;
149 
150  if(!m_syncGenerator->DoubleFromString(
151  m_parent, m_textCtrlTranXq->GetValue(), data.transXq,
152  _("Value entered incorrectly in the field \"Transitory quadrature-axis reactance\".")))
153  return false;
154 
155  if(!m_syncGenerator->DoubleFromString(
156  m_parent, m_textCtrlTranTd0->GetValue(), data.transTd0,
157  _("Value entered incorrectly in the field \"Transitory direct-axis time constant\".")))
158  return false;
159 
160  if(!m_syncGenerator->DoubleFromString(
161  m_parent, m_textCtrlTranTq0->GetValue(), data.transTq0,
162  _("Value entered incorrectly in the field \"Transitory quadrature-axis time constant\".")))
163  return false;
164 
165  if(!m_syncGenerator->DoubleFromString(
166  m_parent, m_textCtrlSubXd->GetValue(), data.subXd,
167  _("Value entered incorrectly in the field \"Subtransitory direct-axis reactance\".")))
168  return false;
169 
170  if(!m_syncGenerator->DoubleFromString(
171  m_parent, m_textCtrlSubXq->GetValue(), data.subXq,
172  _("Value entered incorrectly in the field \"Subtransitory quadrature-axis reactance\".")))
173  return false;
174 
175  if(!m_syncGenerator->DoubleFromString(
176  m_parent, m_textCtrlSubTd0->GetValue(), data.subTd0,
177  _("Value entered incorrectly in the field \"Subtransitory direct-axis time constant\".")))
178  return false;
179 
180  if(!m_syncGenerator->DoubleFromString(
181  m_parent, m_textCtrlSubTq0->GetValue(), data.subTq0,
182  _("Value entered incorrectly in the field \"Subtransitory quadrature-axis time constant\".")))
183  return false;
184 
185  m_syncGenerator->SetElectricalData(data);
186 
187  return true;
188 }
189 void GeneratorStabForm::UseAVRClick(wxCommandEvent& event) { m_buttonEditAVR->Enable(m_checkBoxUseAVR->GetValue()); }
190 void GeneratorStabForm::UseSGClick(wxCommandEvent& event) { m_buttonEditSG->Enable(m_checkBoxUseSG->GetValue()); }
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
- + +
Synchronous generator power element.
diff --git a/docs/doxygen/html/_generator_stab_form_8h_source.html b/docs/doxygen/html/_generator_stab_form_8h_source.html index 3469265..62ee696 100644 --- a/docs/doxygen/html/_generator_stab_form_8h_source.html +++ b/docs/doxygen/html/_generator_stab_form_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_generator_stab_form_8h_source.html','
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GENERATORSTABFORM_H
19 #define GENERATORSTABFORM_H
20 
21 #include "ElementForm.h"
22 
23 class SwitchingForm;
24 class SyncGenerator;
25 class ControlEditor;
27 
36 {
37  public:
38  GeneratorStabForm(wxWindow* parent, SyncGenerator* syncGenerator);
39  virtual ~GeneratorStabForm();
40 
41  protected:
42  virtual void UseAVRClick(wxCommandEvent& event);
43  virtual void UseSGClick(wxCommandEvent& event);
44  virtual void OnCancelButtonClick(wxCommandEvent& event);
45  virtual void OnEditAVRButtonClick(wxCommandEvent& event);
46  virtual void OnOKButtonClick(wxCommandEvent& event);
47  virtual void OnSpeedGovernorButtonClick(wxCommandEvent& event);
48  virtual void OnSwitchingButtonClick(wxCommandEvent& event);
49 
50  virtual bool ValidateData();
51 
52  SyncGenerator* m_syncGenerator = NULL;
53  wxWindow* m_parent = NULL;
54 };
55 #endif // GENERATORSTABFORM_H
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
- +
Synchronous generator power element.
Form to edit the synchronous generator data for electromechanical studies.
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
diff --git a/docs/doxygen/html/_graphical_element_8cpp_source.html b/docs/doxygen/html/_graphical_element_8cpp_source.html index a434513..d5d8d72 100644 --- a/docs/doxygen/html/_graphical_element_8cpp_source.html +++ b/docs/doxygen/html/_graphical_element_8cpp_source.html @@ -88,7 +88,8 @@ $(document).ready(function(){initNavTree('_graphical_element_8cpp_source.html','
GraphicalElement.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GraphicalElement.h"
19 
20 GraphicalElement::GraphicalElement() : Element()
21 {
22 }
23 
24 GraphicalElement::~GraphicalElement()
25 {
26 }
27 
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GraphicalElement.h"
19 
20 GraphicalElement::GraphicalElement() : Element()
21 {
22 }
23 
24 GraphicalElement::~GraphicalElement()
25 {
26 }
27 
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
diff --git a/docs/doxygen/html/_graphical_element_8h.html b/docs/doxygen/html/_graphical_element_8h.html new file mode 100644 index 0000000..362b0bf --- /dev/null +++ b/docs/doxygen/html/_graphical_element_8h.html @@ -0,0 +1,115 @@ + + + + + + + + + +Project/GraphicalElement.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
GraphicalElement.h File Reference
+
+
+
#include "Element.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  GraphicalElement
 Abstract class for graphical elements shown with power elements in workspace. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_graphical_element_8h_source.html b/docs/doxygen/html/_graphical_element_8h_source.html index 3331a7f..3f28397 100644 --- a/docs/doxygen/html/_graphical_element_8h_source.html +++ b/docs/doxygen/html/_graphical_element_8h_source.html @@ -88,15 +88,15 @@ $(document).ready(function(){initNavTree('_graphical_element_8h_source.html','')
GraphicalElement.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GRAPHICALELEMENT_H
19 #define GRAPHICALELEMENT_H
20 
21 #include "Element.h"
22 
23 class GraphicalElement : public Element
24 {
25  public:
28 };
29 
30 #endif // GRAPHICALELEMENT_H
- -
Class to manage color of OpenGL.
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef GRAPHICALELEMENT_H
19 #define GRAPHICALELEMENT_H
20 
21 #include "Element.h"
22 
30 class GraphicalElement : public Element
31 {
32  public:
35 };
36 
37 #endif // GRAPHICALELEMENT_H
Abstract class for graphical elements shown with power elements in workspace.
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IOControl.h"
19 #include "IOControlForm.h"
20 
21 IOControl::IOControl(int ioFlags, int id) : ControlElement(id)
22 {
23  m_ioFlags = ioFlags;
24 
25  Node* node = new Node(m_position, Node::NODE_IN, m_borderSize);
26  m_nodeList.push_back(node);
27 
28  if(ioFlags & IN_TERMINAL_VOLTAGE)
29  SetValue(IN_TERMINAL_VOLTAGE);
30  else if(ioFlags & IN_VELOCITY)
31  SetValue(IN_VELOCITY);
32  node->StartMove(m_position);
33 }
34 
35 IOControl::~IOControl() {}
36 void IOControl::Draw(wxPoint2DDouble translation, double scale) const
37 {
38  std::vector<wxPoint2DDouble> pts;
39  if(m_angle == 0.0) {
40  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
41  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize - 10, m_borderSize));
42  pts.push_back(m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0));
43  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize - 10, -m_borderSize));
44  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
45  } else if(m_angle == 90.0) {
46  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
47  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
48  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize - 10));
49  pts.push_back(m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize));
50  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize - 10));
51  } else if(m_angle == 180.0) {
52  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize + 10, m_borderSize));
53  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
54  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
55  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize + 10, -m_borderSize));
56  pts.push_back(m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0));
57  } else if(m_angle == 270.0) {
58  pts.push_back(m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize));
59  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize + 10));
60  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
61  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
62  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize + 10));
63  }
64 
65  if(m_selected) {
66  glColor4dv(m_selectionColour.GetRGBA());
67  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
68  std::vector<wxPoint2DDouble> selPts = pts;
69  if(m_angle == 0.0) {
70  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
71  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
72  selPts[2] += wxPoint2DDouble(1.5 * borderSize / 2, 0);
73  selPts[3] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
74  selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
75  } else if(m_angle == 90.0) {
76  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
77  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
78  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
79  selPts[3] += wxPoint2DDouble(0, 1.5 * borderSize / 2);
80  selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
81  } else if(m_angle == 180.0) {
82  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
83  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
84  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
85  selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
86  selPts[4] += wxPoint2DDouble(-1.5 * borderSize / 2, 0);
87  } else if(m_angle == 270.0) {
88  selPts[0] += wxPoint2DDouble(0, -1.5 * borderSize / 2);
89  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
90  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
91  selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
92  selPts[4] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
93  }
94  DrawLine(selPts, GL_POLYGON);
95  }
96  glLineWidth(1.0);
97  glColor4d(1.0, 1.0, 1.0, 1.0);
98  DrawLine(pts, GL_POLYGON);
99  glColor4d(0.0, 0.0, 0.0, 1.0);
100  DrawLine(pts, GL_LINE_LOOP);
101 
102  // Plot number.
103  glEnable(GL_TEXTURE_2D);
104  glColor4d(0.0, 0.0, 0.0, 1.0);
105  m_glStringValue->bind();
106  if(m_angle == 0.0) {
107  m_glStringValue->render(m_position.m_x - 5, m_position.m_y);
108  } else if(m_angle == 90.0) {
109  m_glStringValue->render(m_position.m_x, m_position.m_y - 5);
110  } else if(m_angle == 180.0) {
111  m_glStringValue->render(m_position.m_x + 5, m_position.m_y);
112  } else if(m_angle == 270.0) {
113  m_glStringValue->render(m_position.m_x, m_position.m_y + 5);
114  }
115 
116  glDisable(GL_TEXTURE_2D);
117 
118  glColor4d(0.0, 0.0, 0.0, 1.0);
119  DrawNodes();
120 }
121 
122 bool IOControl::ShowForm(wxWindow* parent, Element* element)
123 {
124  IOControlForm* form = new IOControlForm(parent, this);
125  if(form->ShowModal() == wxID_OK) {
126  form->Destroy();
127  return true;
128  }
129  form->Destroy();
130  return false;
131 }
132 
133 void IOControl::Rotate(bool clockwise)
134 {
135  if(clockwise)
136  m_angle += 90.0;
137  else
138  m_angle -= 90.0;
139  if(m_angle >= 360.0)
140  m_angle = 0.0;
141  else if(m_angle < 0)
142  m_angle = 270.0;
143 
144  UpdatePoints();
145 
146  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
147  Node* node = *it;
148  node->Rotate(clockwise);
149  }
150 }
151 
152 wxString IOControl::GenerateText()
153 {
154  wxString omega = wxString::FromUTF8("\xCF\x89");
155 
156  switch(m_value) {
157  case IN_TERMINAL_VOLTAGE: {
158  m_ioNodeType = Node::NODE_OUT;
159  return _("Vt");
160  } break;
161  case IN_VELOCITY: {
162  m_ioNodeType = Node::NODE_OUT;
163  return omega;
164  } break;
165  case IN_ACTIVE_POWER: {
166  m_ioNodeType = Node::NODE_OUT;
167  return _("Pe");
168  } break;
169  case IN_REACTIVE_POWER: {
170  m_ioNodeType = Node::NODE_OUT;
171  return _("Qe");
172  } break;
173  case OUT_FIELD_VOLTAGE: {
174  m_ioNodeType = Node::NODE_IN;
175  return _("Vf");
176  } break;
177  case OUT_MEC_POWER: {
178  m_ioNodeType = Node::NODE_IN;
179  return _("Pm");
180  } break;
181  }
182  return "";
183 }
184 
185 void IOControl::SetValue(IOFlags value)
186 {
187  m_value = value;
188  wxString text = GenerateText();
189 
190  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
191  wxScreenDC dc;
192 
193  if(m_glStringValue) {
194  delete m_glStringValue;
195  m_glStringValue = NULL;
196  }
197  m_glStringValue = new wxGLString(text);
198  m_glStringValue->setFont(font);
199  m_glStringValue->consolidate(&dc);
200 
201  m_width = m_glStringValue->getWidth() + 10 + 2 * m_borderSize;
202  m_height = m_glStringValue->getheight() + 10 + 2 * m_borderSize;
203 
204  SetPosition(m_position); // Update rectangle.
205 
206  UpdatePoints();
207 }
208 
209 void IOControl::UpdatePoints()
210 {
211  if(m_nodeList.size() != 0) {
212  Node* node = m_nodeList[0];
213  if(node->GetNodeType() != m_ioNodeType) {
214  // Rotate 180 degrees
215  node->Rotate();
216  node->Rotate();
217  }
218  node->SetNodeType(m_ioNodeType);
219  if(m_angle == 0.0) {
220  if(m_ioNodeType == Node::NODE_IN)
221  node->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
222  else
223  node->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
224  } else if(m_angle == 90.0) {
225  if(m_ioNodeType == Node::NODE_IN)
226  node->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
227  else
228  node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
229  } else if(m_angle == 180.0) {
230  if(m_ioNodeType == Node::NODE_IN)
231  node->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
232  else
233  node->SetPosition(m_position + wxPoint2DDouble(2 - m_width / 2, 0));
234  } else if(m_angle == 270.0) {
235  if(m_ioNodeType == Node::NODE_IN)
236  node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
237  else
238  node->SetPosition(m_position + wxPoint2DDouble(0, 2 - m_height / 2));
239  }
240  }
241 }
242 
244 {
245  IOControl* copy = new IOControl(m_ioFlags, m_elementID);
246  *copy = *this;
247  m_glStringValue = NULL;
248  SetValue(m_value);
249  return copy;
250 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IOControl.h"
19 #include "IOControlForm.h"
20 
21 IOControl::IOControl(int ioFlags, int id) : ControlElement(id)
22 {
23  m_ioFlags = ioFlags;
24 
25  Node* node = new Node(m_position, Node::NODE_IN, m_borderSize);
26  m_nodeList.push_back(node);
27 
28  if(ioFlags & IN_TERMINAL_VOLTAGE)
29  SetValue(IN_TERMINAL_VOLTAGE);
30  else if(ioFlags & IN_VELOCITY)
31  SetValue(IN_VELOCITY);
32  node->StartMove(m_position);
33 }
34 
35 IOControl::~IOControl() {}
36 void IOControl::Draw(wxPoint2DDouble translation, double scale) const
37 {
38  std::vector<wxPoint2DDouble> pts;
39  if(m_angle == 0.0) {
40  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
41  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize - 10, m_borderSize));
42  pts.push_back(m_position + wxPoint2DDouble(m_width / 2 - m_borderSize, 0));
43  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize - 10, -m_borderSize));
44  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
45  } else if(m_angle == 90.0) {
46  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize));
47  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
48  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize - 10));
49  pts.push_back(m_position + wxPoint2DDouble(0, m_height / 2 - m_borderSize));
50  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize - 10));
51  } else if(m_angle == 180.0) {
52  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize + 10, m_borderSize));
53  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize));
54  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
55  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize + 10, -m_borderSize));
56  pts.push_back(m_position + wxPoint2DDouble(-m_width / 2 + m_borderSize, 0));
57  } else if(m_angle == 270.0) {
58  pts.push_back(m_position + wxPoint2DDouble(0, -m_height / 2 + m_borderSize));
59  pts.push_back(m_rect.GetRightTop() + wxPoint2DDouble(-m_borderSize, m_borderSize + 10));
60  pts.push_back(m_rect.GetRightBottom() + wxPoint2DDouble(-m_borderSize, -m_borderSize));
61  pts.push_back(m_rect.GetLeftBottom() + wxPoint2DDouble(m_borderSize, -m_borderSize));
62  pts.push_back(m_rect.GetLeftTop() + wxPoint2DDouble(m_borderSize, m_borderSize + 10));
63  }
64 
65  if(m_selected) {
66  glColor4dv(m_selectionColour.GetRGBA());
67  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
68  std::vector<wxPoint2DDouble> selPts = pts;
69  if(m_angle == 0.0) {
70  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
71  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
72  selPts[2] += wxPoint2DDouble(1.5 * borderSize / 2, 0);
73  selPts[3] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
74  selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
75  } else if(m_angle == 90.0) {
76  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
77  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
78  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
79  selPts[3] += wxPoint2DDouble(0, 1.5 * borderSize / 2);
80  selPts[4] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
81  } else if(m_angle == 180.0) {
82  selPts[0] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
83  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
84  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
85  selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
86  selPts[4] += wxPoint2DDouble(-1.5 * borderSize / 2, 0);
87  } else if(m_angle == 270.0) {
88  selPts[0] += wxPoint2DDouble(0, -1.5 * borderSize / 2);
89  selPts[1] += wxPoint2DDouble(borderSize / 2, -borderSize / 2);
90  selPts[2] += wxPoint2DDouble(borderSize / 2, borderSize / 2);
91  selPts[3] += wxPoint2DDouble(-borderSize / 2, borderSize / 2);
92  selPts[4] += wxPoint2DDouble(-borderSize / 2, -borderSize / 2);
93  }
94  DrawLine(selPts, GL_POLYGON);
95  }
96  glLineWidth(1.0);
97  glColor4d(1.0, 1.0, 1.0, 1.0);
98  DrawLine(pts, GL_POLYGON);
99  glColor4d(0.0, 0.0, 0.0, 1.0);
100  DrawLine(pts, GL_LINE_LOOP);
101 
102  // Plot number.
103  glEnable(GL_TEXTURE_2D);
104  glColor4d(0.0, 0.0, 0.0, 1.0);
105  m_glStringValue->bind();
106  if(m_angle == 0.0) {
107  m_glStringValue->render(m_position.m_x - 5, m_position.m_y);
108  } else if(m_angle == 90.0) {
109  m_glStringValue->render(m_position.m_x, m_position.m_y - 5);
110  } else if(m_angle == 180.0) {
111  m_glStringValue->render(m_position.m_x + 5, m_position.m_y);
112  } else if(m_angle == 270.0) {
113  m_glStringValue->render(m_position.m_x, m_position.m_y + 5);
114  }
115 
116  glDisable(GL_TEXTURE_2D);
117 
118  glColor4d(0.0, 0.0, 0.0, 1.0);
119  DrawNodes();
120 }
121 
122 bool IOControl::ShowForm(wxWindow* parent, Element* element)
123 {
124  IOControlForm* form = new IOControlForm(parent, this);
125  if(form->ShowModal() == wxID_OK) {
126  form->Destroy();
127  return true;
128  }
129  form->Destroy();
130  return false;
131 }
132 
133 void IOControl::Rotate(bool clockwise)
134 {
135  if(clockwise)
136  m_angle += 90.0;
137  else
138  m_angle -= 90.0;
139  if(m_angle >= 360.0)
140  m_angle = 0.0;
141  else if(m_angle < 0)
142  m_angle = 270.0;
143 
144  UpdatePoints();
145 
146  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
147  Node* node = *it;
148  node->Rotate(clockwise);
149  }
150 }
151 
152 wxString IOControl::GenerateText()
153 {
154  wxString omega = wxString::FromUTF8("\xCF\x89");
155 
156  switch(m_value) {
157  case IN_TERMINAL_VOLTAGE: {
158  m_ioNodeType = Node::NODE_OUT;
159  return _("Vt");
160  } break;
161  case IN_VELOCITY: {
162  m_ioNodeType = Node::NODE_OUT;
163  return omega;
164  } break;
165  case IN_ACTIVE_POWER: {
166  m_ioNodeType = Node::NODE_OUT;
167  return _("Pe");
168  } break;
169  case IN_REACTIVE_POWER: {
170  m_ioNodeType = Node::NODE_OUT;
171  return _("Qe");
172  } break;
173  case OUT_FIELD_VOLTAGE: {
174  m_ioNodeType = Node::NODE_IN;
175  return _("Vf");
176  } break;
177  case OUT_MEC_POWER: {
178  m_ioNodeType = Node::NODE_IN;
179  return _("Pm");
180  } break;
181  }
182  return "";
183 }
184 
185 void IOControl::SetValue(IOFlags value)
186 {
187  m_value = value;
188  wxString text = GenerateText();
189 
190  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
191  wxScreenDC dc;
192 
193  if(m_glStringValue) {
194  delete m_glStringValue;
195  m_glStringValue = NULL;
196  }
197  m_glStringValue = new wxGLString(text);
198  m_glStringValue->setFont(font);
199  m_glStringValue->consolidate(&dc);
200 
201  m_width = m_glStringValue->getWidth() + 10 + 2 * m_borderSize;
202  m_height = m_glStringValue->getheight() + 10 + 2 * m_borderSize;
203 
204  SetPosition(m_position); // Update rectangle.
205 
206  UpdatePoints();
207 }
208 
209 void IOControl::UpdatePoints()
210 {
211  if(m_nodeList.size() != 0) {
212  Node* node = m_nodeList[0];
213  if(node->GetNodeType() != m_ioNodeType) {
214  // Rotate 180 degrees
215  node->Rotate();
216  node->Rotate();
217  }
218  node->SetNodeType(m_ioNodeType);
219  if(m_angle == 0.0) {
220  if(m_ioNodeType == Node::NODE_IN)
221  node->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
222  else
223  node->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 2, 0));
224  } else if(m_angle == 90.0) {
225  if(m_ioNodeType == Node::NODE_IN)
226  node->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
227  else
228  node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2 - 2));
229  } else if(m_angle == 180.0) {
230  if(m_ioNodeType == Node::NODE_IN)
231  node->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
232  else
233  node->SetPosition(m_position + wxPoint2DDouble(2 - m_width / 2, 0));
234  } else if(m_angle == 270.0) {
235  if(m_ioNodeType == Node::NODE_IN)
236  node->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
237  else
238  node->SetPosition(m_position + wxPoint2DDouble(0, 2 - m_height / 2));
239  }
240  }
241 }
242 
244 {
245  IOControl* copy = new IOControl(m_ioFlags, m_elementID);
246  *copy = *this;
247  m_glStringValue = NULL;
248  SetValue(m_value);
249  return copy;
250 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void DrawLine(std::vector< wxPoint2DDouble > points, GLenum mode=GL_LINE_STRIP) const
Draw line.
Definition: Element.cpp:89
Node of a control element. This class manages the user interaction with the connection and control el...
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: IOControl.cpp:133
diff --git a/docs/doxygen/html/_i_o_control_8h_source.html b/docs/doxygen/html/_i_o_control_8h_source.html index ae24203..4950e4d 100644 --- a/docs/doxygen/html/_i_o_control_8h_source.html +++ b/docs/doxygen/html/_i_o_control_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_i_o_control_8h_source.html','');});
IOControl.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef IOCONTROL_H
19 #define IOCONTROL_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class IOControlForm;
27 
35 class IOControl : public ControlElement
36 {
37  public:
38  enum IOFlags {
39  IN_TERMINAL_VOLTAGE = 1 << 0,
40  IN_VELOCITY = 1 << 1,
41  IN_ACTIVE_POWER = 1 << 2,
42  IN_REACTIVE_POWER = 1 << 3,
43  OUT_FIELD_VOLTAGE = 1 << 4,
44  OUT_MEC_POWER = 1 << 5
45  };
46 
47  IOControl(int ioFlags, int id);
48  ~IOControl();
49 
50  virtual void Draw(wxPoint2DDouble translation, double scale) const;
51  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
52  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
53  virtual bool ShowForm(wxWindow* parent, Element* element);
54  virtual void Rotate(bool clockwise = true);
55  virtual void UpdateText() { SetValue(m_value); }
56  virtual wxString GenerateText();
57  virtual void UpdatePoints();
58 
59  virtual IOFlags GetValue() const { return m_value; }
60  virtual void SetValue(IOFlags value);
61  virtual int GetIOFlags() const { return m_ioFlags; }
62  virtual Node::NodeType GetType() { return m_ioNodeType; }
63  virtual Element* GetCopy();
64 
65  protected:
66  IOFlags m_value;
67  int m_ioFlags;
68 
69  Node::NodeType m_ioNodeType = Node::NODE_IN;
70 
71  wxGLString* m_glStringValue = NULL;
72  int m_fontSize = 10;
73 };
74 
75 #endif // IOCONTROL_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef IOCONTROL_H
19 #define IOCONTROL_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
26 class IOControlForm;
27 
35 class IOControl : public ControlElement
36 {
37  public:
38  enum IOFlags {
39  IN_TERMINAL_VOLTAGE = 1 << 0,
40  IN_VELOCITY = 1 << 1,
41  IN_ACTIVE_POWER = 1 << 2,
42  IN_REACTIVE_POWER = 1 << 3,
43  OUT_FIELD_VOLTAGE = 1 << 4,
44  OUT_MEC_POWER = 1 << 5
45  };
46 
47  IOControl(int ioFlags, int id);
48  ~IOControl();
49 
50  virtual void Draw(wxPoint2DDouble translation, double scale) const;
51  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
52  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
53  virtual bool ShowForm(wxWindow* parent, Element* element);
54  virtual void Rotate(bool clockwise = true);
55  virtual void UpdateText() { SetValue(m_value); }
56  virtual wxString GenerateText();
57  virtual void UpdatePoints();
58 
59  virtual IOFlags GetValue() const { return m_value; }
60  virtual void SetValue(IOFlags value);
61  virtual int GetIOFlags() const { return m_ioFlags; }
62  virtual Node::NodeType GetType() { return m_ioNodeType; }
63  virtual Element* GetCopy();
64 
65  protected:
66  IOFlags m_value;
67  int m_ioFlags;
68 
69  Node::NodeType m_ioNodeType = Node::NODE_IN;
70 
71  wxGLString* m_glStringValue = NULL;
72  int m_fontSize = 10;
73 };
74 
75 #endif // IOCONTROL_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: IOControl.h:51
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: IOControl.cpp:133
Provides the communication with the power element.
Definition: IOControl.h:35
diff --git a/docs/doxygen/html/_ind_motor_8cpp_source.html b/docs/doxygen/html/_ind_motor_8cpp_source.html index d690c6f..3b97823 100644 --- a/docs/doxygen/html/_ind_motor_8cpp_source.html +++ b/docs/doxygen/html/_ind_motor_8cpp_source.html @@ -88,8 +88,8 @@ $(document).ready(function(){initNavTree('_ind_motor_8cpp_source.html','');});
IndMotor.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IndMotorForm.h"
19 #include "IndMotor.h"
20 
21 IndMotor::IndMotor() : Machines() {}
22 IndMotor::IndMotor(wxString name) : Machines() { m_electricalData.name = name; }
23 IndMotor::~IndMotor() {}
24 void IndMotor::DrawSymbol() const
25 {
26  std::vector<wxPoint2DDouble> mPts;
27  mPts.push_back(wxPoint2DDouble(-10, 13) + m_position);
28  mPts.push_back(wxPoint2DDouble(-10, -13) + m_position);
29  mPts.push_back(wxPoint2DDouble(0, 2) + m_position);
30  mPts.push_back(wxPoint2DDouble(10, -13) + m_position);
31  mPts.push_back(wxPoint2DDouble(10, 13) + m_position);
32  DrawLine(mPts);
33 }
34 
35 bool IndMotor::GetContextMenu(wxMenu& menu)
36 {
37  menu.Append(ID_EDIT_ELEMENT, _("Edit induction motor"));
38  GeneralMenuItens(menu);
39  return true;
40 }
41 
42 bool IndMotor::ShowForm(wxWindow* parent, Element* element)
43 {
44  IndMotorForm* indMotorForm = new IndMotorForm(parent, this);
45  if(indMotorForm->ShowModal() == wxID_OK) {
46  indMotorForm->Destroy();
47  return true;
48  }
49  indMotorForm->Destroy();
50  return false;
51 }
52 
53 IndMotorElectricalData IndMotor::GetPUElectricalData(double systemPowerBase)
54 {
55  IndMotorElectricalData data = m_electricalData;
56 
57  switch(data.activePowerUnit) {
58  case UNIT_W: {
59  data.activePower = data.activePower / systemPowerBase;
60  data.activePowerUnit = UNIT_PU;
61  } break;
62  case UNIT_kW: {
63  data.activePower = (data.activePower * 1e3) / systemPowerBase;
64  data.activePowerUnit = UNIT_PU;
65  } break;
66  case UNIT_MW: {
67  data.activePower = (data.activePower * 1e6) / systemPowerBase;
68  data.activePowerUnit = UNIT_PU;
69  } break;
70  default:
71  break;
72  }
73  switch(data.reactivePowerUnit) {
74  case UNIT_VAr: {
75  data.reactivePower = data.reactivePower / systemPowerBase;
76  data.reactivePowerUnit = UNIT_PU;
77  } break;
78  case UNIT_kVAr: {
79  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
80  data.reactivePowerUnit = UNIT_PU;
81  } break;
82  case UNIT_MVAr: {
83  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
84  data.reactivePowerUnit = UNIT_PU;
85  } break;
86  default:
87  break;
88  }
89 
90  return data;
91 }
92 
94 {
95  IndMotor* copy = new IndMotor();
96  *copy = *this;
97  return copy;
98 }
99 
100 wxString IndMotor::GetTipText() const
101 {
102  wxString tipText = m_electricalData.name;
103  tipText += "\n";
104  double activePower = m_electricalData.activePower;
105  if(!m_online) activePower = 0.0;
106  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
107  switch(m_electricalData.activePowerUnit) {
108  case UNIT_PU: {
109  tipText += _(" p.u.");
110  } break;
111  case UNIT_W: {
112  tipText += _(" W");
113  } break;
114  case UNIT_kW: {
115  tipText += _(" kW");
116  } break;
117  case UNIT_MW: {
118  tipText += _(" MW");
119  } break;
120  default:
121  break;
122  }
123  double reactivePower = m_electricalData.reactivePower;
124  if(!m_online) reactivePower = 0.0;
125  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
126  switch(m_electricalData.reactivePowerUnit) {
127  case UNIT_PU: {
128  tipText += _(" p.u.");
129  } break;
130  case UNIT_VAr: {
131  tipText += _(" VAr");
132  } break;
133  case UNIT_kVAr: {
134  tipText += _(" kVAr");
135  } break;
136  case UNIT_MVAr: {
137  tipText += _(" MVAr");
138  } break;
139  default:
140  break;
141  }
142 
143  return tipText;
144 }
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IndMotorForm.h"
19 #include "IndMotor.h"
20 
21 IndMotor::IndMotor() : Machines() {}
22 IndMotor::IndMotor(wxString name) : Machines() { m_electricalData.name = name; }
23 IndMotor::~IndMotor() {}
24 void IndMotor::DrawSymbol() const
25 {
26  std::vector<wxPoint2DDouble> mPts;
27  mPts.push_back(wxPoint2DDouble(-10, 13) + m_position);
28  mPts.push_back(wxPoint2DDouble(-10, -13) + m_position);
29  mPts.push_back(wxPoint2DDouble(0, 2) + m_position);
30  mPts.push_back(wxPoint2DDouble(10, -13) + m_position);
31  mPts.push_back(wxPoint2DDouble(10, 13) + m_position);
32  DrawLine(mPts);
33 }
34 
35 bool IndMotor::GetContextMenu(wxMenu& menu)
36 {
37  menu.Append(ID_EDIT_ELEMENT, _("Edit induction motor"));
38  GeneralMenuItens(menu);
39  return true;
40 }
41 
42 bool IndMotor::ShowForm(wxWindow* parent, Element* element)
43 {
44  IndMotorForm* indMotorForm = new IndMotorForm(parent, this);
45  if(indMotorForm->ShowModal() == wxID_OK) {
46  indMotorForm->Destroy();
47  return true;
48  }
49  indMotorForm->Destroy();
50  return false;
51 }
52 
53 IndMotorElectricalData IndMotor::GetPUElectricalData(double systemPowerBase)
54 {
55  IndMotorElectricalData data = m_electricalData;
56 
57  switch(data.activePowerUnit) {
58  case UNIT_W: {
59  data.activePower = data.activePower / systemPowerBase;
60  data.activePowerUnit = UNIT_PU;
61  } break;
62  case UNIT_kW: {
63  data.activePower = (data.activePower * 1e3) / systemPowerBase;
64  data.activePowerUnit = UNIT_PU;
65  } break;
66  case UNIT_MW: {
67  data.activePower = (data.activePower * 1e6) / systemPowerBase;
68  data.activePowerUnit = UNIT_PU;
69  } break;
70  default:
71  break;
72  }
73  switch(data.reactivePowerUnit) {
74  case UNIT_VAr: {
75  data.reactivePower = data.reactivePower / systemPowerBase;
76  data.reactivePowerUnit = UNIT_PU;
77  } break;
78  case UNIT_kVAr: {
79  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
80  data.reactivePowerUnit = UNIT_PU;
81  } break;
82  case UNIT_MVAr: {
83  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
84  data.reactivePowerUnit = UNIT_PU;
85  } break;
86  default:
87  break;
88  }
89 
90  return data;
91 }
92 
94 {
95  IndMotor* copy = new IndMotor();
96  *copy = *this;
97  return copy;
98 }
99 
100 wxString IndMotor::GetTipText() const
101 {
102  wxString tipText = m_electricalData.name;
103  tipText += "\n";
104  double activePower = m_electricalData.activePower;
105  if(!m_online) activePower = 0.0;
106  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
107  switch(m_electricalData.activePowerUnit) {
108  case UNIT_PU: {
109  tipText += _(" p.u.");
110  } break;
111  case UNIT_W: {
112  tipText += _(" W");
113  } break;
114  case UNIT_kW: {
115  tipText += _(" kW");
116  } break;
117  case UNIT_MW: {
118  tipText += _(" MW");
119  } break;
120  default:
121  break;
122  }
123  double reactivePower = m_electricalData.reactivePower;
124  if(!m_online) reactivePower = 0.0;
125  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
126  switch(m_electricalData.reactivePowerUnit) {
127  case UNIT_PU: {
128  tipText += _(" p.u.");
129  } break;
130  case UNIT_VAr: {
131  tipText += _(" VAr");
132  } break;
133  case UNIT_kVAr: {
134  tipText += _(" kVAr");
135  } break;
136  case UNIT_MVAr: {
137  tipText += _(" MVAr");
138  } break;
139  default:
140  break;
141  }
142 
143  return tipText;
144 }
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void DrawLine(std::vector< wxPoint2DDouble > points, GLenum mode=GL_LINE_STRIP) const
Draw line.
Definition: Element.cpp:89
@@ -98,12 +98,13 @@ $(document).ready(function(){initNavTree('_ind_motor_8cpp_source.html','');});
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition: Element.cpp:245
+
virtual Element * GetCopy()
Get a the element copy.
Definition: IndMotor.cpp:93
- +
Induction motor power element.
Definition: IndMotor.h:40
- +
Abstract class for rotary machines power elements.
Definition: Machines.h:33
Form to edit the induction motor power data.
Definition: IndMotorForm.h:31
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: IndMotor.cpp:42
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: IndMotor.cpp:35
diff --git a/docs/doxygen/html/_ind_motor_8h.html b/docs/doxygen/html/_ind_motor_8h.html new file mode 100644 index 0000000..eee2bbb --- /dev/null +++ b/docs/doxygen/html/_ind_motor_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/IndMotor.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
IndMotor.h File Reference
+
+
+
#include "Machines.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  IndMotorElectricalData
 
class  IndMotor
 Induction motor power element. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_ind_motor_8h_source.html b/docs/doxygen/html/_ind_motor_8h_source.html index c81f671..cca021d 100644 --- a/docs/doxygen/html/_ind_motor_8h_source.html +++ b/docs/doxygen/html/_ind_motor_8h_source.html @@ -88,20 +88,21 @@ $(document).ready(function(){initNavTree('_ind_motor_8h_source.html','');});
IndMotor.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INDMOTOR_H
19 #define INDMOTOR_H
20 
21 #include "Machines.h"
22 
23 class IndMotorForm;
24 
26  wxString name;
27  double activePower = 100.0;
28  ElectricalUnit activePowerUnit = UNIT_MW;
29  double reactivePower = 0.0;
30  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
31 };
32 
33 class IndMotor : public Machines
34 {
35  public:
36  IndMotor();
37  IndMotor(wxString name);
38  ~IndMotor();
39 
40  virtual Element* GetCopy();
41  virtual void DrawSymbol() const;
42  virtual bool GetContextMenu(wxMenu& menu);
43  virtual wxString GetTipText() const;
44  virtual bool ShowForm(wxWindow* parent, Element* element);
45  virtual IndMotorElectricalData GetElectricalData() { return m_electricalData; }
46  virtual IndMotorElectricalData GetPUElectricalData(double systemPowerBase);
47  virtual void SetElectricalData(IndMotorElectricalData electricalData) { m_electricalData = electricalData; }
48  protected:
49  IndMotorElectricalData m_electricalData;
50 };
51 
52 #endif // INDMOTOR_H
- +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INDMOTOR_H
19 #define INDMOTOR_H
20 
21 #include "Machines.h"
22 
23 class IndMotorForm;
24 
26  wxString name;
27  double activePower = 100.0;
28  ElectricalUnit activePowerUnit = UNIT_MW;
29  double reactivePower = 0.0;
30  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
31 };
32 
40 class IndMotor : public Machines
41 {
42  public:
43  IndMotor();
44  IndMotor(wxString name);
45  ~IndMotor();
46 
47  virtual Element* GetCopy();
48  virtual void DrawSymbol() const;
49  virtual bool GetContextMenu(wxMenu& menu);
50  virtual wxString GetTipText() const;
51  virtual bool ShowForm(wxWindow* parent, Element* element);
52  virtual IndMotorElectricalData GetElectricalData() { return m_electricalData; }
53  virtual IndMotorElectricalData GetPUElectricalData(double systemPowerBase);
54  virtual void SetElectricalData(IndMotorElectricalData electricalData) { m_electricalData = electricalData; }
55  protected:
56  IndMotorElectricalData m_electricalData;
57 };
58 
59 #endif // INDMOTOR_H
+ +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- - +
Induction motor power element.
Definition: IndMotor.h:40
+
Abstract class for rotary machines power elements.
Definition: Machines.h:33
Form to edit the induction motor power data.
Definition: IndMotorForm.h:31
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IndMotorForm.h"
19 #include "IndMotor.h"
20 
21 IndMotorForm::IndMotorForm(wxWindow* parent, IndMotor* indMotor) : IndMotorFormBase(parent)
22 {
23  SetSize(GetBestSize());
24  m_buttonStabButton->Enable(false);
25  IndMotorElectricalData data = indMotor->GetElectricalData();
26 
27  m_textCtrlName->SetValue(data.name);
28 
29  m_textCtrlActivePower->SetValue(IndMotor::StringFromDouble(data.activePower));
30  switch(data.activePowerUnit) {
31  case UNIT_PU: {
32  m_choiceActivePower->SetSelection(0);
33  } break;
34  case UNIT_W: {
35  m_choiceActivePower->SetSelection(1);
36  } break;
37  case UNIT_kW: {
38  m_choiceActivePower->SetSelection(2);
39  } break;
40  case UNIT_MW: {
41  m_choiceActivePower->SetSelection(3);
42  } break;
43  default:
44  break;
45  }
46 
47  m_textCtrlReactivePower->SetValue(IndMotor::StringFromDouble(data.reactivePower));
48  switch(data.reactivePowerUnit) {
49  case UNIT_PU: {
50  m_choiceReactivePower->SetSelection(0);
51  } break;
52  case UNIT_VAr: {
53  m_choiceReactivePower->SetSelection(1);
54  } break;
55  case UNIT_kVAr: {
56  m_choiceReactivePower->SetSelection(2);
57  } break;
58  case UNIT_MVAr: {
59  m_choiceReactivePower->SetSelection(3);
60  } break;
61  default:
62  break;
63  }
64 
65  m_parent = parent;
66  m_indMotor = indMotor;
67 }
68 
69 IndMotorForm::~IndMotorForm() {}
70 void IndMotorForm::OnOKButtonClick(wxCommandEvent& event)
71 {
72  if(ValidateData()) EndModal(wxID_OK);
73 }
74 void IndMotorForm::OnStabilityButtonClick(wxCommandEvent& event)
75 {
76  // TODO: Induction motor stability form
77 }
78 
79 bool IndMotorForm::ValidateData()
80 {
82 
83  data.name = m_textCtrlName->GetValue();
84 
85  if(!m_indMotor->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
86  _("Value entered incorrectly in the field \"Active power\".")))
87  return false;
88  switch(m_choiceActivePower->GetSelection()) {
89  case 0: {
90  data.activePowerUnit = UNIT_PU;
91  } break;
92  case 1: {
93  data.activePowerUnit = UNIT_W;
94  } break;
95  case 2: {
96  data.activePowerUnit = UNIT_kW;
97  } break;
98  case 3: {
99  data.activePowerUnit = UNIT_MW;
100  } break;
101  }
102 
103  if(!m_indMotor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
104  _("Value entered incorrectly in the field \"Reactive power\".")))
105  return false;
106  switch(m_choiceReactivePower->GetSelection()) {
107  case 0: {
108  data.reactivePowerUnit = UNIT_PU;
109  } break;
110  case 1: {
111  data.reactivePowerUnit = UNIT_VAr;
112  } break;
113  case 2: {
114  data.reactivePowerUnit = UNIT_kVAr;
115  } break;
116  case 3: {
117  data.reactivePowerUnit = UNIT_MVAr;
118  } break;
119  }
120 
121  m_indMotor->SetElectricalData(data);
122  return true;
123 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "IndMotorForm.h"
19 #include "IndMotor.h"
20 
21 IndMotorForm::IndMotorForm(wxWindow* parent, IndMotor* indMotor) : IndMotorFormBase(parent)
22 {
23  SetSize(GetBestSize());
24  m_buttonStabButton->Enable(false);
25  IndMotorElectricalData data = indMotor->GetElectricalData();
26 
27  m_textCtrlName->SetValue(data.name);
28 
29  m_textCtrlActivePower->SetValue(IndMotor::StringFromDouble(data.activePower));
30  switch(data.activePowerUnit) {
31  case UNIT_PU: {
32  m_choiceActivePower->SetSelection(0);
33  } break;
34  case UNIT_W: {
35  m_choiceActivePower->SetSelection(1);
36  } break;
37  case UNIT_kW: {
38  m_choiceActivePower->SetSelection(2);
39  } break;
40  case UNIT_MW: {
41  m_choiceActivePower->SetSelection(3);
42  } break;
43  default:
44  break;
45  }
46 
47  m_textCtrlReactivePower->SetValue(IndMotor::StringFromDouble(data.reactivePower));
48  switch(data.reactivePowerUnit) {
49  case UNIT_PU: {
50  m_choiceReactivePower->SetSelection(0);
51  } break;
52  case UNIT_VAr: {
53  m_choiceReactivePower->SetSelection(1);
54  } break;
55  case UNIT_kVAr: {
56  m_choiceReactivePower->SetSelection(2);
57  } break;
58  case UNIT_MVAr: {
59  m_choiceReactivePower->SetSelection(3);
60  } break;
61  default:
62  break;
63  }
64 
65  m_parent = parent;
66  m_indMotor = indMotor;
67 }
68 
69 IndMotorForm::~IndMotorForm() {}
70 void IndMotorForm::OnOKButtonClick(wxCommandEvent& event)
71 {
72  if(ValidateData()) EndModal(wxID_OK);
73 }
74 void IndMotorForm::OnStabilityButtonClick(wxCommandEvent& event)
75 {
76  // TODO: Induction motor stability form
77 }
78 
79 bool IndMotorForm::ValidateData()
80 {
82 
83  data.name = m_textCtrlName->GetValue();
84 
85  if(!m_indMotor->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
86  _("Value entered incorrectly in the field \"Active power\".")))
87  return false;
88  switch(m_choiceActivePower->GetSelection()) {
89  case 0: {
90  data.activePowerUnit = UNIT_PU;
91  } break;
92  case 1: {
93  data.activePowerUnit = UNIT_W;
94  } break;
95  case 2: {
96  data.activePowerUnit = UNIT_kW;
97  } break;
98  case 3: {
99  data.activePowerUnit = UNIT_MW;
100  } break;
101  }
102 
103  if(!m_indMotor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
104  _("Value entered incorrectly in the field \"Reactive power\".")))
105  return false;
106  switch(m_choiceReactivePower->GetSelection()) {
107  case 0: {
108  data.reactivePowerUnit = UNIT_PU;
109  } break;
110  case 1: {
111  data.reactivePowerUnit = UNIT_VAr;
112  } break;
113  case 2: {
114  data.reactivePowerUnit = UNIT_kVAr;
115  } break;
116  case 3: {
117  data.reactivePowerUnit = UNIT_MVAr;
118  } break;
119  }
120 
121  m_indMotor->SetElectricalData(data);
122  return true;
123 }
+ - +
Induction motor power element.
Definition: IndMotor.h:40
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
diff --git a/docs/doxygen/html/_ind_motor_form_8h_source.html b/docs/doxygen/html/_ind_motor_form_8h_source.html index 526fa6a..be88cab 100644 --- a/docs/doxygen/html/_ind_motor_form_8h_source.html +++ b/docs/doxygen/html/_ind_motor_form_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_ind_motor_form_8h_source.html','');})
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INDMOTORFORM_H
19 #define INDMOTORFORM_H
20 #include "ElementForm.h"
21 
22 class IndMotor;
23 
32 {
33  public:
34  IndMotorForm(wxWindow* parent, IndMotor* indMotor);
35  virtual ~IndMotorForm();
36  virtual bool ValidateData();
37 
38  protected:
39  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); };
40  virtual void OnOKButtonClick(wxCommandEvent& event);
41  virtual void OnStabilityButtonClick(wxCommandEvent& event);
42 
43  wxWindow* m_parent = NULL;
44  IndMotor* m_indMotor = NULL;
45 };
46 #endif // INDMOTORFORM_H
- +
Induction motor power element.
Definition: IndMotor.h:40
Form to edit the induction motor power data.
Definition: IndMotorForm.h:31
diff --git a/docs/doxygen/html/_inductor_8cpp_source.html b/docs/doxygen/html/_inductor_8cpp_source.html index 9977b24..ec93e1b 100644 --- a/docs/doxygen/html/_inductor_8cpp_source.html +++ b/docs/doxygen/html/_inductor_8cpp_source.html @@ -88,9 +88,9 @@ $(document).ready(function(){initNavTree('_inductor_8cpp_source.html','');});
Inductor.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "Inductor.h"
20 
21 Inductor::Inductor() : Shunt() {}
22 Inductor::Inductor(wxString name) : Shunt() { m_electricalData.name = name; }
23 Inductor::~Inductor() {}
24 bool Inductor::AddParent(Element* parent, wxPoint2DDouble position)
25 {
26  if(parent) {
27  m_parentList.push_back(parent);
28  parent->AddChild(this);
29  wxPoint2DDouble parentPt =
30  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
31  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
32  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
33 
34  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
35  m_width = 20.0;
36  m_height = 70.0;
37  m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
43 
44  m_inserted = true;
45 
46  wxRect2DDouble genRect(0, 0, 0, 0);
47  m_switchRect.push_back(genRect); // Push a general rectangle.
48  UpdateSwitches();
49 
50  return true;
51  }
52  return false;
53 }
54 
55 void Inductor::Draw(wxPoint2DDouble translation, double scale) const
56 {
57  OpenGLColour elementColour;
58  if(m_online) {
59  if(m_dynEvent)
60  elementColour = m_dynamicEventColour;
61  else
62  elementColour = m_onlineElementColour;
63  } else
64  elementColour = m_offlineElementColour;
65 
66  if(m_inserted) {
67  if(m_selected) {
68  glLineWidth(1.5 + m_borderSize * 2.0);
69  glColor4dv(m_selectionColour.GetRGBA());
70 
71  DrawLine(m_pointList);
72 
73  glPushMatrix();
74  glTranslated(m_position.m_x, m_position.m_y, 0.0);
75  glRotated(m_angle, 0.0, 0.0, 1.0);
76  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
77 
78  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 30, GL_LINE_STRIP);
79  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 30, GL_LINE_STRIP);
80  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 30, GL_LINE_STRIP);
81 
82  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
83 
84  glPopMatrix();
85 
86  // Draw node selection.
87  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
88  }
89  // Draw Load (layer 2).
90  glLineWidth(1.5);
91  glColor4dv(elementColour.GetRGBA());
92  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
93  DrawLine(m_pointList);
94 
95  DrawSwitches();
96 
97  glPushMatrix();
98  glTranslated(m_position.m_x, m_position.m_y, 0.0);
99  glRotated(m_angle, 0.0, 0.0, 1.0);
100  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
101 
102  glColor4dv(elementColour.GetRGBA());
103  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 10, GL_LINE_STRIP);
104  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 10, GL_LINE_STRIP);
105  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 10, GL_LINE_STRIP);
106 
107  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
108 
109  glPopMatrix();
110  }
111 }
112 
113 void Inductor::Rotate(bool clockwise)
114 {
115  double rotAngle = m_rotationAngle;
116  if(!clockwise) rotAngle = -m_rotationAngle;
117 
118  m_angle += rotAngle;
119  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
120  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
121  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
122  UpdateSwitchesPosition();
123 }
124 
125 bool Inductor::GetContextMenu(wxMenu& menu)
126 {
127  menu.Append(ID_EDIT_ELEMENT, _("Edit Inductor"));
128  GeneralMenuItens(menu);
129  return true;
130 }
131 
132 bool Inductor::Contains(wxPoint2DDouble position) const
133 {
134  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
135  return m_rect.Contains(ptR);
136 }
137 
138 bool Inductor::Intersects(wxRect2DDouble rect) const { return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0); }
139 bool Inductor::ShowForm(wxWindow* parent, Element* element)
140 {
141  ReactiveShuntElementForm* capacitorForm = new ReactiveShuntElementForm(parent, this);
142  capacitorForm->SetTitle(_("Inductor"));
143  if(capacitorForm->ShowModal() == wxID_OK) {
144  capacitorForm->Destroy();
145  return true;
146  }
147  capacitorForm->Destroy();
148  return false;
149 }
150 
151 InductorElectricalData Inductor::GetPUElectricalData(double systemPowerBase)
152 {
153  InductorElectricalData data = m_electricalData;
154  switch(data.reactivePowerUnit) {
155  case UNIT_VAr: {
156  data.reactivePower = data.reactivePower / systemPowerBase;
157  data.reactivePowerUnit = UNIT_PU;
158  } break;
159  case UNIT_kVAr: {
160  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
161  data.reactivePowerUnit = UNIT_PU;
162  } break;
163  case UNIT_MVAr: {
164  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
165  data.reactivePowerUnit = UNIT_PU;
166  } break;
167  default:
168  break;
169  }
170 
171  return data;
172 }
173 
175 {
176  Inductor* copy = new Inductor();
177  *copy = *this;
178  return copy;
179 }
180 
181 wxString Inductor::GetTipText() const
182 {
183  wxString tipText = m_electricalData.name;
184 
185  // TODO: Avoid reactive power calculation.
186  double reactivePower = m_electricalData.reactivePower;
187  if(!m_online)
188  reactivePower = 0.0;
189  else {
190  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
191  reactivePower *= std::pow(std::abs(v), 2);
192  }
193  tipText += "\n";
194  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
195  switch(m_electricalData.reactivePowerUnit) {
196  case UNIT_PU: {
197  tipText += _(" p.u.");
198  } break;
199  case UNIT_VAr: {
200  tipText += _(" VAr");
201  } break;
202  case UNIT_kVAr: {
203  tipText += _(" kVAr");
204  } break;
205  case UNIT_MVAr: {
206  tipText += _(" MVAr");
207  } break;
208  default:
209  break;
210  }
211 
212  return tipText;
213 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "Inductor.h"
20 
21 Inductor::Inductor() : Shunt() {}
22 Inductor::Inductor(wxString name) : Shunt() { m_electricalData.name = name; }
23 Inductor::~Inductor() {}
24 bool Inductor::AddParent(Element* parent, wxPoint2DDouble position)
25 {
26  if(parent) {
27  m_parentList.push_back(parent);
28  parent->AddChild(this);
29  wxPoint2DDouble parentPt =
30  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
31  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
32  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
33 
34  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
35  m_width = 20.0;
36  m_height = 70.0;
37  m_rect = wxRect2DDouble(m_position.m_x - m_width / 2.0, m_position.m_y - m_height / 2.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0 - 10.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -m_height / 2.0));
43 
44  m_inserted = true;
45 
46  wxRect2DDouble genRect(0, 0, 0, 0);
47  m_switchRect.push_back(genRect); // Push a general rectangle.
48  UpdateSwitches();
49 
50  return true;
51  }
52  return false;
53 }
54 
55 void Inductor::Draw(wxPoint2DDouble translation, double scale) const
56 {
57  OpenGLColour elementColour;
58  if(m_online) {
59  if(m_dynEvent)
60  elementColour = m_dynamicEventColour;
61  else
62  elementColour = m_onlineElementColour;
63  } else
64  elementColour = m_offlineElementColour;
65 
66  if(m_inserted) {
67  if(m_selected) {
68  glLineWidth(1.5 + m_borderSize * 2.0);
69  glColor4dv(m_selectionColour.GetRGBA());
70 
71  DrawLine(m_pointList);
72 
73  glPushMatrix();
74  glTranslated(m_position.m_x, m_position.m_y, 0.0);
75  glRotated(m_angle, 0.0, 0.0, 1.0);
76  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
77 
78  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 30, GL_LINE_STRIP);
79  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 30, GL_LINE_STRIP);
80  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 30, GL_LINE_STRIP);
81 
82  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
83 
84  glPopMatrix();
85 
86  // Draw node selection.
87  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
88  }
89  // Draw Load (layer 2).
90  glLineWidth(1.5);
91  glColor4dv(elementColour.GetRGBA());
92  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
93  DrawLine(m_pointList);
94 
95  DrawSwitches();
96 
97  glPushMatrix();
98  glTranslated(m_position.m_x, m_position.m_y, 0.0);
99  glRotated(m_angle, 0.0, 0.0, 1.0);
100  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
101 
102  glColor4dv(elementColour.GetRGBA());
103  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 10.0), 10, 45, 270, 10, GL_LINE_STRIP);
104  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 25.0), 10, 45, 315, 10, GL_LINE_STRIP);
105  DrawArc(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 40.0), 10, 90, 315, 10, GL_LINE_STRIP);
106 
107  DrawGround(m_position + wxPoint2DDouble(0, -m_height / 2.0 + 50.0));
108 
109  glPopMatrix();
110  }
111 }
112 
113 void Inductor::Rotate(bool clockwise)
114 {
115  double rotAngle = m_rotationAngle;
116  if(!clockwise) rotAngle = -m_rotationAngle;
117 
118  m_angle += rotAngle;
119  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
120  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
121  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
122  UpdateSwitchesPosition();
123 }
124 
125 bool Inductor::GetContextMenu(wxMenu& menu)
126 {
127  menu.Append(ID_EDIT_ELEMENT, _("Edit Inductor"));
128  GeneralMenuItens(menu);
129  return true;
130 }
131 
132 bool Inductor::Contains(wxPoint2DDouble position) const
133 {
134  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
135  return m_rect.Contains(ptR);
136 }
137 
138 bool Inductor::Intersects(wxRect2DDouble rect) const { return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0); }
139 bool Inductor::ShowForm(wxWindow* parent, Element* element)
140 {
141  ReactiveShuntElementForm* capacitorForm = new ReactiveShuntElementForm(parent, this);
142  capacitorForm->SetTitle(_("Inductor"));
143  if(capacitorForm->ShowModal() == wxID_OK) {
144  capacitorForm->Destroy();
145  return true;
146  }
147  capacitorForm->Destroy();
148  return false;
149 }
150 
151 InductorElectricalData Inductor::GetPUElectricalData(double systemPowerBase)
152 {
153  InductorElectricalData data = m_electricalData;
154  switch(data.reactivePowerUnit) {
155  case UNIT_VAr: {
156  data.reactivePower = data.reactivePower / systemPowerBase;
157  data.reactivePowerUnit = UNIT_PU;
158  } break;
159  case UNIT_kVAr: {
160  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
161  data.reactivePowerUnit = UNIT_PU;
162  } break;
163  case UNIT_MVAr: {
164  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
165  data.reactivePowerUnit = UNIT_PU;
166  } break;
167  default:
168  break;
169  }
170 
171  return data;
172 }
173 
175 {
176  Inductor* copy = new Inductor();
177  *copy = *this;
178  return copy;
179 }
180 
181 wxString Inductor::GetTipText() const
182 {
183  wxString tipText = m_electricalData.name;
184 
185  // TODO: Avoid reactive power calculation.
186  double reactivePower = m_electricalData.reactivePower;
187  if(!m_online)
188  reactivePower = 0.0;
189  else {
190  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
191  reactivePower *= std::pow(std::abs(v), 2);
192  }
193  tipText += "\n";
194  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
195  switch(m_electricalData.reactivePowerUnit) {
196  case UNIT_PU: {
197  tipText += _(" p.u.");
198  } break;
199  case UNIT_VAr: {
200  tipText += _(" VAr");
201  } break;
202  case UNIT_kVAr: {
203  tipText += _(" kVAr");
204  } break;
205  case UNIT_MVAr: {
206  tipText += _(" MVAr");
207  } break;
208  default:
209  break;
210  }
211 
212  return tipText;
213 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Inductor.cpp:139
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual wxString GetTipText() const
Get the tip text.
Definition: Inductor.cpp:181
@@ -102,17 +102,18 @@ $(document).ready(function(){initNavTree('_inductor_8cpp_source.html','');});
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Inductor.cpp:125
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Inductor.cpp:55
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Inductor.cpp:24
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
- +
Class to manage color of OpenGL.
Definition: Element.h:67
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Inductor.cpp:138
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
- -
Definition: Shunt.h:24
+
Inductor shunt power element.
Definition: Inductor.h:38
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
Form to edit the reactive shunt element power data.
const GLdouble * GetRGBA() const
Get colour in RGBA.
Definition: Element.h:101
diff --git a/docs/doxygen/html/_inductor_8h.html b/docs/doxygen/html/_inductor_8h.html new file mode 100644 index 0000000..6328d39 --- /dev/null +++ b/docs/doxygen/html/_inductor_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/Inductor.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Inductor.h File Reference
+
+
+
#include "Shunt.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  InductorElectricalData
 
class  Inductor
 Inductor shunt power element. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_inductor_8h_source.html b/docs/doxygen/html/_inductor_8h_source.html index 6c82c0b..d663b20 100644 --- a/docs/doxygen/html/_inductor_8h_source.html +++ b/docs/doxygen/html/_inductor_8h_source.html @@ -88,19 +88,20 @@ $(document).ready(function(){initNavTree('_inductor_8h_source.html','');});
Inductor.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INDUCTOR_H
19 #define INDUCTOR_H
20 
21 #include "Shunt.h"
22 
24 
26  wxString name;
27  double reactivePower = 100.0;
28  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
29 };
30 
31 class Inductor : public Shunt
32 {
33  public:
34  Inductor();
35  Inductor(wxString name);
36  ~Inductor();
37 
38  virtual Element* GetCopy();
39  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
40  virtual void Draw(wxPoint2DDouble translation, double scale) const;
41  virtual bool Contains(wxPoint2DDouble position) const;
42  virtual bool Intersects(wxRect2DDouble rect) const;
43  virtual void Rotate(bool clockwise = true);
44  virtual bool GetContextMenu(wxMenu& menu);
45  virtual wxString GetTipText() const;
46  virtual bool ShowForm(wxWindow* parent, Element* element);
47  virtual InductorElectricalData GetElectricalData() { return m_electricalData; }
48  virtual InductorElectricalData GetPUElectricalData(double systemPowerBase);
49  virtual void SetElectricalData(InductorElectricalData electricalData) { m_electricalData = electricalData; }
50  protected:
51  InductorElectricalData m_electricalData;
52 };
53 
54 #endif // INDUCTOR_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INDUCTOR_H
19 #define INDUCTOR_H
20 
21 #include "Shunt.h"
22 
24 
26  wxString name;
27  double reactivePower = 100.0;
28  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
29 };
30 
38 class Inductor : public Shunt
39 {
40  public:
41  Inductor();
42  Inductor(wxString name);
43  ~Inductor();
44 
45  virtual Element* GetCopy();
46  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
47  virtual void Draw(wxPoint2DDouble translation, double scale) const;
48  virtual bool Contains(wxPoint2DDouble position) const;
49  virtual bool Intersects(wxRect2DDouble rect) const;
50  virtual void Rotate(bool clockwise = true);
51  virtual bool GetContextMenu(wxMenu& menu);
52  virtual wxString GetTipText() const;
53  virtual bool ShowForm(wxWindow* parent, Element* element);
54  virtual InductorElectricalData GetElectricalData() { return m_electricalData; }
55  virtual InductorElectricalData GetPUElectricalData(double systemPowerBase);
56  virtual void SetElectricalData(InductorElectricalData electricalData) { m_electricalData = electricalData; }
57  protected:
58  InductorElectricalData m_electricalData;
59 };
60 
61 #endif // INDUCTOR_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- -
Definition: Shunt.h:24
+
Inductor shunt power element.
Definition: Inductor.h:38
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
Form to edit the reactive shunt element power data.
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "LineForm.h"
19 #include "SwitchingForm.h"
20 #include "Line.h"
21 
22 LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent)
23 {
24  SetSize(GetBestSize());
25  m_choiceResistance->SetString(1, L'\u03A9');
26  m_choiceResistance->SetString(2, (wxString)L'\u03A9' + "/km");
27  m_choiceResistance->SetInitialSize();
28  m_textCtrlResistance->SetInitialSize();
29 
30  m_choiceReactance->SetString(1, L'\u03A9');
31  m_choiceReactance->SetString(2, (wxString)L'\u03A9' + "/km");
32  m_choiceReactance->SetInitialSize();
33  m_textCtrlReactance->SetInitialSize();
34 
35  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
36  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
37  ReplaceStaticTextLabelChar(m_staticTextZeroSusceptance, L'\u2080');
38 
39  SetSize(GetBestSize());
40  Layout();
41  m_parent = parent;
42  m_line = line;
43 
44  LineElectricalData data = line->GetElectricalData();
45 
46  m_textCtrlName->SetValue(data.name);
47 
48  wxString nominalVoltageStr = Line::StringFromDouble(data.nominalVoltage);
49  switch(data.nominalVoltageUnit) {
50  case UNIT_V: {
51  nominalVoltageStr += " V";
52  } break;
53  case UNIT_kV: {
54  nominalVoltageStr += " kV";
55  } break;
56  default:
57  break;
58  }
59  m_staticTextNominalVoltageValue->SetLabel(nominalVoltageStr);
60 
61  m_textCtrlNominalPower->SetValue(Line::StringFromDouble(data.nominalPower));
62  switch(data.nominalPowerUnit) {
63  case UNIT_VA: {
64  m_choiceNominalPower->SetSelection(0);
65  } break;
66  case UNIT_kVA: {
67  m_choiceNominalPower->SetSelection(1);
68  } break;
69  case UNIT_MVA: {
70  m_choiceNominalPower->SetSelection(2);
71  } break;
72  default:
73  break;
74  }
75 
76  m_textCtrlResistance->SetValue(Line::StringFromDouble(data.resistance));
77  switch(data.resistanceUnit) {
78  case UNIT_PU: {
79  m_choiceResistance->SetSelection(0);
80  } break;
81  case UNIT_OHM: {
82  m_choiceResistance->SetSelection(1);
83  } break;
84  case UNIT_OHM_km: {
85  m_choiceResistance->SetSelection(2);
86  } break;
87  default:
88  break;
89  }
90 
91  m_textCtrlReactance->SetValue(Line::StringFromDouble(data.indReactance));
92  switch(data.indReactanceUnit) {
93  case UNIT_PU: {
94  m_choiceReactance->SetSelection(0);
95  } break;
96  case UNIT_OHM: {
97  m_choiceReactance->SetSelection(1);
98  } break;
99  case UNIT_OHM_km: {
100  m_choiceReactance->SetSelection(2);
101  } break;
102  default:
103  break;
104  }
105 
106  m_textCtrlSusceptance->SetValue(Line::StringFromDouble(data.capSusceptance));
107  switch(data.capSusceptanceUnit) {
108  case UNIT_PU: {
109  m_choiceSusceptance->SetSelection(0);
110  } break;
111  case UNIT_S: {
112  m_choiceSusceptance->SetSelection(1);
113  } break;
114  case UNIT_S_km: {
115  m_choiceSusceptance->SetSelection(2);
116  } break;
117  default:
118  break;
119  }
120 
121  m_textCtrlLineSize->SetValue(Line::StringFromDouble(data.lineSize));
122  m_checkUseLinePower->SetValue(data.useLinePower);
123 
124  m_textCtrlZeroResistance->SetValue(Line::StringFromDouble(data.zeroResistance));
125  m_textCtrlZeroReactance->SetValue(Line::StringFromDouble(data.zeroIndReactance));
126  m_textCtrlZeroSusceptance->SetValue(Line::StringFromDouble(data.zeroCapSusceptance));
127 }
128 
129 LineForm::~LineForm() {}
130 void LineForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
131 void LineForm::OnOKButtonClick(wxCommandEvent& event)
132 {
133  if(ValidateData()) EndModal(wxID_OK);
134 }
135 
136 void LineForm::OnStabilityButtonClick(wxCommandEvent& event)
137 {
138  if(ValidateData()) {
139  SwitchingForm swForm(m_parent, m_line);
140  swForm.SetTitle(_("Line: Switching"));
141  swForm.ShowModal();
142  EndModal(wxID_OK);
143  }
144 }
145 
146 void LineForm::ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar)
147 {
148  wxString label = staticText->GetLabel();
149  label[label.length() - 2] = newChar;
150  staticText->SetLabel(label);
151 }
152 
153 bool LineForm::ValidateData()
154 {
155  LineElectricalData data = m_line->GetElectricalData();
156 
157  data.name = m_textCtrlName->GetValue();
158 
159  if(!m_line->DoubleFromString(m_parent, m_textCtrlNominalPower->GetValue(), data.nominalPower,
160  _("Value entered incorrectly in the field \"Nominal power\".")))
161  return false;
162  switch(m_choiceNominalPower->GetSelection()) {
163  case 0: {
164  data.nominalPowerUnit = UNIT_VA;
165  } break;
166  case 1: {
167  data.nominalPowerUnit = UNIT_kVA;
168  } break;
169  case 2: {
170  data.nominalPowerUnit = UNIT_MVA;
171  } break;
172  }
173 
174  if(!m_line->DoubleFromString(m_parent, m_textCtrlResistance->GetValue(), data.resistance,
175  _("Value entered incorrectly in the field \"Resistance\".")))
176  return false;
177  switch(m_choiceResistance->GetSelection()) {
178  case 0: {
179  data.resistanceUnit = UNIT_PU;
180  } break;
181  case 1: {
182  data.resistanceUnit = UNIT_OHM;
183  } break;
184  case 2: {
185  data.resistanceUnit = UNIT_OHM_km;
186  } break;
187  }
188 
189  if(!m_line->DoubleFromString(m_parent, m_textCtrlReactance->GetValue(), data.indReactance,
190  _("Value entered incorrectly in the field \"Indutive Reactance\".")))
191  return false;
192  switch(m_choiceReactance->GetSelection()) {
193  case 0: {
194  data.indReactanceUnit = UNIT_PU;
195  } break;
196  case 1: {
197  data.indReactanceUnit = UNIT_OHM;
198  } break;
199  case 2: {
200  data.indReactanceUnit = UNIT_OHM_km;
201  } break;
202  }
203 
204  if(!m_line->DoubleFromString(m_parent, m_textCtrlSusceptance->GetValue(), data.capSusceptance,
205  _("Value entered incorrectly in the field \"Capacitive Susceptance\".")))
206  return false;
207  switch(m_choiceSusceptance->GetSelection()) {
208  case 0: {
209  data.capSusceptanceUnit = UNIT_PU;
210  } break;
211  case 1: {
212  data.capSusceptanceUnit = UNIT_S;
213  } break;
214  case 2: {
215  data.capSusceptanceUnit = UNIT_S_km;
216  } break;
217  }
218 
219  if(!m_line->DoubleFromString(m_parent, m_textCtrlLineSize->GetValue(), data.lineSize,
220  _("Value entered incorrectly in the field \"Line size\".")))
221  return false;
222 
223  data.useLinePower = m_checkUseLinePower->GetValue();
224 
225  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
226  _("Value entered incorrectly in the field \"Zero-sequence resistance\".")))
227  return false;
228  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroIndReactance,
229  _("Value entered incorrectly in the field \"Zero-sequence indutive reactance\".")))
230  return false;
231  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroSusceptance->GetValue(), data.zeroCapSusceptance,
232  _("Value entered incorrectly in the field \"Zero-sequence capacitive susceptance\".")))
233  return false;
234 
235  m_line->SetElectricalData(data);
236 
237  return true;
238 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "LineForm.h"
19 #include "SwitchingForm.h"
20 #include "Line.h"
21 
22 LineForm::LineForm(wxWindow* parent, Line* line) : LineFormBase(parent)
23 {
24  SetSize(GetBestSize());
25  m_choiceResistance->SetString(1, L'\u03A9');
26  m_choiceResistance->SetString(2, (wxString)L'\u03A9' + "/km");
27  m_choiceResistance->SetInitialSize();
28  m_textCtrlResistance->SetInitialSize();
29 
30  m_choiceReactance->SetString(1, L'\u03A9');
31  m_choiceReactance->SetString(2, (wxString)L'\u03A9' + "/km");
32  m_choiceReactance->SetInitialSize();
33  m_textCtrlReactance->SetInitialSize();
34 
35  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
36  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
37  ReplaceStaticTextLabelChar(m_staticTextZeroSusceptance, L'\u2080');
38 
39  SetSize(GetBestSize());
40  Layout();
41  m_parent = parent;
42  m_line = line;
43 
44  LineElectricalData data = line->GetElectricalData();
45 
46  m_textCtrlName->SetValue(data.name);
47 
48  wxString nominalVoltageStr = Line::StringFromDouble(data.nominalVoltage);
49  switch(data.nominalVoltageUnit) {
50  case UNIT_V: {
51  nominalVoltageStr += " V";
52  } break;
53  case UNIT_kV: {
54  nominalVoltageStr += " kV";
55  } break;
56  default:
57  break;
58  }
59  m_staticTextNominalVoltageValue->SetLabel(nominalVoltageStr);
60 
61  m_textCtrlNominalPower->SetValue(Line::StringFromDouble(data.nominalPower));
62  switch(data.nominalPowerUnit) {
63  case UNIT_VA: {
64  m_choiceNominalPower->SetSelection(0);
65  } break;
66  case UNIT_kVA: {
67  m_choiceNominalPower->SetSelection(1);
68  } break;
69  case UNIT_MVA: {
70  m_choiceNominalPower->SetSelection(2);
71  } break;
72  default:
73  break;
74  }
75 
76  m_textCtrlResistance->SetValue(Line::StringFromDouble(data.resistance));
77  switch(data.resistanceUnit) {
78  case UNIT_PU: {
79  m_choiceResistance->SetSelection(0);
80  } break;
81  case UNIT_OHM: {
82  m_choiceResistance->SetSelection(1);
83  } break;
84  case UNIT_OHM_km: {
85  m_choiceResistance->SetSelection(2);
86  } break;
87  default:
88  break;
89  }
90 
91  m_textCtrlReactance->SetValue(Line::StringFromDouble(data.indReactance));
92  switch(data.indReactanceUnit) {
93  case UNIT_PU: {
94  m_choiceReactance->SetSelection(0);
95  } break;
96  case UNIT_OHM: {
97  m_choiceReactance->SetSelection(1);
98  } break;
99  case UNIT_OHM_km: {
100  m_choiceReactance->SetSelection(2);
101  } break;
102  default:
103  break;
104  }
105 
106  m_textCtrlSusceptance->SetValue(Line::StringFromDouble(data.capSusceptance));
107  switch(data.capSusceptanceUnit) {
108  case UNIT_PU: {
109  m_choiceSusceptance->SetSelection(0);
110  } break;
111  case UNIT_S: {
112  m_choiceSusceptance->SetSelection(1);
113  } break;
114  case UNIT_S_km: {
115  m_choiceSusceptance->SetSelection(2);
116  } break;
117  default:
118  break;
119  }
120 
121  m_textCtrlLineSize->SetValue(Line::StringFromDouble(data.lineSize));
122  m_checkUseLinePower->SetValue(data.useLinePower);
123 
124  m_textCtrlZeroResistance->SetValue(Line::StringFromDouble(data.zeroResistance));
125  m_textCtrlZeroReactance->SetValue(Line::StringFromDouble(data.zeroIndReactance));
126  m_textCtrlZeroSusceptance->SetValue(Line::StringFromDouble(data.zeroCapSusceptance));
127 }
128 
129 LineForm::~LineForm() {}
130 void LineForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
131 void LineForm::OnOKButtonClick(wxCommandEvent& event)
132 {
133  if(ValidateData()) EndModal(wxID_OK);
134 }
135 
136 void LineForm::OnStabilityButtonClick(wxCommandEvent& event)
137 {
138  if(ValidateData()) {
139  SwitchingForm swForm(m_parent, m_line);
140  swForm.SetTitle(_("Line: Switching"));
141  swForm.ShowModal();
142  EndModal(wxID_OK);
143  }
144 }
145 
146 void LineForm::ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar)
147 {
148  wxString label = staticText->GetLabel();
149  label[label.length() - 2] = newChar;
150  staticText->SetLabel(label);
151 }
152 
153 bool LineForm::ValidateData()
154 {
155  LineElectricalData data = m_line->GetElectricalData();
156 
157  data.name = m_textCtrlName->GetValue();
158 
159  if(!m_line->DoubleFromString(m_parent, m_textCtrlNominalPower->GetValue(), data.nominalPower,
160  _("Value entered incorrectly in the field \"Nominal power\".")))
161  return false;
162  switch(m_choiceNominalPower->GetSelection()) {
163  case 0: {
164  data.nominalPowerUnit = UNIT_VA;
165  } break;
166  case 1: {
167  data.nominalPowerUnit = UNIT_kVA;
168  } break;
169  case 2: {
170  data.nominalPowerUnit = UNIT_MVA;
171  } break;
172  }
173 
174  if(!m_line->DoubleFromString(m_parent, m_textCtrlResistance->GetValue(), data.resistance,
175  _("Value entered incorrectly in the field \"Resistance\".")))
176  return false;
177  switch(m_choiceResistance->GetSelection()) {
178  case 0: {
179  data.resistanceUnit = UNIT_PU;
180  } break;
181  case 1: {
182  data.resistanceUnit = UNIT_OHM;
183  } break;
184  case 2: {
185  data.resistanceUnit = UNIT_OHM_km;
186  } break;
187  }
188 
189  if(!m_line->DoubleFromString(m_parent, m_textCtrlReactance->GetValue(), data.indReactance,
190  _("Value entered incorrectly in the field \"Indutive Reactance\".")))
191  return false;
192  switch(m_choiceReactance->GetSelection()) {
193  case 0: {
194  data.indReactanceUnit = UNIT_PU;
195  } break;
196  case 1: {
197  data.indReactanceUnit = UNIT_OHM;
198  } break;
199  case 2: {
200  data.indReactanceUnit = UNIT_OHM_km;
201  } break;
202  }
203 
204  if(!m_line->DoubleFromString(m_parent, m_textCtrlSusceptance->GetValue(), data.capSusceptance,
205  _("Value entered incorrectly in the field \"Capacitive Susceptance\".")))
206  return false;
207  switch(m_choiceSusceptance->GetSelection()) {
208  case 0: {
209  data.capSusceptanceUnit = UNIT_PU;
210  } break;
211  case 1: {
212  data.capSusceptanceUnit = UNIT_S;
213  } break;
214  case 2: {
215  data.capSusceptanceUnit = UNIT_S_km;
216  } break;
217  }
218 
219  if(!m_line->DoubleFromString(m_parent, m_textCtrlLineSize->GetValue(), data.lineSize,
220  _("Value entered incorrectly in the field \"Line size\".")))
221  return false;
222 
223  data.useLinePower = m_checkUseLinePower->GetValue();
224 
225  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
226  _("Value entered incorrectly in the field \"Zero-sequence resistance\".")))
227  return false;
228  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroIndReactance,
229  _("Value entered incorrectly in the field \"Zero-sequence indutive reactance\".")))
230  return false;
231  if(!m_line->DoubleFromString(m_parent, m_textCtrlZeroSusceptance->GetValue(), data.zeroCapSusceptance,
232  _("Value entered incorrectly in the field \"Zero-sequence capacitive susceptance\".")))
233  return false;
234 
235  m_line->SetElectricalData(data);
236 
237  return true;
238 }
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
+ -
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
diff --git a/docs/doxygen/html/_line_form_8h_source.html b/docs/doxygen/html/_line_form_8h_source.html index df9f02e..911327d 100644 --- a/docs/doxygen/html/_line_form_8h_source.html +++ b/docs/doxygen/html/_line_form_8h_source.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_line_form_8h_source.html','');}); Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef LINEFORM_H
19 #define LINEFORM_H
20 #include "ElementForm.h"
21 
22 class Line;
23 class SwitchingForm;
24 
32 class LineForm : public LineFormBase
33 {
34  public:
35  LineForm(wxWindow* parent, Line* line);
36  virtual ~LineForm();
37 
38  protected:
39  virtual void OnCancelButtonClick(wxCommandEvent& event);
40  virtual void OnOKButtonClick(wxCommandEvent& event);
41  virtual void OnStabilityButtonClick(wxCommandEvent& event);
42  virtual void ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar);
43  virtual bool ValidateData();
44 
45  wxWindow* m_parent = NULL;
46  Line* m_line = NULL;
47 };
48 #endif // LINEFORM_H
Form to edit the line power data.
Definition: LineForm.h:32
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
-
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
diff --git a/docs/doxygen/html/_load_8cpp_source.html b/docs/doxygen/html/_load_8cpp_source.html index 9b7b909..0dd68df 100644 --- a/docs/doxygen/html/_load_8cpp_source.html +++ b/docs/doxygen/html/_load_8cpp_source.html @@ -88,8 +88,8 @@ $(document).ready(function(){initNavTree('_load_8cpp_source.html','');});
Load.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Load.h"
19 
20 Load::Load() : Shunt() {}
21 Load::Load(wxString name) : Shunt() { m_electricalData.name = name; }
22 Load::~Load() {}
23 bool Load::AddParent(Element* parent, wxPoint2DDouble position)
24 {
25  if(parent) {
26  m_parentList.push_back(parent);
27  parent->AddChild(this);
28  wxPoint2DDouble parentPt =
29  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
30  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
31  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
32 
33  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
34  m_width = m_height = 20.0;
35  m_rect = wxRect2DDouble(m_position.m_x - 10.0, m_position.m_y - 10.0, m_width, m_height);
36 
37  m_pointList.push_back(parentPt);
38  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
39  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -20.0));
40  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -10.0));
41 
42  m_triangPts.push_back(wxPoint2DDouble(-m_width / 2.0, -m_height / 2.0));
43  m_triangPts.push_back(wxPoint2DDouble(m_width / 2.0, -m_height / 2.0));
44  m_triangPts.push_back(wxPoint2DDouble(0.0, m_height / 2.0));
45 
46  m_inserted = true;
47 
48  wxRect2DDouble genRect(0, 0, 0, 0);
49  m_switchRect.push_back(genRect); // Push a general rectangle.
50  UpdateSwitches();
51  m_pfDirection = PF_TO_ELEMENT;
52  UpdatePowerFlowArrowsPosition();
53 
54  return true;
55  }
56  return false;
57 }
58 
59 void Load::Draw(wxPoint2DDouble translation, double scale) const
60 {
61  OpenGLColour elementColour;
62  if(m_online) {
63  if(m_dynEvent)
64  elementColour = m_dynamicEventColour;
65  else
66  elementColour = m_onlineElementColour;
67  } else
68  elementColour = m_offlineElementColour;
69 
70  if(m_inserted) {
71  // Draw Selection (layer 1).
72  if(m_selected) {
73  glLineWidth(1.5 + m_borderSize * 2.0);
74  glColor4dv(m_selectionColour.GetRGBA());
75  std::vector<wxPoint2DDouble> selTriangPts;
76  selTriangPts.push_back(m_triangPts[0] + m_position +
77  wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale));
78  selTriangPts.push_back(m_triangPts[1] + m_position +
79  wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale));
80  selTriangPts.push_back(m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale));
81 
82  glPushMatrix();
83  glTranslated(m_position.m_x, m_position.m_y, 0.0);
84  glRotated(m_angle, 0.0, 0.0, 1.0);
85  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
86  DrawTriangle(selTriangPts);
87  glPopMatrix();
88 
89  DrawLine(m_pointList);
90 
91  // Draw node selection.
92  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
93  }
94 
95  // Draw Load (layer 2).
96  glLineWidth(1.5);
97 
98  // Draw node.
99  glColor4dv(elementColour.GetRGBA());
100  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
101 
102  DrawLine(m_pointList);
103 
104  DrawSwitches();
105  DrawPowerFlowPts();
106 
107  std::vector<wxPoint2DDouble> triangPts;
108  for(int i = 0; i < 3; i++) {
109  triangPts.push_back(m_triangPts[i] + m_position);
110  }
111  glPushMatrix();
112  glTranslated(m_position.m_x, m_position.m_y, 0.0);
113  glRotated(m_angle, 0.0, 0.0, 1.0);
114  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
115  glColor4dv(elementColour.GetRGBA());
116  DrawTriangle(triangPts);
117  glPopMatrix();
118  }
119 }
120 
121 void Load::Rotate(bool clockwise)
122 {
123  double rotAngle = m_rotationAngle;
124  if(!clockwise) rotAngle = -m_rotationAngle;
125 
126  m_angle += rotAngle;
127  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
128  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
129  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
130  UpdateSwitchesPosition();
131  UpdatePowerFlowArrowsPosition();
132 }
133 
134 bool Load::GetContextMenu(wxMenu& menu)
135 {
136  menu.Append(ID_EDIT_ELEMENT, _("Edit Load"));
137  GeneralMenuItens(menu);
138  return true;
139 }
140 
141 bool Load::ShowForm(wxWindow* parent, Element* element)
142 {
143  LoadForm* loadForm = new LoadForm(parent, this);
144  if(loadForm->ShowModal() == wxID_OK) {
145  loadForm->Destroy();
146  return true;
147  }
148  loadForm->Destroy();
149  return false;
150 }
151 
152 LoadElectricalData Load::GetPUElectricalData(double systemPowerBase)
153 {
154  LoadElectricalData data = m_electricalData;
155  switch(data.activePowerUnit) {
156  case UNIT_W: {
157  data.activePower = data.activePower / systemPowerBase;
158  data.activePowerUnit = UNIT_PU;
159  } break;
160  case UNIT_kW: {
161  data.activePower = (data.activePower * 1e3) / systemPowerBase;
162  data.activePowerUnit = UNIT_PU;
163  } break;
164  case UNIT_MW: {
165  data.activePower = (data.activePower * 1e6) / systemPowerBase;
166  data.activePowerUnit = UNIT_PU;
167  } break;
168  default:
169  break;
170  }
171  switch(data.reactivePowerUnit) {
172  case UNIT_VAr: {
173  data.reactivePower = data.reactivePower / systemPowerBase;
174  data.reactivePowerUnit = UNIT_PU;
175  } break;
176  case UNIT_kVAr: {
177  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
178  data.reactivePowerUnit = UNIT_PU;
179  } break;
180  case UNIT_MVAr: {
181  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
182  data.reactivePowerUnit = UNIT_PU;
183  } break;
184  default:
185  break;
186  }
187 
188  return data;
189 }
190 
192 {
193  Load* copy = new Load();
194  *copy = *this;
195  return copy;
196 }
197 
198 wxString Load::GetTipText() const
199 {
200  wxString tipText = m_electricalData.name;
201 
202  // TODO: Avoid power calculation.
203  double activePower = m_electricalData.activePower;
204  double reactivePower = m_electricalData.reactivePower;
205  if(!m_online) {
206  activePower = 0.0;
207  reactivePower = 0.0;
208  }
209  if(m_online && m_electricalData.loadType == CONST_IMPEDANCE) {
210  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
211  reactivePower *= std::pow(std::abs(v), 2);
212  activePower *= std::pow(std::abs(v), 2);
213  }
214  tipText += "\n";
215  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
216  switch(m_electricalData.activePowerUnit) {
217  case UNIT_PU: {
218  tipText += _(" p.u.");
219  } break;
220  case UNIT_W: {
221  tipText += _(" W");
222  } break;
223  case UNIT_kW: {
224  tipText += _(" kW");
225  } break;
226  case UNIT_MW: {
227  tipText += _(" MW");
228  } break;
229  default:
230  break;
231  }
232  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
233  switch(m_electricalData.reactivePowerUnit) {
234  case UNIT_PU: {
235  tipText += _(" p.u.");
236  } break;
237  case UNIT_VAr: {
238  tipText += _(" VAr");
239  } break;
240  case UNIT_kVAr: {
241  tipText += _(" kVAr");
242  } break;
243  case UNIT_MVAr: {
244  tipText += _(" MVAr");
245  } break;
246  default:
247  break;
248  }
249 
250  return tipText;
251 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Load.h"
19 
20 Load::Load() : Shunt() {}
21 Load::Load(wxString name) : Shunt() { m_electricalData.name = name; }
22 Load::~Load() {}
23 bool Load::AddParent(Element* parent, wxPoint2DDouble position)
24 {
25  if(parent) {
26  m_parentList.push_back(parent);
27  parent->AddChild(this);
28  wxPoint2DDouble parentPt =
29  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
30  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
31  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
32 
33  m_position = parentPt + wxPoint2DDouble(0.0, 100.0); // Shifts the position to the down of the bus.
34  m_width = m_height = 20.0;
35  m_rect = wxRect2DDouble(m_position.m_x - 10.0, m_position.m_y - 10.0, m_width, m_height);
36 
37  m_pointList.push_back(parentPt);
38  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
39  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -20.0));
40  m_pointList.push_back(m_position + wxPoint2DDouble(0.0, -10.0));
41 
42  m_triangPts.push_back(wxPoint2DDouble(-m_width / 2.0, -m_height / 2.0));
43  m_triangPts.push_back(wxPoint2DDouble(m_width / 2.0, -m_height / 2.0));
44  m_triangPts.push_back(wxPoint2DDouble(0.0, m_height / 2.0));
45 
46  m_inserted = true;
47 
48  wxRect2DDouble genRect(0, 0, 0, 0);
49  m_switchRect.push_back(genRect); // Push a general rectangle.
50  UpdateSwitches();
51  m_pfDirection = PF_TO_ELEMENT;
52  UpdatePowerFlowArrowsPosition();
53 
54  return true;
55  }
56  return false;
57 }
58 
59 void Load::Draw(wxPoint2DDouble translation, double scale) const
60 {
61  OpenGLColour elementColour;
62  if(m_online) {
63  if(m_dynEvent)
64  elementColour = m_dynamicEventColour;
65  else
66  elementColour = m_onlineElementColour;
67  } else
68  elementColour = m_offlineElementColour;
69 
70  if(m_inserted) {
71  // Draw Selection (layer 1).
72  if(m_selected) {
73  glLineWidth(1.5 + m_borderSize * 2.0);
74  glColor4dv(m_selectionColour.GetRGBA());
75  std::vector<wxPoint2DDouble> selTriangPts;
76  selTriangPts.push_back(m_triangPts[0] + m_position +
77  wxPoint2DDouble(-m_borderSize / scale, -m_borderSize / scale));
78  selTriangPts.push_back(m_triangPts[1] + m_position +
79  wxPoint2DDouble(m_borderSize / scale, -m_borderSize / scale));
80  selTriangPts.push_back(m_triangPts[2] + m_position + wxPoint2DDouble(0.0, m_borderSize / scale));
81 
82  glPushMatrix();
83  glTranslated(m_position.m_x, m_position.m_y, 0.0);
84  glRotated(m_angle, 0.0, 0.0, 1.0);
85  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
86  DrawTriangle(selTriangPts);
87  glPopMatrix();
88 
89  DrawLine(m_pointList);
90 
91  // Draw node selection.
92  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
93  }
94 
95  // Draw Load (layer 2).
96  glLineWidth(1.5);
97 
98  // Draw node.
99  glColor4dv(elementColour.GetRGBA());
100  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
101 
102  DrawLine(m_pointList);
103 
104  DrawSwitches();
105  DrawPowerFlowPts();
106 
107  std::vector<wxPoint2DDouble> triangPts;
108  for(int i = 0; i < 3; i++) {
109  triangPts.push_back(m_triangPts[i] + m_position);
110  }
111  glPushMatrix();
112  glTranslated(m_position.m_x, m_position.m_y, 0.0);
113  glRotated(m_angle, 0.0, 0.0, 1.0);
114  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
115  glColor4dv(elementColour.GetRGBA());
116  DrawTriangle(triangPts);
117  glPopMatrix();
118  }
119 }
120 
121 void Load::Rotate(bool clockwise)
122 {
123  double rotAngle = m_rotationAngle;
124  if(!clockwise) rotAngle = -m_rotationAngle;
125 
126  m_angle += rotAngle;
127  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
128  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
129  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
130  UpdateSwitchesPosition();
131  UpdatePowerFlowArrowsPosition();
132 }
133 
134 bool Load::GetContextMenu(wxMenu& menu)
135 {
136  menu.Append(ID_EDIT_ELEMENT, _("Edit Load"));
137  GeneralMenuItens(menu);
138  return true;
139 }
140 
141 bool Load::ShowForm(wxWindow* parent, Element* element)
142 {
143  LoadForm* loadForm = new LoadForm(parent, this);
144  if(loadForm->ShowModal() == wxID_OK) {
145  loadForm->Destroy();
146  return true;
147  }
148  loadForm->Destroy();
149  return false;
150 }
151 
152 LoadElectricalData Load::GetPUElectricalData(double systemPowerBase)
153 {
154  LoadElectricalData data = m_electricalData;
155  switch(data.activePowerUnit) {
156  case UNIT_W: {
157  data.activePower = data.activePower / systemPowerBase;
158  data.activePowerUnit = UNIT_PU;
159  } break;
160  case UNIT_kW: {
161  data.activePower = (data.activePower * 1e3) / systemPowerBase;
162  data.activePowerUnit = UNIT_PU;
163  } break;
164  case UNIT_MW: {
165  data.activePower = (data.activePower * 1e6) / systemPowerBase;
166  data.activePowerUnit = UNIT_PU;
167  } break;
168  default:
169  break;
170  }
171  switch(data.reactivePowerUnit) {
172  case UNIT_VAr: {
173  data.reactivePower = data.reactivePower / systemPowerBase;
174  data.reactivePowerUnit = UNIT_PU;
175  } break;
176  case UNIT_kVAr: {
177  data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
178  data.reactivePowerUnit = UNIT_PU;
179  } break;
180  case UNIT_MVAr: {
181  data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
182  data.reactivePowerUnit = UNIT_PU;
183  } break;
184  default:
185  break;
186  }
187 
188  return data;
189 }
190 
192 {
193  Load* copy = new Load();
194  *copy = *this;
195  return copy;
196 }
197 
198 wxString Load::GetTipText() const
199 {
200  wxString tipText = m_electricalData.name;
201 
202  // TODO: Avoid power calculation.
203  double activePower = m_electricalData.activePower;
204  double reactivePower = m_electricalData.reactivePower;
205  if(!m_online) {
206  activePower = 0.0;
207  reactivePower = 0.0;
208  }
209  if(m_online && m_electricalData.loadType == CONST_IMPEDANCE) {
210  std::complex<double> v = static_cast<Bus*>(m_parentList[0])->GetElectricalData().voltage;
211  reactivePower *= std::pow(std::abs(v), 2);
212  activePower *= std::pow(std::abs(v), 2);
213  }
214  tipText += "\n";
215  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
216  switch(m_electricalData.activePowerUnit) {
217  case UNIT_PU: {
218  tipText += _(" p.u.");
219  } break;
220  case UNIT_W: {
221  tipText += _(" W");
222  } break;
223  case UNIT_kW: {
224  tipText += _(" kW");
225  } break;
226  case UNIT_MW: {
227  tipText += _(" MW");
228  } break;
229  default:
230  break;
231  }
232  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
233  switch(m_electricalData.reactivePowerUnit) {
234  case UNIT_PU: {
235  tipText += _(" p.u.");
236  } break;
237  case UNIT_VAr: {
238  tipText += _(" VAr");
239  } break;
240  case UNIT_kVAr: {
241  tipText += _(" kVAr");
242  } break;
243  case UNIT_MVAr: {
244  tipText += _(" MVAr");
245  } break;
246  default:
247  break;
248  }
249 
250  return tipText;
251 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Load.cpp:121
@@ -97,22 +97,23 @@ $(document).ready(function(){initNavTree('_load_8cpp_source.html','');}); -
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual Element * GetCopy()
Get a the element copy.
Definition: Load.cpp:191
+
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Load.cpp:134
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Load.cpp:59
- +
Class to manage color of OpenGL.
Definition: Element.h:67
Form to edit the load power data.
Definition: LoadForm.h:32
virtual wxString GetTipText() const
Get the tip text.
Definition: Load.cpp:198
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Load.cpp:23
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
-
Definition: Shunt.h:24
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Load.cpp:141
const GLdouble * GetRGBA() const
Get colour in RGBA.
Definition: Element.h:101
diff --git a/docs/doxygen/html/_load_8h.html b/docs/doxygen/html/_load_8h.html new file mode 100644 index 0000000..af11d9f --- /dev/null +++ b/docs/doxygen/html/_load_8h.html @@ -0,0 +1,126 @@ + + + + + + + + + +Project/Load.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Load.h File Reference
+
+
+
#include "LoadForm.h"
+#include "Shunt.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  LoadElectricalData
 
class  Load
 Loas shunt power element. More...
 
+ + + +

+Enumerations

enum  LoadType { CONST_POWER = 0, +CONST_IMPEDANCE + }
 
+
+
+ + + + diff --git a/docs/doxygen/html/_load_8h.js b/docs/doxygen/html/_load_8h.js new file mode 100644 index 0000000..31f1d49 --- /dev/null +++ b/docs/doxygen/html/_load_8h.js @@ -0,0 +1,9 @@ +var _load_8h = +[ + [ "LoadElectricalData", "struct_load_electrical_data.html", "struct_load_electrical_data" ], + [ "Load", "class_load.html", "class_load" ], + [ "LoadType", "_load_8h.html#a23ef47ba052bffd629011885a72be6ae", [ + [ "CONST_POWER", "_load_8h.html#a23ef47ba052bffd629011885a72be6aea050d3b412b1a323ad9b62e94a7e8386f", null ], + [ "CONST_IMPEDANCE", "_load_8h.html#a23ef47ba052bffd629011885a72be6aea3030768ede9894e4595833f464783de6", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/doxygen/html/_load_8h_source.html b/docs/doxygen/html/_load_8h_source.html index 05f39b3..468482b 100644 --- a/docs/doxygen/html/_load_8h_source.html +++ b/docs/doxygen/html/_load_8h_source.html @@ -88,20 +88,21 @@ $(document).ready(function(){initNavTree('_load_8h_source.html','');});
Load.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef LOAD_H
19 #define LOAD_H
20 
21 #include "LoadForm.h"
22 #include "Shunt.h"
23 
24 enum LoadType { CONST_POWER = 0, CONST_IMPEDANCE };
25 
27  wxString name;
28  double activePower = 100.0;
29  ElectricalUnit activePowerUnit = UNIT_MW;
30  double reactivePower = 0.0;
31  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
32  LoadType loadType = CONST_POWER;
33 };
34 
35 class Load : public Shunt
36 {
37  public:
38  Load();
39  Load(wxString name);
40  ~Load();
41 
42  virtual Element* GetCopy();
43  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
44  virtual void Draw(wxPoint2DDouble translation, double scale) const;
45  virtual void Rotate(bool clockwise = true);
46  virtual bool GetContextMenu(wxMenu& menu);
47  virtual wxString GetTipText() const;
48  virtual bool ShowForm(wxWindow* parent, Element* element);
49  LoadElectricalData GetElectricalData() { return m_electricalData; }
50  LoadElectricalData GetPUElectricalData(double systemPowerBase);
51  void SetElectricalData(LoadElectricalData electricalData) { m_electricalData = electricalData; }
52  protected:
53  std::vector<wxPoint2DDouble> m_triangPts;
54  LoadElectricalData m_electricalData;
55 };
56 
57 #endif // LOAD_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef LOAD_H
19 #define LOAD_H
20 
21 #include "LoadForm.h"
22 #include "Shunt.h"
23 
24 enum LoadType { CONST_POWER = 0, CONST_IMPEDANCE };
25 
27  wxString name;
28  double activePower = 100.0;
29  ElectricalUnit activePowerUnit = UNIT_MW;
30  double reactivePower = 0.0;
31  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
32  LoadType loadType = CONST_POWER;
33 };
34 
42 class Load : public Shunt
43 {
44  public:
45  Load();
46  Load(wxString name);
47  ~Load();
48 
49  virtual Element* GetCopy();
50  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
51  virtual void Draw(wxPoint2DDouble translation, double scale) const;
52  virtual void Rotate(bool clockwise = true);
53  virtual bool GetContextMenu(wxMenu& menu);
54  virtual wxString GetTipText() const;
55  virtual bool ShowForm(wxWindow* parent, Element* element);
56  LoadElectricalData GetElectricalData() { return m_electricalData; }
57  LoadElectricalData GetPUElectricalData(double systemPowerBase);
58  void SetElectricalData(LoadElectricalData electricalData) { m_electricalData = electricalData; }
59  protected:
60  std::vector<wxPoint2DDouble> m_triangPts;
61  LoadElectricalData m_electricalData;
62 };
63 
64 #endif // LOAD_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
-
Definition: Shunt.h:24
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "LoadForm.h"
19 #include "SwitchingForm.h"
20 #include "Load.h"
21 
22 LoadForm::LoadForm(wxWindow* parent, Load* load) : LoadFormBase(parent)
23 {
24  SetSize(GetBestSize());
25  LoadElectricalData data = load->GetElectricalData();
26 
27  m_textCtrlName->SetValue(data.name);
28 
29  m_textCtrlActivePower->SetValue(Load::StringFromDouble(data.activePower));
30  switch(data.activePowerUnit) {
31  case UNIT_PU: {
32  m_choiceActivePower->SetSelection(0);
33  } break;
34  case UNIT_W: {
35  m_choiceActivePower->SetSelection(1);
36  } break;
37  case UNIT_kW: {
38  m_choiceActivePower->SetSelection(2);
39  } break;
40  case UNIT_MW: {
41  m_choiceActivePower->SetSelection(3);
42  } break;
43  default:
44  break;
45  }
46 
47  m_textCtrlReactivePower->SetValue(Load::StringFromDouble(data.reactivePower));
48  switch(data.reactivePowerUnit) {
49  case UNIT_PU: {
50  m_choiceReactivePower->SetSelection(0);
51  } break;
52  case UNIT_VAr: {
53  m_choiceReactivePower->SetSelection(1);
54  } break;
55  case UNIT_kVAr: {
56  m_choiceReactivePower->SetSelection(2);
57  } break;
58  case UNIT_MVAr: {
59  m_choiceReactivePower->SetSelection(3);
60  } break;
61  default:
62  break;
63  }
64 
65  switch(data.loadType) {
66  case CONST_POWER: {
67  m_choiceType->SetSelection(0);
68  } break;
69  case CONST_IMPEDANCE: {
70  m_choiceType->SetSelection(1);
71  } break;
72  }
73 
74  m_parent = parent;
75  m_load = load;
76 }
77 
78 LoadForm::~LoadForm() {}
79 void LoadForm::OnOnButtonClick(wxCommandEvent& event)
80 {
81  if(ValidateData()) EndModal(wxID_OK);
82 }
83 
84 void LoadForm::OnStabilityButtonClick(wxCommandEvent& event)
85 {
86  if(ValidateData()) {
87  SwitchingForm swForm(m_parent, m_load);
88  swForm.SetTitle(_("Load: Switching"));
89  swForm.ShowModal();
90  EndModal(wxID_OK);
91  }
92 }
93 
94 bool LoadForm::ValidateData()
95 {
96  LoadElectricalData data;
97 
98  data.name = m_textCtrlName->GetValue();
99 
100  if(!m_load->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
101  _("Value entered incorrectly in the field \"Active power\".")))
102  return false;
103  switch(m_choiceActivePower->GetSelection()) {
104  case 0: {
105  data.activePowerUnit = UNIT_PU;
106  } break;
107  case 1: {
108  data.activePowerUnit = UNIT_W;
109  } break;
110  case 2: {
111  data.activePowerUnit = UNIT_kW;
112  } break;
113  case 3: {
114  data.activePowerUnit = UNIT_MW;
115  } break;
116  }
117 
118  if(!m_load->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
119  _("Value entered incorrectly in the field \"Reactive power\".")))
120  return false;
121  switch(m_choiceReactivePower->GetSelection()) {
122  case 0: {
123  data.reactivePowerUnit = UNIT_PU;
124  } break;
125  case 1: {
126  data.reactivePowerUnit = UNIT_VAr;
127  } break;
128  case 2: {
129  data.reactivePowerUnit = UNIT_kVAr;
130  } break;
131  case 3: {
132  data.reactivePowerUnit = UNIT_MVAr;
133  } break;
134  }
135 
136  switch(m_choiceType->GetSelection()) {
137  case 0: {
138  data.loadType = CONST_POWER;
139  } break;
140  case 1: {
141  data.loadType = CONST_IMPEDANCE;
142  } break;
143  }
144 
145  m_load->SetElectricalData(data);
146  return true;
147 }
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "LoadForm.h"
19 #include "SwitchingForm.h"
20 #include "Load.h"
21 
22 LoadForm::LoadForm(wxWindow* parent, Load* load) : LoadFormBase(parent)
23 {
24  SetSize(GetBestSize());
25  LoadElectricalData data = load->GetElectricalData();
26 
27  m_textCtrlName->SetValue(data.name);
28 
29  m_textCtrlActivePower->SetValue(Load::StringFromDouble(data.activePower));
30  switch(data.activePowerUnit) {
31  case UNIT_PU: {
32  m_choiceActivePower->SetSelection(0);
33  } break;
34  case UNIT_W: {
35  m_choiceActivePower->SetSelection(1);
36  } break;
37  case UNIT_kW: {
38  m_choiceActivePower->SetSelection(2);
39  } break;
40  case UNIT_MW: {
41  m_choiceActivePower->SetSelection(3);
42  } break;
43  default:
44  break;
45  }
46 
47  m_textCtrlReactivePower->SetValue(Load::StringFromDouble(data.reactivePower));
48  switch(data.reactivePowerUnit) {
49  case UNIT_PU: {
50  m_choiceReactivePower->SetSelection(0);
51  } break;
52  case UNIT_VAr: {
53  m_choiceReactivePower->SetSelection(1);
54  } break;
55  case UNIT_kVAr: {
56  m_choiceReactivePower->SetSelection(2);
57  } break;
58  case UNIT_MVAr: {
59  m_choiceReactivePower->SetSelection(3);
60  } break;
61  default:
62  break;
63  }
64 
65  switch(data.loadType) {
66  case CONST_POWER: {
67  m_choiceType->SetSelection(0);
68  } break;
69  case CONST_IMPEDANCE: {
70  m_choiceType->SetSelection(1);
71  } break;
72  }
73 
74  m_parent = parent;
75  m_load = load;
76 }
77 
78 LoadForm::~LoadForm() {}
79 void LoadForm::OnOnButtonClick(wxCommandEvent& event)
80 {
81  if(ValidateData()) EndModal(wxID_OK);
82 }
83 
84 void LoadForm::OnStabilityButtonClick(wxCommandEvent& event)
85 {
86  if(ValidateData()) {
87  SwitchingForm swForm(m_parent, m_load);
88  swForm.SetTitle(_("Load: Switching"));
89  swForm.ShowModal();
90  EndModal(wxID_OK);
91  }
92 }
93 
94 bool LoadForm::ValidateData()
95 {
96  LoadElectricalData data;
97 
98  data.name = m_textCtrlName->GetValue();
99 
100  if(!m_load->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
101  _("Value entered incorrectly in the field \"Active power\".")))
102  return false;
103  switch(m_choiceActivePower->GetSelection()) {
104  case 0: {
105  data.activePowerUnit = UNIT_PU;
106  } break;
107  case 1: {
108  data.activePowerUnit = UNIT_W;
109  } break;
110  case 2: {
111  data.activePowerUnit = UNIT_kW;
112  } break;
113  case 3: {
114  data.activePowerUnit = UNIT_MW;
115  } break;
116  }
117 
118  if(!m_load->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
119  _("Value entered incorrectly in the field \"Reactive power\".")))
120  return false;
121  switch(m_choiceReactivePower->GetSelection()) {
122  case 0: {
123  data.reactivePowerUnit = UNIT_PU;
124  } break;
125  case 1: {
126  data.reactivePowerUnit = UNIT_VAr;
127  } break;
128  case 2: {
129  data.reactivePowerUnit = UNIT_kVAr;
130  } break;
131  case 3: {
132  data.reactivePowerUnit = UNIT_MVAr;
133  } break;
134  }
135 
136  switch(m_choiceType->GetSelection()) {
137  case 0: {
138  data.loadType = CONST_POWER;
139  } break;
140  case 1: {
141  data.loadType = CONST_IMPEDANCE;
142  } break;
143  }
144 
145  m_load->SetElectricalData(data);
146  return true;
147 }
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
+ -
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
diff --git a/docs/doxygen/html/_load_form_8h_source.html b/docs/doxygen/html/_load_form_8h_source.html index 284ad8b..47a70cd 100644 --- a/docs/doxygen/html/_load_form_8h_source.html +++ b/docs/doxygen/html/_load_form_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_load_form_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef LOADFORM_H
19 #define LOADFORM_H
20 #include "ElementForm.h"
21 
22 class Load;
23 class SwitchingForm;
24 
32 class LoadForm : public LoadFormBase
33 {
34  public:
35  LoadForm(wxWindow* parent, Load* load);
36  virtual ~LoadForm();
37 
38  virtual bool ValidateData();
39 
40  protected:
41  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); };
42  virtual void OnOnButtonClick(wxCommandEvent& event);
43  virtual void OnStabilityButtonClick(wxCommandEvent& event);
44 
45  wxWindow* m_parent = NULL;
46  Load* m_load = NULL;
47 };
48 #endif // LOADFORM_H
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
Form to edit the load power data.
Definition: LoadForm.h:32
diff --git a/docs/doxygen/html/_machines_8cpp_source.html b/docs/doxygen/html/_machines_8cpp_source.html index b780cef..51a16f2 100644 --- a/docs/doxygen/html/_machines_8cpp_source.html +++ b/docs/doxygen/html/_machines_8cpp_source.html @@ -88,9 +88,10 @@ $(document).ready(function(){initNavTree('_machines_8cpp_source.html','');});
Machines.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Machines.h"
19 
21 #include "ControlElementSolver.h"
22 
23 Machines::Machines() : PowerElement() {}
24 Machines::~Machines() {}
25 bool Machines::AddParent(Element* parent, wxPoint2DDouble position)
26 {
27  if(parent) {
28  m_parentList.push_back(parent);
29  parent->AddChild(this);
30  wxPoint2DDouble parentPt =
31  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
32  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
33  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
34 
35  m_position = parentPt + wxPoint2DDouble(-100.0, 0.0); // Shifts the position to the left of the bus.
36  m_width = m_height = 50.0;
37  m_rect = wxRect2DDouble(m_position.m_x - 25.0, m_position.m_y - 25.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(35.0, 0.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(25.0, 0.0));
43  m_inserted = true;
44 
45  wxRect2DDouble genRect(0, 0, 0, 0);
46  m_switchRect.push_back(genRect); // Push a general rectangle.
47  UpdateSwitches();
48  UpdatePowerFlowArrowsPosition();
49  return true;
50  }
51  return false;
52 }
53 
54 void Machines::Draw(wxPoint2DDouble translation, double scale) const
55 {
56  OpenGLColour elementColour;
57  if(m_online) {
58  if(m_dynEvent)
59  elementColour = m_dynamicEventColour;
60  else
61  elementColour = m_onlineElementColour;
62  } else
63  elementColour = m_offlineElementColour;
64 
65  if(m_inserted) {
66  // Draw Selection (layer 1).
67  if(m_selected) {
68  glLineWidth(1.5 + m_borderSize * 2.0);
69  glColor4dv(m_selectionColour.GetRGBA());
70  DrawCircle(m_position, 25.0 + (m_borderSize + 1.5) / scale, 20, GL_POLYGON);
71  DrawLine(m_pointList);
72 
73  // Draw node selection.
74  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
75  }
76 
77  // Draw Machines (layer 2).
78  glLineWidth(1.5);
79 
80  // Draw node.
81  glColor4dv(elementColour.GetRGBA());
82  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
83 
84  DrawLine(m_pointList);
85 
86  DrawSwitches();
87  DrawPowerFlowPts();
88 
89  glColor4d(1.0, 1.0, 1.0, 1.0);
90  DrawCircle(m_position, 25.0, 20, GL_POLYGON);
91 
92  glColor4dv(elementColour.GetRGBA());
93  DrawCircle(m_position, 25.0, 20);
94 
95  // Draw machine symbol.
96  glLineWidth(2.0);
97  DrawSymbol();
98  }
99 }
100 
101 void Machines::UpdateSwitchesPosition()
102 {
103  if(m_parentList[0]) {
104  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
105  } else {
106  m_pointList[1] = m_pointList[0];
107  }
108  UpdateSwitches();
109 }
110 
111 void Machines::Move(wxPoint2DDouble position)
112 {
113  SetPosition(m_movePos + position - m_moveStartPt);
114  for(int i = 2; i < (int)m_pointList.size(); i++) {
115  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
116  }
117  if(!m_parentList[0]) {
118  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
119  }
120  UpdateSwitchesPosition();
121  UpdatePowerFlowArrowsPosition();
122 }
123 
124 void Machines::MoveNode(Element* element, wxPoint2DDouble position)
125 {
126  if(element) {
127  if(element == m_parentList[0]) {
128  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
129  }
130  } else {
131  if(m_activeNodeID == 1) {
132  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
133  if(m_parentList[0]) {
134  m_parentList[0]->RemoveChild(this);
135  m_parentList[0] = NULL;
136  m_online = false;
137  }
138  }
139  }
140 
141  // Recalculate switches positions
142  UpdateSwitchesPosition();
143  UpdatePowerFlowArrowsPosition();
144 }
145 
146 void Machines::StartMove(wxPoint2DDouble position)
147 {
148  m_moveStartPt = position;
149  m_movePts = m_pointList;
150  m_movePos = m_position;
151 }
152 
153 void Machines::RotateNode(Element* parent, bool clockwise)
154 {
155  double rotAngle = m_rotationAngle;
156  if(!clockwise) rotAngle = -m_rotationAngle;
157 
158  if(parent == m_parentList[0]) {
159  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
160  UpdateSwitchesPosition();
161  UpdatePowerFlowArrowsPosition();
162  }
163 }
164 
166 {
167  if(parent == m_parentList[0]) {
168  m_parentList[0] = NULL;
169  m_online = false;
170  UpdateSwitchesPosition();
171  UpdatePowerFlowArrowsPosition();
172  }
173 }
174 
175 bool Machines::NodeContains(wxPoint2DDouble position)
176 {
177  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
178  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
179 
180  if(nodeRect.Contains(position)) {
181  m_activeNodeID = 1;
182  return true;
183  }
184 
185  m_activeNodeID = 0;
186  return false;
187 }
188 
190 {
191  if(parent && m_activeNodeID != 0) {
192  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
193  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
194 
195  if(parent->Intersects(nodeRect)) {
196  m_parentList[0] = parent;
197 
198  // Centralize the node on bus.
199  wxPoint2DDouble parentPt =
200  parent->RotateAtPosition(m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
201  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
202  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
203  m_pointList[0] = parentPt;
204 
205  UpdateSwitchesPosition();
206  UpdatePowerFlowArrowsPosition();
207  return true;
208  } else {
209  m_parentList[0] = NULL;
210  m_online = false;
211  }
212  }
213  return false;
214 }
215 
217 {
218  if(m_parentList[0]) {
219  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
220  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
221 
222  if(!m_parentList[0]->Intersects(nodeRect)) {
223  m_parentList[0]->RemoveChild(this);
224  m_parentList[0] = NULL;
225  m_online = false;
226  UpdateSwitchesPosition();
227  UpdatePowerFlowArrowsPosition();
228  }
229  }
230 }
231 
232 void Machines::Rotate(bool clockwise)
233 {
234  double rotAngle = m_rotationAngle;
235  if(!clockwise) rotAngle = -m_rotationAngle;
236 
237  m_angle += rotAngle;
238  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
239  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
240  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
241  UpdateSwitchesPosition();
242  UpdatePowerFlowArrowsPosition();
243 }
244 
245 void Machines::UpdatePowerFlowArrowsPosition()
246 {
247  std::vector<wxPoint2DDouble> edges;
248  switch(m_pfDirection) {
249  case PF_NONE: {
250  m_powerFlowArrow.clear();
251  } break;
252  case PF_TO_BUS: {
253  edges.push_back(m_pointList[2]);
254  edges.push_back(m_pointList[1]);
255  } break;
256  case PF_TO_ELEMENT: {
257  edges.push_back(m_pointList[1]);
258  edges.push_back(m_pointList[2]);
259  } break;
260  default:
261  break;
262  }
263 
264  CalculatePowerFlowPts(edges);
265 }
266 
268 {
269  m_pfDirection = pfDirection;
270  UpdatePowerFlowArrowsPosition();
271 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Machines.h"
19 
21 #include "ControlElementSolver.h"
22 
23 Machines::Machines() : PowerElement() {}
24 Machines::~Machines() {}
25 bool Machines::AddParent(Element* parent, wxPoint2DDouble position)
26 {
27  if(parent) {
28  m_parentList.push_back(parent);
29  parent->AddChild(this);
30  wxPoint2DDouble parentPt =
31  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
32  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
33  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
34 
35  m_position = parentPt + wxPoint2DDouble(-100.0, 0.0); // Shifts the position to the left of the bus.
36  m_width = m_height = 50.0;
37  m_rect = wxRect2DDouble(m_position.m_x - 25.0, m_position.m_y - 25.0, m_width, m_height);
38 
39  m_pointList.push_back(parentPt);
40  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
41  m_pointList.push_back(m_position + wxPoint2DDouble(35.0, 0.0));
42  m_pointList.push_back(m_position + wxPoint2DDouble(25.0, 0.0));
43  m_inserted = true;
44 
45  wxRect2DDouble genRect(0, 0, 0, 0);
46  m_switchRect.push_back(genRect); // Push a general rectangle.
47  UpdateSwitches();
48  UpdatePowerFlowArrowsPosition();
49  return true;
50  }
51  return false;
52 }
53 
54 void Machines::Draw(wxPoint2DDouble translation, double scale) const
55 {
56  OpenGLColour elementColour;
57  if(m_online) {
58  if(m_dynEvent)
59  elementColour = m_dynamicEventColour;
60  else
61  elementColour = m_onlineElementColour;
62  } else
63  elementColour = m_offlineElementColour;
64 
65  if(m_inserted) {
66  // Draw Selection (layer 1).
67  if(m_selected) {
68  glLineWidth(1.5 + m_borderSize * 2.0);
69  glColor4dv(m_selectionColour.GetRGBA());
70  DrawCircle(m_position, 25.0 + (m_borderSize + 1.5) / scale, 20, GL_POLYGON);
71  DrawLine(m_pointList);
72 
73  // Draw node selection.
74  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
75  }
76 
77  // Draw Machines (layer 2).
78  glLineWidth(1.5);
79 
80  // Draw node.
81  glColor4dv(elementColour.GetRGBA());
82  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
83 
84  DrawLine(m_pointList);
85 
86  DrawSwitches();
87  DrawPowerFlowPts();
88 
89  glColor4d(1.0, 1.0, 1.0, 1.0);
90  DrawCircle(m_position, 25.0, 20, GL_POLYGON);
91 
92  glColor4dv(elementColour.GetRGBA());
93  DrawCircle(m_position, 25.0, 20);
94 
95  // Draw machine symbol.
96  glLineWidth(2.0);
97  DrawSymbol();
98  }
99 }
100 
101 void Machines::UpdateSwitchesPosition()
102 {
103  if(m_parentList[0]) {
104  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
105  } else {
106  m_pointList[1] = m_pointList[0];
107  }
108  UpdateSwitches();
109 }
110 
111 void Machines::Move(wxPoint2DDouble position)
112 {
113  SetPosition(m_movePos + position - m_moveStartPt);
114  for(int i = 2; i < (int)m_pointList.size(); i++) {
115  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
116  }
117  if(!m_parentList[0]) {
118  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
119  }
120  UpdateSwitchesPosition();
121  UpdatePowerFlowArrowsPosition();
122 }
123 
124 void Machines::MoveNode(Element* element, wxPoint2DDouble position)
125 {
126  if(element) {
127  if(element == m_parentList[0]) {
128  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
129  }
130  } else {
131  if(m_activeNodeID == 1) {
132  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
133  if(m_parentList[0]) {
134  m_parentList[0]->RemoveChild(this);
135  m_parentList[0] = NULL;
136  m_online = false;
137  }
138  }
139  }
140 
141  // Recalculate switches positions
142  UpdateSwitchesPosition();
143  UpdatePowerFlowArrowsPosition();
144 }
145 
146 void Machines::StartMove(wxPoint2DDouble position)
147 {
148  m_moveStartPt = position;
149  m_movePts = m_pointList;
150  m_movePos = m_position;
151 }
152 
153 void Machines::RotateNode(Element* parent, bool clockwise)
154 {
155  double rotAngle = m_rotationAngle;
156  if(!clockwise) rotAngle = -m_rotationAngle;
157 
158  if(parent == m_parentList[0]) {
159  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
160  UpdateSwitchesPosition();
161  UpdatePowerFlowArrowsPosition();
162  }
163 }
164 
166 {
167  if(parent == m_parentList[0]) {
168  m_parentList[0] = NULL;
169  m_online = false;
170  UpdateSwitchesPosition();
171  UpdatePowerFlowArrowsPosition();
172  }
173 }
174 
175 bool Machines::NodeContains(wxPoint2DDouble position)
176 {
177  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
178  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
179 
180  if(nodeRect.Contains(position)) {
181  m_activeNodeID = 1;
182  return true;
183  }
184 
185  m_activeNodeID = 0;
186  return false;
187 }
188 
190 {
191  if(parent && m_activeNodeID != 0) {
192  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
193  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
194 
195  if(parent->Intersects(nodeRect)) {
196  m_parentList[0] = parent;
197 
198  // Centralize the node on bus.
199  wxPoint2DDouble parentPt =
200  parent->RotateAtPosition(m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
201  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
202  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
203  m_pointList[0] = parentPt;
204 
205  UpdateSwitchesPosition();
206  UpdatePowerFlowArrowsPosition();
207  return true;
208  } else {
209  m_parentList[0] = NULL;
210  m_online = false;
211  }
212  }
213  return false;
214 }
215 
217 {
218  if(m_parentList[0]) {
219  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
220  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
221 
222  if(!m_parentList[0]->Intersects(nodeRect)) {
223  m_parentList[0]->RemoveChild(this);
224  m_parentList[0] = NULL;
225  m_online = false;
226  UpdateSwitchesPosition();
227  UpdatePowerFlowArrowsPosition();
228  }
229  }
230 }
231 
232 void Machines::Rotate(bool clockwise)
233 {
234  double rotAngle = m_rotationAngle;
235  if(!clockwise) rotAngle = -m_rotationAngle;
236 
237  m_angle += rotAngle;
238  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
239  m_pointList[2] = RotateAtPosition(m_pointList[2], rotAngle);
240  m_pointList[3] = RotateAtPosition(m_pointList[3], rotAngle);
241  UpdateSwitchesPosition();
242  UpdatePowerFlowArrowsPosition();
243 }
244 
245 void Machines::UpdatePowerFlowArrowsPosition()
246 {
247  std::vector<wxPoint2DDouble> edges;
248  switch(m_pfDirection) {
249  case PF_NONE: {
250  m_powerFlowArrow.clear();
251  } break;
252  case PF_TO_BUS: {
253  edges.push_back(m_pointList[2]);
254  edges.push_back(m_pointList[1]);
255  } break;
256  case PF_TO_ELEMENT: {
257  edges.push_back(m_pointList[1]);
258  edges.push_back(m_pointList[2]);
259  } break;
260  default:
261  break;
262  }
263 
264  CalculatePowerFlowPts(edges);
265 }
266 
268 {
269  m_pfDirection = pfDirection;
270  UpdatePowerFlowArrowsPosition();
271 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Machines.cpp:146
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Machines.cpp:111
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition: Element.cpp:107
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element&#39;s rect intersects other rect.
@@ -107,11 +108,11 @@ $(document).ready(function(){initNavTree('_machines_8cpp_source.html','');}); - +
Class to manage color of OpenGL.
Definition: Element.h:67
PowerFlowDirection
Direction of power flow arrows.
Definition: PowerElement.h:78
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Machines.cpp:165
- +
Abstract class of power elements.
Definition: PowerElement.h:117
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Machines.cpp:124
const GLdouble * GetRGBA() const
Get colour in RGBA.
Definition: Element.h:101
diff --git a/docs/doxygen/html/_machines_8h.html b/docs/doxygen/html/_machines_8h.html new file mode 100644 index 0000000..7c8209e --- /dev/null +++ b/docs/doxygen/html/_machines_8h.html @@ -0,0 +1,115 @@ + + + + + + + + + +Project/Machines.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Machines.h File Reference
+
+
+
#include "PowerElement.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  Machines
 Abstract class for rotary machines power elements. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_machines_8h_source.html b/docs/doxygen/html/_machines_8h_source.html index 9b7c76c..1310bfd 100644 --- a/docs/doxygen/html/_machines_8h_source.html +++ b/docs/doxygen/html/_machines_8h_source.html @@ -88,9 +88,9 @@ $(document).ready(function(){initNavTree('_machines_8h_source.html','');});
Machines.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MACHINES_H
19 #define MACHINES_H
20 
21 #include "PowerElement.h"
22 
25 
26 class Machines : public PowerElement
27 {
28  public:
29  enum SyncMachineModel { SM_MODEL_1 = 0, SM_MODEL_2, SM_MODEL_3, SM_MODEL_4, SM_MODEL_5 };
30 
31  Machines();
32  ~Machines();
33 
34  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
35  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
36  virtual void Draw(wxPoint2DDouble translation, double scale) const;
37  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
38  virtual void Move(wxPoint2DDouble position);
39  virtual void MoveNode(Element* element, wxPoint2DDouble position);
40  virtual void StartMove(wxPoint2DDouble position);
41  virtual void RotateNode(Element* parent, bool clockwise = true);
42  virtual void RemoveParent(Element* parent);
43  virtual bool NodeContains(wxPoint2DDouble position);
44  virtual bool SetNodeParent(Element* parent);
45  virtual void UpdateNodes();
46  virtual void Rotate(bool clockwise = true);
47  virtual void DrawSymbol() const {}
48  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection);
49 
50  protected:
51  void UpdateSwitchesPosition();
52  void UpdatePowerFlowArrowsPosition();
53  bool m_inserted = false;
54 };
55 
56 #endif // MACHINES_H
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Machines.h:35
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MACHINES_H
19 #define MACHINES_H
20 
21 #include "PowerElement.h"
22 
25 
33 class Machines : public PowerElement
34 {
35  public:
36  enum SyncMachineModel { SM_MODEL_1 = 0, SM_MODEL_2, SM_MODEL_3, SM_MODEL_4, SM_MODEL_5 };
37 
38  Machines();
39  ~Machines();
40 
41  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
42  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
43  virtual void Draw(wxPoint2DDouble translation, double scale) const;
44  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
45  virtual void Move(wxPoint2DDouble position);
46  virtual void MoveNode(Element* element, wxPoint2DDouble position);
47  virtual void StartMove(wxPoint2DDouble position);
48  virtual void RotateNode(Element* parent, bool clockwise = true);
49  virtual void RemoveParent(Element* parent);
50  virtual bool NodeContains(wxPoint2DDouble position);
51  virtual bool SetNodeParent(Element* parent);
52  virtual void UpdateNodes();
53  virtual void Rotate(bool clockwise = true);
54  virtual void DrawSymbol() const {}
55  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection);
56 
57  protected:
58  void UpdateSwitchesPosition();
59  void UpdatePowerFlowArrowsPosition();
60  bool m_inserted = false;
61 };
62 
63 #endif // MACHINES_H
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Machines.h:42
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Machines.cpp:146
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Machines.cpp:111
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement...
Definition: Machines.cpp:175
@@ -100,21 +100,21 @@ $(document).ready(function(){initNavTree('_machines_8h_source.html','');});
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Machines.cpp:189
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Machines.cpp:216
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
-
Switching data of power elements.
+
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Machines.cpp:232
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Machines.cpp:54
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Machines.h:37
- +
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Machines.h:44
+
Abstract class for rotary machines power elements.
Definition: Machines.h:33
PowerFlowDirection
Direction of power flow arrows.
Definition: PowerElement.h:78
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Machines.cpp:165
- +
Abstract class of power elements.
Definition: PowerElement.h:117
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Machines.cpp:124
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "MainFrame.h"
19 #include "ArtMetro.h"
20 #include "Workspace.h"
21 #include "Bus.h"
22 #include "Line.h"
23 #include "Transformer.h"
24 #include "SyncGenerator.h"
25 #include "IndMotor.h"
26 #include "SyncMotor.h"
27 #include "Load.h"
28 #include "Inductor.h"
29 #include "Capacitor.h"
30 #include "FileHanding.h"
31 #include "GeneralPropertiesForm.h"
33 #include "PropertiesData.h"
34 #include "ChartView.h"
35 #include "DataReport.h"
36 #include "AboutForm.h"
37 
39 MainFrame::MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initProperties, wxString openPath)
40  : MainFrameBase(parent)
41 {
42  m_locale = locale;
43  m_generalProperties = initProperties;
44 
45  Init();
46 
47  if(openPath != "") {
48  EnableCurrentProjectRibbon();
49  Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar());
50 
51  FileHanding fileHandling(newWorkspace);
52  if(fileHandling.OpenProject(openPath)) {
53  newWorkspace->SetSavedPath(openPath);
54 
55  m_workspaceList.push_back(newWorkspace);
56 
57  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
58  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
59 
60  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
61  m_auiNotebook->Layout();
62  newWorkspace->Redraw();
63  newWorkspace->SetJustOpened(true);
64  m_projectNumber++;
65  }
66  }
67 }
68 
70 {
71  // if(m_artMetro) delete m_artMetro;
72  if(m_addElementsMenu) {
73  m_addElementsMenu->Disconnect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::OnAddElementsClick),
74  NULL, this);
75  delete m_addElementsMenu;
76  }
77  if(m_locale) delete m_locale;
78  if(m_generalProperties) delete m_generalProperties;
79 }
80 
81 void MainFrame::Init()
82 {
83  this->SetSize(800, 600);
84 
85  CreateAddElementsMenu();
86 
87  EnableCurrentProjectRibbon(false);
88 
89  m_artMetro = new wxRibbonMetroArtProvider();
90  m_ribbonBar->SetArtProvider(m_artMetro);
91  m_ribbonBar->Realize();
92 
93  this->Layout();
94 }
95 
96 void MainFrame::EnableCurrentProjectRibbon(bool enable)
97 {
98  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ADDELEMENT, enable);
99  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_CHARTS, enable);
100  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_CLOSE, enable);
101  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_COPY, enable);
102  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_DATAREPORT, enable);
103  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_DELETE, enable);
104  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_DISABLESOL, enable);
105  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_DRAG, enable);
106  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_ENABLESOL, enable);
107  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_FAULT, enable);
108  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_FIT, enable);
109  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_MOVE, enable);
110  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_PASTE, enable);
111  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_POWERFLOW, enable);
112  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_REDO, enable);
113  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_RESETVOLT, enable);
114  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_RUNSTAB, enable);
115  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_SAVE, enable);
116  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_SAVEAS, enable);
117  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_SCPOWER, enable);
118  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_PROJSETTINGS, enable);
119  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_SNAPSHOT, enable);
120  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_SIMULSETTINGS, enable);
121  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_UNDO, enable);
122  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ROTATEC, enable);
123  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ROTATECC, enable);
124 }
125 
126 void MainFrame::CreateAddElementsMenu()
127 {
128  m_addElementsMenu = new wxMenu();
129 
130  wxMenuItem* busElement =
131  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_BUS, _("&Bus\tB"), _("Adds a bus at the circuit"));
132  // busElement->SetBitmap(wxArtProvider::GetBitmap(wxART_WARNING));
133  wxMenuItem* lineElement =
134  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_LINE, _("&Line\tL"), _("Adds a power line at the circuit"));
135  wxMenuItem* transformerElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_TRANSFORMER, _("&Transformer\tT"),
136  _("Adds a transformer at the circuit"));
137  wxMenuItem* generatorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_GENERATOR, _("&Generator\tG"),
138  _("Adds a generator at the circuit"));
139  wxMenuItem* indMotorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_INDMOTOR, _("&Induction motor\tI"),
140  _("Adds an induction motor at the circuit"));
141  wxMenuItem* syncCompElement =
142  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_SYNCCOMP, _("&Synchronous compensator \tK"),
143  _("Adds an induction motor at the circuit"));
144  wxMenuItem* loadElement =
145  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_LOAD, _("&Load\tShift-L"), _("Adds a load at the circuit"));
146  wxMenuItem* capacitorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_CAPACITOR, _("&Capacitor\tShift-C"),
147  _("Adds a shunt capacitor at the circuit"));
148  wxMenuItem* inductorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_INDUCTOR, _("&Inductor\tShift-I"),
149  _("Adds a shunt inductor at the circuit"));
150 
151  m_addElementsMenu->Append(busElement);
152  m_addElementsMenu->Append(lineElement);
153  m_addElementsMenu->Append(transformerElement);
154  m_addElementsMenu->Append(generatorElement);
155  m_addElementsMenu->Append(indMotorElement);
156  m_addElementsMenu->Append(syncCompElement);
157  m_addElementsMenu->Append(loadElement);
158  m_addElementsMenu->Append(capacitorElement);
159  m_addElementsMenu->Append(inductorElement);
160 
161  m_addElementsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnAddElementsClick, this);
162 }
163 
164 void MainFrame::OnNewClick(wxRibbonButtonBarEvent& event)
165 {
166  EnableCurrentProjectRibbon();
167 
168  Workspace* newWorkspace =
169  new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), this->GetStatusBar());
170  m_workspaceList.push_back(newWorkspace);
171 
172  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
173  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
174 
175  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
176  newWorkspace->Redraw();
177  m_projectNumber++;
178 }
179 
180 void MainFrame::OnAboutClick(wxRibbonButtonBarEvent& event)
181 {
182  AboutForm about(this);
183  about.ShowModal();
184 }
185 
186 void MainFrame::OnAddElementDropdown(wxRibbonButtonBarEvent& event) { event.PopupMenu(m_addElementsMenu); }
187 void MainFrame::OnChartsClick(wxRibbonButtonBarEvent& event)
188 {
189  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
190  std::vector<ElementPlotData> plotDataList;
191  auto elementList = workspace->GetElementList();
192  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
193  if(PowerElement* powerElement = dynamic_cast<PowerElement*>(*it)) {
194  ElementPlotData plotData;
195  if(powerElement->GetPlotData(plotData)) plotDataList.push_back(plotData);
196  }
197  }
198  ChartView* cView = new ChartView(workspace, plotDataList, workspace->GetStabilityTimeVector());
199  cView->Show();
200  }
201 }
202 
203 void MainFrame::OnCloseClick(wxRibbonButtonBarEvent& event) {}
204 void MainFrame::OnCopyClick(wxRibbonButtonBarEvent& event) {}
205 void MainFrame::OnDataReportClick(wxRibbonButtonBarEvent& event)
206 {
207  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
208  DataReport* dataReport = new DataReport(workspace, workspace);
209  dataReport->Show();
210  }
211 }
212 void MainFrame::OnDeleteClick(wxRibbonButtonBarEvent& event)
213 {
214  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
215  if(workspace) {
216  workspace->DeleteSelectedElements();
217  }
218 }
219 void MainFrame::OnDisableSolutionClick(wxRibbonButtonBarEvent& event)
220 {
221  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
222  workspace->SetContinuousCalculationActive(false);
223  }
224  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
225  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
226 }
227 
228 void MainFrame::OnDragClick(wxRibbonButtonBarEvent& event) {}
229 void MainFrame::OnEnableSolutionClick(wxRibbonButtonBarEvent& event)
230 {
231  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
232  workspace->SetContinuousCalculationActive(true);
233  workspace->RunStaticStudies();
234  }
235  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, true);
236  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, false);
237 }
238 
239 void MainFrame::OnExpImpClick(wxRibbonButtonBarEvent& event) {}
240 void MainFrame::OnFaultClick(wxRibbonButtonBarEvent& event)
241 {
242  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
243  workspace->RunFault();
244  }
245 }
246 
247 void MainFrame::OnFitClick(wxRibbonButtonBarEvent& event)
248 {
249  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
250  if(workspace) {
251  workspace->Fit();
252  }
253 }
254 
255 void MainFrame::OnMoveClick(wxRibbonButtonBarEvent& event)
256 {
257  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
258  if(workspace) {
259  auto elementList = workspace->GetAllElements();
260  // Calculate the average position of selected elements.
261  wxPoint2DDouble averagePos(0, 0);
262  int numSelElements = 0;
263  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
264  Element* element = *it;
265  if(element->IsSelected()) {
266  averagePos += element->GetPosition();
267  numSelElements++;
268  }
269  }
270  averagePos = wxPoint2DDouble(averagePos.m_x / double(numSelElements), averagePos.m_y / double(numSelElements));
271  // Set the move position to the average of selected elements.
272  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
273  Element* element = *it;
274  if(element->IsSelected()) {
275  element->StartMove(averagePos);
276  }
277  }
278  workspace->SetWorkspaceMode(Workspace::MODE_MOVE_ELEMENT);
279  }
280 }
281 
282 void MainFrame::OnOpenClick(wxRibbonButtonBarEvent& event)
283 {
284  wxFileDialog openFileDialog(this, _("Open PSP file"), "", "", "PSP files (*.psp)|*.psp",
285  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
286  if(openFileDialog.ShowModal() == wxID_CANCEL) return;
287 
288  wxFileName fileName(openFileDialog.GetPath());
289 
290  EnableCurrentProjectRibbon();
291  Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar());
292 
293  FileHanding fileHandling(newWorkspace);
294  if(fileHandling.OpenProject(fileName)) {
295  newWorkspace->SetSavedPath(fileName);
296 
297  m_workspaceList.push_back(newWorkspace);
298 
299  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
300  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
301 
302  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
303  m_auiNotebook->Layout();
304  newWorkspace->Redraw();
305  newWorkspace->SetJustOpened(true);
306  m_projectNumber++;
307  } else {
308  wxMessageDialog msgDialog(this, _("It was not possible to open the selected file."), _("Error"),
309  wxOK | wxCENTRE | wxICON_ERROR);
310  msgDialog.ShowModal();
311  delete newWorkspace;
312  }
313 }
314 
315 void MainFrame::OnPSPGuideClick(wxRibbonButtonBarEvent& event) {}
316 void MainFrame::OnPasteClick(wxRibbonButtonBarEvent& event) {}
317 void MainFrame::OnPowerFlowClick(wxRibbonButtonBarEvent& event)
318 {
319  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
320  if(workspace) {
321  workspace->RunPowerFlow();
322  }
323 }
324 
325 void MainFrame::OnRedoClick(wxRibbonButtonBarEvent& event) {}
326 void MainFrame::OnResetVoltagesClick(wxRibbonButtonBarEvent& event) {}
327 void MainFrame::OnRunStabilityClick(wxRibbonButtonBarEvent& event)
328 {
329  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
330  if(workspace) {
331  workspace->RunStability();
332  }
333 }
334 
335 void MainFrame::OnSCPowerClick(wxRibbonButtonBarEvent& event)
336 {
337  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
338  if(workspace) {
339  workspace->RunSCPower();
340  }
341 }
342 
343 void MainFrame::OnSaveAsClick(wxRibbonButtonBarEvent& event)
344 {
345  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
346  if(workspace) {
347  FileHanding fileHandling(workspace);
348 
349  wxFileDialog saveFileDialog(this, _("Save PSP file"), "", "", "PSP files (*.psp)|*.psp",
350  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
351  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
352 
353  fileHandling.SaveProject(saveFileDialog.GetPath());
354  wxFileName fileName(saveFileDialog.GetPath());
355  workspace->SetName(fileName.GetName());
356  m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(workspace), workspace->GetName());
357  workspace->SetSavedPath(fileName);
358  }
359 }
360 
361 void MainFrame::OnSaveClick(wxRibbonButtonBarEvent& event)
362 {
363  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
364  if(workspace) {
365  FileHanding fileHandling(workspace);
366 
367  if(workspace->GetSavedPath().IsOk()) {
368  fileHandling.SaveProject(workspace->GetSavedPath());
369  } else {
370  wxFileDialog saveFileDialog(this, _("Save PSP file"), "", "", "PSP files (*.psp)|*.psp",
371  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
372  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
373 
374  fileHandling.SaveProject(saveFileDialog.GetPath());
375  wxFileName fileName(saveFileDialog.GetPath());
376  workspace->SetName(fileName.GetName());
377  m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(workspace), workspace->GetName());
378  workspace->SetSavedPath(fileName);
379  }
380  }
381 }
382 
383 void MainFrame::OnSnapshotClick(wxRibbonButtonBarEvent& event) {}
384 void MainFrame::OnUndoClick(wxRibbonButtonBarEvent& event) {}
385 void MainFrame::OnAddElementsClick(wxCommandEvent& event)
386 {
387  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
388 
389  if(workspace) {
390  if(workspace->GetWorkspaceMode() != Workspace::MODE_INSERT) {
391  auto elementList = workspace->GetElementList();
392  wxString statusBarText = "";
393  bool newElement = false;
394 
395  switch(event.GetId()) {
396  case ID_ADDMENU_BUS: {
397  Bus* newBus = new Bus(wxPoint2DDouble(0, 0),
398  wxString::Format(_("Bus %d"), workspace->GetElementNumber(ID_BUS)));
399  workspace->IncrementElementNumber(ID_BUS);
400  elementList.push_back(newBus);
401  statusBarText = _("Insert Bus: Click to insert, ESC to cancel.");
402  newElement = true;
403  } break;
404  case ID_ADDMENU_LINE: {
405  Line* newLine = new Line(wxString::Format(_("Line %d"), workspace->GetElementNumber(ID_LINE)));
406  elementList.push_back(newLine);
407  workspace->IncrementElementNumber(ID_LINE);
408  statusBarText = _("Insert Line: Click on two buses, ESC to cancel.");
409  newElement = true;
410  } break;
411  case ID_ADDMENU_TRANSFORMER: {
412  Transformer* newTransformer = new Transformer(
413  wxString::Format(_("Transformer %d"), workspace->GetElementNumber(ID_TRANSFORMER)));
414  workspace->IncrementElementNumber(ID_TRANSFORMER);
415  elementList.push_back(newTransformer);
416  statusBarText = _("Insert Transformer: Click on two buses, ESC to cancel.");
417  newElement = true;
418  } break;
419  case ID_ADDMENU_GENERATOR: {
420  SyncGenerator* newGenerator = new SyncGenerator(
421  wxString::Format(_("Generator %d"), workspace->GetElementNumber(ID_SYNCGENERATOR)));
422  workspace->IncrementElementNumber(ID_SYNCGENERATOR);
423  elementList.push_back(newGenerator);
424  statusBarText = _("Insert Generator: Click on a buses, ESC to cancel.");
425  newElement = true;
426  } break;
427  case ID_ADDMENU_LOAD: {
428  Load* newLoad = new Load(wxString::Format(_("Load %d"), workspace->GetElementNumber(ID_LOAD)));
429  workspace->IncrementElementNumber(ID_LOAD);
430  elementList.push_back(newLoad);
431  statusBarText = _("Insert Load: Click on a buses, ESC to cancel.");
432  newElement = true;
433  } break;
434  case ID_ADDMENU_CAPACITOR: {
435  Capacitor* newCapacitor =
436  new Capacitor(wxString::Format(_("Capacitor %d"), workspace->GetElementNumber(ID_CAPACITOR)));
437  workspace->IncrementElementNumber(ID_CAPACITOR);
438  elementList.push_back(newCapacitor);
439  statusBarText = _("Insert Capacitor: Click on a buses, ESC to cancel.");
440  newElement = true;
441  } break;
442  case ID_ADDMENU_INDUCTOR: {
443  Inductor* newInductor =
444  new Inductor(wxString::Format(_("Inductor %d"), workspace->GetElementNumber(ID_INDUCTOR)));
445  workspace->IncrementElementNumber(ID_INDUCTOR);
446  elementList.push_back(newInductor);
447  statusBarText = _("Insert Inductor: Click on a buses, ESC to cancel.");
448  newElement = true;
449  } break;
450  case ID_ADDMENU_INDMOTOR: {
451  IndMotor* newIndMotor = new IndMotor(
452  wxString::Format(_("Induction motor %d"), workspace->GetElementNumber(ID_INDMOTOR)));
453  workspace->IncrementElementNumber(ID_INDMOTOR);
454  elementList.push_back(newIndMotor);
455  statusBarText = _("Insert Induction Motor: Click on a buses, ESC to cancel.");
456  newElement = true;
457  } break;
458  case ID_ADDMENU_SYNCCOMP: {
459  SyncMotor* newSyncCondenser = new SyncMotor(
460  wxString::Format(_("Synchronous condenser %d"), workspace->GetElementNumber(ID_SYNCMOTOR)));
461  workspace->IncrementElementNumber(ID_SYNCMOTOR);
462  elementList.push_back(newSyncCondenser);
463  statusBarText = _("Insert Synchronous Condenser: Click on a buses, ESC to cancel.");
464  newElement = true;
465  } break;
466  }
467  if(newElement) {
468  workspace->SetElementList(elementList);
469  workspace->SetWorkspaceMode(Workspace::MODE_INSERT);
470  workspace->SetStatusBarText(statusBarText);
471  workspace->Redraw();
472  }
473  }
474  }
475 }
476 void MainFrame::NotebookPageClosed(wxAuiNotebookEvent& event)
477 {
478  if(m_auiNotebook->GetPageCount() == 0) EnableCurrentProjectRibbon(false);
479 }
480 
481 void MainFrame::NotebookPageClosing(wxAuiNotebookEvent& event)
482 {
483  auto it = m_workspaceList.begin();
484  while(it != m_workspaceList.end()) {
485  if(*it == m_auiNotebook->GetCurrentPage()) {
486  m_workspaceList.erase(it);
487  break;
488  }
489  it++;
490  }
491  event.Skip();
492 }
493 
494 void MainFrame::OnRotClockClick(wxRibbonButtonBarEvent& event)
495 {
496  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
497  if(workspace) {
498  workspace->RotateSelectedElements();
499  }
500 }
501 
502 void MainFrame::OnRotCounterClockClick(wxRibbonButtonBarEvent& event)
503 {
504  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
505  if(workspace) {
506  workspace->RotateSelectedElements(false);
507  }
508 }
509 
510 void MainFrame::OnGeneralSettingsClick(wxRibbonButtonBarEvent& event)
511 {
512  GeneralPropertiesForm genPropForm(this, m_generalProperties);
513  genPropForm.SetInitialSize();
514  genPropForm.ShowModal();
515 }
516 
517 void MainFrame::OnSimulationSettingsClick(wxRibbonButtonBarEvent& event)
518 {
519  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
520  if(workspace) {
521  SimulationsSettingsForm simulSettingsForm(this, workspace->GetProperties());
522  simulSettingsForm.SetInitialSize();
523  simulSettingsForm.ShowModal();
524  }
525 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "MainFrame.h"
19 #include "ArtMetro.h"
20 #include "Workspace.h"
21 #include "Bus.h"
22 #include "Line.h"
23 #include "Transformer.h"
24 #include "SyncGenerator.h"
25 #include "IndMotor.h"
26 #include "SyncMotor.h"
27 #include "Load.h"
28 #include "Inductor.h"
29 #include "Capacitor.h"
30 #include "FileHanding.h"
31 #include "GeneralPropertiesForm.h"
33 #include "PropertiesData.h"
34 #include "ChartView.h"
35 #include "DataReport.h"
36 #include "AboutForm.h"
37 
39 MainFrame::MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initProperties, wxString openPath)
40  : MainFrameBase(parent)
41 {
42  m_locale = locale;
43  m_generalProperties = initProperties;
44 
45  Init();
46 
47  if(openPath != "") {
48  EnableCurrentProjectRibbon();
49  Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar());
50 
51  FileHanding fileHandling(newWorkspace);
52  if(fileHandling.OpenProject(openPath)) {
53  newWorkspace->SetSavedPath(openPath);
54 
55  m_workspaceList.push_back(newWorkspace);
56 
57  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
58  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
59 
60  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
61  m_auiNotebook->Layout();
62  newWorkspace->Redraw();
63  newWorkspace->SetJustOpened(true);
64  m_projectNumber++;
65  }
66  }
67 }
68 
70 {
71  // if(m_artMetro) delete m_artMetro;
72  if(m_addElementsMenu) {
73  m_addElementsMenu->Disconnect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::OnAddElementsClick),
74  NULL, this);
75  delete m_addElementsMenu;
76  }
77  if(m_locale) delete m_locale;
78  if(m_generalProperties) delete m_generalProperties;
79 }
80 
81 void MainFrame::Init()
82 {
83  this->SetSize(800, 600);
84 
85  CreateAddElementsMenu();
86 
87  EnableCurrentProjectRibbon(false);
88 
89  m_artMetro = new wxRibbonMetroArtProvider();
90  m_ribbonBar->SetArtProvider(m_artMetro);
91  m_ribbonBar->Realize();
92 
93  this->Layout();
94 }
95 
96 void MainFrame::EnableCurrentProjectRibbon(bool enable)
97 {
98  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ADDELEMENT, enable);
99  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_CHARTS, enable);
100  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_CLOSE, enable);
101  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_COPY, enable);
102  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_DATAREPORT, enable);
103  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_DELETE, enable);
104  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_DISABLESOL, enable);
105  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_DRAG, enable);
106  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_ENABLESOL, enable);
107  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_FAULT, enable);
108  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_FIT, enable);
109  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_MOVE, enable);
110  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_PASTE, enable);
111  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_POWERFLOW, enable);
112  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_REDO, enable);
113  m_ribbonButtonBarContinuous->EnableButton(ID_RIBBON_RESETVOLT, enable);
114  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_RUNSTAB, enable);
115  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_SAVE, enable);
116  m_ribbonButtonBarCProject->EnableButton(ID_RIBBON_SAVEAS, enable);
117  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_SCPOWER, enable);
118  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_PROJSETTINGS, enable);
119  m_ribbonButtonBarReports->EnableButton(ID_RIBBON_SNAPSHOT, enable);
120  m_ribbonButtonBarSimulations->EnableButton(ID_RIBBON_SIMULSETTINGS, enable);
121  m_ribbonButtonBarClipboard->EnableButton(ID_RIBBON_UNDO, enable);
122  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ROTATEC, enable);
123  m_ribbonButtonBarCircuit->EnableButton(ID_RIBBON_ROTATECC, enable);
124 }
125 
126 void MainFrame::CreateAddElementsMenu()
127 {
128  m_addElementsMenu = new wxMenu();
129 
130  wxMenuItem* busElement =
131  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_BUS, _("&Bus\tB"), _("Adds a bus at the circuit"));
132  // busElement->SetBitmap(wxArtProvider::GetBitmap(wxART_WARNING));
133  wxMenuItem* lineElement =
134  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_LINE, _("&Line\tL"), _("Adds a power line at the circuit"));
135  wxMenuItem* transformerElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_TRANSFORMER, _("&Transformer\tT"),
136  _("Adds a transformer at the circuit"));
137  wxMenuItem* generatorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_GENERATOR, _("&Generator\tG"),
138  _("Adds a generator at the circuit"));
139  wxMenuItem* indMotorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_INDMOTOR, _("&Induction motor\tI"),
140  _("Adds an induction motor at the circuit"));
141  wxMenuItem* syncCompElement =
142  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_SYNCCOMP, _("&Synchronous compensator \tK"),
143  _("Adds an induction motor at the circuit"));
144  wxMenuItem* loadElement =
145  new wxMenuItem(m_addElementsMenu, ID_ADDMENU_LOAD, _("&Load\tShift-L"), _("Adds a load at the circuit"));
146  wxMenuItem* capacitorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_CAPACITOR, _("&Capacitor\tShift-C"),
147  _("Adds a shunt capacitor at the circuit"));
148  wxMenuItem* inductorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_INDUCTOR, _("&Inductor\tShift-I"),
149  _("Adds a shunt inductor at the circuit"));
150 
151  m_addElementsMenu->Append(busElement);
152  m_addElementsMenu->Append(lineElement);
153  m_addElementsMenu->Append(transformerElement);
154  m_addElementsMenu->Append(generatorElement);
155  m_addElementsMenu->Append(indMotorElement);
156  m_addElementsMenu->Append(syncCompElement);
157  m_addElementsMenu->Append(loadElement);
158  m_addElementsMenu->Append(capacitorElement);
159  m_addElementsMenu->Append(inductorElement);
160 
161  m_addElementsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnAddElementsClick, this);
162 }
163 
164 void MainFrame::OnNewClick(wxRibbonButtonBarEvent& event)
165 {
166  EnableCurrentProjectRibbon();
167 
168  Workspace* newWorkspace =
169  new Workspace(this, wxString::Format(_("New project %d"), m_projectNumber), this->GetStatusBar());
170  m_workspaceList.push_back(newWorkspace);
171 
172  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
173  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
174 
175  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
176  newWorkspace->Redraw();
177  m_projectNumber++;
178 }
179 
180 void MainFrame::OnAboutClick(wxRibbonButtonBarEvent& event)
181 {
182  AboutForm about(this);
183  about.ShowModal();
184 }
185 
186 void MainFrame::OnAddElementDropdown(wxRibbonButtonBarEvent& event) { event.PopupMenu(m_addElementsMenu); }
187 void MainFrame::OnChartsClick(wxRibbonButtonBarEvent& event)
188 {
189  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
190  std::vector<ElementPlotData> plotDataList;
191  auto elementList = workspace->GetElementList();
192  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
193  if(PowerElement* powerElement = dynamic_cast<PowerElement*>(*it)) {
194  ElementPlotData plotData;
195  if(powerElement->GetPlotData(plotData)) plotDataList.push_back(plotData);
196  }
197  }
198  ChartView* cView = new ChartView(workspace, plotDataList, workspace->GetStabilityTimeVector());
199  cView->Show();
200  }
201 }
202 
203 void MainFrame::OnCloseClick(wxRibbonButtonBarEvent& event) {}
204 void MainFrame::OnCopyClick(wxRibbonButtonBarEvent& event) {}
205 void MainFrame::OnDataReportClick(wxRibbonButtonBarEvent& event)
206 {
207  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
208  DataReport* dataReport = new DataReport(workspace, workspace);
209  dataReport->Show();
210  }
211 }
212 void MainFrame::OnDeleteClick(wxRibbonButtonBarEvent& event)
213 {
214  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
215  if(workspace) {
216  workspace->DeleteSelectedElements();
217  }
218 }
219 void MainFrame::OnDisableSolutionClick(wxRibbonButtonBarEvent& event)
220 {
221  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
222  workspace->SetContinuousCalculationActive(false);
223  }
224  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
225  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
226 }
227 
228 void MainFrame::OnDragClick(wxRibbonButtonBarEvent& event) {}
229 void MainFrame::OnEnableSolutionClick(wxRibbonButtonBarEvent& event)
230 {
231  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
232  workspace->SetContinuousCalculationActive(true);
233  workspace->RunStaticStudies();
234  }
235  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, true);
236  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, false);
237 }
238 
239 void MainFrame::OnExpImpClick(wxRibbonButtonBarEvent& event) {}
240 void MainFrame::OnFaultClick(wxRibbonButtonBarEvent& event)
241 {
242  if(Workspace* workspace = dynamic_cast<Workspace*>(m_auiNotebook->GetCurrentPage())) {
243  workspace->RunFault();
244  }
245 }
246 
247 void MainFrame::OnFitClick(wxRibbonButtonBarEvent& event)
248 {
249  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
250  if(workspace) {
251  workspace->Fit();
252  }
253 }
254 
255 void MainFrame::OnMoveClick(wxRibbonButtonBarEvent& event)
256 {
257  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
258  if(workspace) {
259  auto elementList = workspace->GetAllElements();
260  // Calculate the average position of selected elements.
261  wxPoint2DDouble averagePos(0, 0);
262  int numSelElements = 0;
263  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
264  Element* element = *it;
265  if(element->IsSelected()) {
266  averagePos += element->GetPosition();
267  numSelElements++;
268  }
269  }
270  averagePos = wxPoint2DDouble(averagePos.m_x / double(numSelElements), averagePos.m_y / double(numSelElements));
271  // Set the move position to the average of selected elements.
272  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
273  Element* element = *it;
274  if(element->IsSelected()) {
275  element->StartMove(averagePos);
276  }
277  }
278  workspace->SetWorkspaceMode(Workspace::MODE_MOVE_ELEMENT);
279  }
280 }
281 
282 void MainFrame::OnOpenClick(wxRibbonButtonBarEvent& event)
283 {
284  wxFileDialog openFileDialog(this, _("Open PSP file"), "", "", "PSP files (*.psp)|*.psp",
285  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
286  if(openFileDialog.ShowModal() == wxID_CANCEL) return;
287 
288  wxFileName fileName(openFileDialog.GetPath());
289 
290  EnableCurrentProjectRibbon();
291  Workspace* newWorkspace = new Workspace(this, _("Open project"), this->GetStatusBar());
292 
293  FileHanding fileHandling(newWorkspace);
294  if(fileHandling.OpenProject(fileName)) {
295  newWorkspace->SetSavedPath(fileName);
296 
297  m_workspaceList.push_back(newWorkspace);
298 
299  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_DISABLESOL, true);
300  m_ribbonButtonBarContinuous->ToggleButton(ID_RIBBON_ENABLESOL, false);
301 
302  m_auiNotebook->AddPage(newWorkspace, newWorkspace->GetName(), true);
303  m_auiNotebook->Layout();
304  newWorkspace->Redraw();
305  newWorkspace->SetJustOpened(true);
306  m_projectNumber++;
307  } else {
308  wxMessageDialog msgDialog(this, _("It was not possible to open the selected file."), _("Error"),
309  wxOK | wxCENTRE | wxICON_ERROR);
310  msgDialog.ShowModal();
311  delete newWorkspace;
312  }
313 }
314 
315 void MainFrame::OnPSPGuideClick(wxRibbonButtonBarEvent& event) {}
316 void MainFrame::OnPasteClick(wxRibbonButtonBarEvent& event) {}
317 void MainFrame::OnPowerFlowClick(wxRibbonButtonBarEvent& event)
318 {
319  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
320  if(workspace) {
321  workspace->RunPowerFlow();
322  }
323 }
324 
325 void MainFrame::OnRedoClick(wxRibbonButtonBarEvent& event) {}
326 void MainFrame::OnResetVoltagesClick(wxRibbonButtonBarEvent& event) {}
327 void MainFrame::OnRunStabilityClick(wxRibbonButtonBarEvent& event)
328 {
329  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
330  if(workspace) {
331  workspace->RunStability();
332  }
333 }
334 
335 void MainFrame::OnSCPowerClick(wxRibbonButtonBarEvent& event)
336 {
337  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
338  if(workspace) {
339  workspace->RunSCPower();
340  }
341 }
342 
343 void MainFrame::OnSaveAsClick(wxRibbonButtonBarEvent& event)
344 {
345  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
346  if(workspace) {
347  FileHanding fileHandling(workspace);
348 
349  wxFileDialog saveFileDialog(this, _("Save PSP file"), "", "", "PSP files (*.psp)|*.psp",
350  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
351  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
352 
353  fileHandling.SaveProject(saveFileDialog.GetPath());
354  wxFileName fileName(saveFileDialog.GetPath());
355  workspace->SetName(fileName.GetName());
356  m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(workspace), workspace->GetName());
357  workspace->SetSavedPath(fileName);
358  }
359 }
360 
361 void MainFrame::OnSaveClick(wxRibbonButtonBarEvent& event)
362 {
363  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
364  if(workspace) {
365  FileHanding fileHandling(workspace);
366 
367  if(workspace->GetSavedPath().IsOk()) {
368  fileHandling.SaveProject(workspace->GetSavedPath());
369  } else {
370  wxFileDialog saveFileDialog(this, _("Save PSP file"), "", "", "PSP files (*.psp)|*.psp",
371  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
372  if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
373 
374  fileHandling.SaveProject(saveFileDialog.GetPath());
375  wxFileName fileName(saveFileDialog.GetPath());
376  workspace->SetName(fileName.GetName());
377  m_auiNotebook->SetPageText(m_auiNotebook->GetPageIndex(workspace), workspace->GetName());
378  workspace->SetSavedPath(fileName);
379  }
380  }
381 }
382 
383 void MainFrame::OnSnapshotClick(wxRibbonButtonBarEvent& event) {}
384 void MainFrame::OnUndoClick(wxRibbonButtonBarEvent& event) {}
385 void MainFrame::OnAddElementsClick(wxCommandEvent& event)
386 {
387  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
388 
389  if(workspace) {
390  if(workspace->GetWorkspaceMode() != Workspace::MODE_INSERT) {
391  auto elementList = workspace->GetElementList();
392  wxString statusBarText = "";
393  bool newElement = false;
394 
395  switch(event.GetId()) {
396  case ID_ADDMENU_BUS: {
397  Bus* newBus = new Bus(wxPoint2DDouble(0, 0),
398  wxString::Format(_("Bus %d"), workspace->GetElementNumber(ID_BUS)));
399  workspace->IncrementElementNumber(ID_BUS);
400  elementList.push_back(newBus);
401  statusBarText = _("Insert Bus: Click to insert, ESC to cancel.");
402  newElement = true;
403  } break;
404  case ID_ADDMENU_LINE: {
405  Line* newLine = new Line(wxString::Format(_("Line %d"), workspace->GetElementNumber(ID_LINE)));
406  elementList.push_back(newLine);
407  workspace->IncrementElementNumber(ID_LINE);
408  statusBarText = _("Insert Line: Click on two buses, ESC to cancel.");
409  newElement = true;
410  } break;
411  case ID_ADDMENU_TRANSFORMER: {
412  Transformer* newTransformer = new Transformer(
413  wxString::Format(_("Transformer %d"), workspace->GetElementNumber(ID_TRANSFORMER)));
414  workspace->IncrementElementNumber(ID_TRANSFORMER);
415  elementList.push_back(newTransformer);
416  statusBarText = _("Insert Transformer: Click on two buses, ESC to cancel.");
417  newElement = true;
418  } break;
419  case ID_ADDMENU_GENERATOR: {
420  SyncGenerator* newGenerator = new SyncGenerator(
421  wxString::Format(_("Generator %d"), workspace->GetElementNumber(ID_SYNCGENERATOR)));
422  workspace->IncrementElementNumber(ID_SYNCGENERATOR);
423  elementList.push_back(newGenerator);
424  statusBarText = _("Insert Generator: Click on a buses, ESC to cancel.");
425  newElement = true;
426  } break;
427  case ID_ADDMENU_LOAD: {
428  Load* newLoad = new Load(wxString::Format(_("Load %d"), workspace->GetElementNumber(ID_LOAD)));
429  workspace->IncrementElementNumber(ID_LOAD);
430  elementList.push_back(newLoad);
431  statusBarText = _("Insert Load: Click on a buses, ESC to cancel.");
432  newElement = true;
433  } break;
434  case ID_ADDMENU_CAPACITOR: {
435  Capacitor* newCapacitor =
436  new Capacitor(wxString::Format(_("Capacitor %d"), workspace->GetElementNumber(ID_CAPACITOR)));
437  workspace->IncrementElementNumber(ID_CAPACITOR);
438  elementList.push_back(newCapacitor);
439  statusBarText = _("Insert Capacitor: Click on a buses, ESC to cancel.");
440  newElement = true;
441  } break;
442  case ID_ADDMENU_INDUCTOR: {
443  Inductor* newInductor =
444  new Inductor(wxString::Format(_("Inductor %d"), workspace->GetElementNumber(ID_INDUCTOR)));
445  workspace->IncrementElementNumber(ID_INDUCTOR);
446  elementList.push_back(newInductor);
447  statusBarText = _("Insert Inductor: Click on a buses, ESC to cancel.");
448  newElement = true;
449  } break;
450  case ID_ADDMENU_INDMOTOR: {
451  IndMotor* newIndMotor = new IndMotor(
452  wxString::Format(_("Induction motor %d"), workspace->GetElementNumber(ID_INDMOTOR)));
453  workspace->IncrementElementNumber(ID_INDMOTOR);
454  elementList.push_back(newIndMotor);
455  statusBarText = _("Insert Induction Motor: Click on a buses, ESC to cancel.");
456  newElement = true;
457  } break;
458  case ID_ADDMENU_SYNCCOMP: {
459  SyncMotor* newSyncCondenser = new SyncMotor(
460  wxString::Format(_("Synchronous condenser %d"), workspace->GetElementNumber(ID_SYNCMOTOR)));
461  workspace->IncrementElementNumber(ID_SYNCMOTOR);
462  elementList.push_back(newSyncCondenser);
463  statusBarText = _("Insert Synchronous Condenser: Click on a buses, ESC to cancel.");
464  newElement = true;
465  } break;
466  }
467  if(newElement) {
468  workspace->SetElementList(elementList);
469  workspace->SetWorkspaceMode(Workspace::MODE_INSERT);
470  workspace->SetStatusBarText(statusBarText);
471  workspace->Redraw();
472  }
473  }
474  }
475 }
476 void MainFrame::NotebookPageClosed(wxAuiNotebookEvent& event)
477 {
478  if(m_auiNotebook->GetPageCount() == 0) EnableCurrentProjectRibbon(false);
479 }
480 
481 void MainFrame::NotebookPageClosing(wxAuiNotebookEvent& event)
482 {
483  auto it = m_workspaceList.begin();
484  while(it != m_workspaceList.end()) {
485  if(*it == m_auiNotebook->GetCurrentPage()) {
486  m_workspaceList.erase(it);
487  break;
488  }
489  it++;
490  }
491  event.Skip();
492 }
493 
494 void MainFrame::OnRotClockClick(wxRibbonButtonBarEvent& event)
495 {
496  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
497  if(workspace) {
498  workspace->RotateSelectedElements();
499  }
500 }
501 
502 void MainFrame::OnRotCounterClockClick(wxRibbonButtonBarEvent& event)
503 {
504  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
505  if(workspace) {
506  workspace->RotateSelectedElements(false);
507  }
508 }
509 
510 void MainFrame::OnGeneralSettingsClick(wxRibbonButtonBarEvent& event)
511 {
512  GeneralPropertiesForm genPropForm(this, m_generalProperties);
513  genPropForm.SetInitialSize();
514  genPropForm.ShowModal();
515 }
516 
517 void MainFrame::OnSimulationSettingsClick(wxRibbonButtonBarEvent& event)
518 {
519  Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
520  if(workspace) {
521  SimulationsSettingsForm simulSettingsForm(this, workspace->GetProperties());
522  simulSettingsForm.SetInitialSize();
523  simulSettingsForm.ShowModal();
524  }
525 }
General and simulation data manager.
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+ +
~MainFrame()
Default destructor.
Definition: MainFrame.cpp:69
@@ -99,30 +101,38 @@ $(document).ready(function(){initNavTree('_main_frame_8cpp_source.html','');});
MainFrame()
Default constructor.
Definition: MainFrame.cpp:38
Save and opens the projects created on disk.
Definition: FileHanding.h:43
Form to edit the software&#39;s general data.
+ - -
Definition: Bus.h:62
- +
Synchronous generator power element.
+ + +
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
+ + + + -
Definition: Line.h:52
+
Power line element.
Definition: Line.h:59
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
Form to edit the simulation data.
- +
Induction motor power element.
Definition: IndMotor.h:40
bool IsSelected() const
Checks if the element is selected.
Definition: Element.h:202
+ - +
Shunt capactior power element.
Definition: Capacitor.h:38
Form that shows the results of power flow and fault calculations.
Definition: DataReport.h:33
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Element.cpp:117
- +
Abstract class of power elements.
Definition: PowerElement.h:117
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
- +
Inductor shunt power element.
Definition: Inductor.h:38
Form to show some informations.
Definition: AboutForm.h:32
+
This class manages the graphical and power elements. It is responsible for handling the user&#39;s intera...
Definition: Workspace.h:81
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_main_frame_8h_source.html b/docs/doxygen/html/_main_frame_8h_source.html index 2396190..3ac55b9 100644 --- a/docs/doxygen/html/_main_frame_8h_source.html +++ b/docs/doxygen/html/_main_frame_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_main_frame_8h_source.html','');});
MainFrame.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MAINFRAME_H
19 #define MAINFRAME_H
20 
21 #include <wx/menu.h>
22 #include <wx/msgdlg.h>
23 #include <wx/filedlg.h>
24 
25 #include "MainFrameBase.h"
26 
27 class MainFrameBase;
29 class Workspace;
30 class FileHanding;
33 class PropertiesData;
34 class ChartView;
35 class DataReport;
36 class AboutForm;
37 
38 enum {
39  ID_ADDMENU_BUS = 20000,
40  ID_ADDMENU_LINE,
41  ID_ADDMENU_TRANSFORMER,
42  ID_ADDMENU_GENERATOR,
43  ID_ADDMENU_LOAD,
44  ID_ADDMENU_CAPACITOR,
45  ID_ADDMENU_INDUCTOR,
46  ID_ADDMENU_INDMOTOR,
47  ID_ADDMENU_SYNCCOMP
48 };
49 
57 class MainFrame : public MainFrameBase
58 {
59  public:
64  MainFrame();
71  MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initProperties, wxString openPath = "");
72 
76  ~MainFrame();
77 
78  protected:
79  virtual void OnGeneralSettingsClick(wxRibbonButtonBarEvent& event);
80  virtual void OnSimulationSettingsClick(wxRibbonButtonBarEvent& event);
81  virtual void OnRotClockClick(wxRibbonButtonBarEvent& event);
82  virtual void OnRotCounterClockClick(wxRibbonButtonBarEvent& event);
83  virtual void NotebookPageClosed(wxAuiNotebookEvent& event);
84  virtual void NotebookPageClosing(wxAuiNotebookEvent& event);
85  virtual void OnAboutClick(wxRibbonButtonBarEvent& event);
86  virtual void OnAddElementDropdown(wxRibbonButtonBarEvent& event);
87  virtual void OnChartsClick(wxRibbonButtonBarEvent& event);
88  virtual void OnCloseClick(wxRibbonButtonBarEvent& event);
89  virtual void OnCopyClick(wxRibbonButtonBarEvent& event);
90  virtual void OnDataReportClick(wxRibbonButtonBarEvent& event);
91  virtual void OnDeleteClick(wxRibbonButtonBarEvent& event);
92  virtual void OnDisableSolutionClick(wxRibbonButtonBarEvent& event);
93  virtual void OnDragClick(wxRibbonButtonBarEvent& event);
94  virtual void OnEnableSolutionClick(wxRibbonButtonBarEvent& event);
95  virtual void OnExitClick(wxRibbonButtonBarEvent& event) { this->Close(); };
96  virtual void OnExpImpClick(wxRibbonButtonBarEvent& event);
97  virtual void OnFaultClick(wxRibbonButtonBarEvent& event);
98  virtual void OnFitClick(wxRibbonButtonBarEvent& event);
99  virtual void OnMoveClick(wxRibbonButtonBarEvent& event);
100  virtual void OnOpenClick(wxRibbonButtonBarEvent& event);
101  virtual void OnPSPGuideClick(wxRibbonButtonBarEvent& event);
102  virtual void OnPasteClick(wxRibbonButtonBarEvent& event);
103  virtual void OnPowerFlowClick(wxRibbonButtonBarEvent& event);
104  virtual void OnRedoClick(wxRibbonButtonBarEvent& event);
105  virtual void OnResetVoltagesClick(wxRibbonButtonBarEvent& event);
106  virtual void OnRunStabilityClick(wxRibbonButtonBarEvent& event);
107  virtual void OnSCPowerClick(wxRibbonButtonBarEvent& event);
108  virtual void OnSaveAsClick(wxRibbonButtonBarEvent& event);
109  virtual void OnSaveClick(wxRibbonButtonBarEvent& event);
110  virtual void OnSnapshotClick(wxRibbonButtonBarEvent& event);
111  virtual void OnUndoClick(wxRibbonButtonBarEvent& event);
112  virtual void OnNewClick(wxRibbonButtonBarEvent& event);
113 
114  std::vector<Workspace*> m_workspaceList;
115  int m_projectNumber = 1;
116 
117  wxRibbonMetroArtProvider* m_artMetro = NULL;
118  wxMenu* m_addElementsMenu = NULL;
119  wxLocale* m_locale = NULL;
120  PropertiesData* m_generalProperties = NULL;
121 
122  void Init();
123  void EnableCurrentProjectRibbon(bool enable = true);
124  void CreateAddElementsMenu();
125 
126  void OnAddElementsClick(wxCommandEvent& event);
127 };
128 
129 #endif // MAINFRAME_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MAINFRAME_H
19 #define MAINFRAME_H
20 
21 #include <wx/menu.h>
22 #include <wx/msgdlg.h>
23 #include <wx/filedlg.h>
24 
25 #include "MainFrameBase.h"
26 
27 class MainFrameBase;
29 class Workspace;
30 class FileHanding;
33 class PropertiesData;
34 class ChartView;
35 class DataReport;
36 class AboutForm;
37 
38 enum {
39  ID_ADDMENU_BUS = 20000,
40  ID_ADDMENU_LINE,
41  ID_ADDMENU_TRANSFORMER,
42  ID_ADDMENU_GENERATOR,
43  ID_ADDMENU_LOAD,
44  ID_ADDMENU_CAPACITOR,
45  ID_ADDMENU_INDUCTOR,
46  ID_ADDMENU_INDMOTOR,
47  ID_ADDMENU_SYNCCOMP
48 };
49 
57 class MainFrame : public MainFrameBase
58 {
59  public:
64  MainFrame();
71  MainFrame(wxWindow* parent, wxLocale* locale, PropertiesData* initProperties, wxString openPath = "");
72 
76  ~MainFrame();
77 
78  protected:
79  virtual void OnGeneralSettingsClick(wxRibbonButtonBarEvent& event);
80  virtual void OnSimulationSettingsClick(wxRibbonButtonBarEvent& event);
81  virtual void OnRotClockClick(wxRibbonButtonBarEvent& event);
82  virtual void OnRotCounterClockClick(wxRibbonButtonBarEvent& event);
83  virtual void NotebookPageClosed(wxAuiNotebookEvent& event);
84  virtual void NotebookPageClosing(wxAuiNotebookEvent& event);
85  virtual void OnAboutClick(wxRibbonButtonBarEvent& event);
86  virtual void OnAddElementDropdown(wxRibbonButtonBarEvent& event);
87  virtual void OnChartsClick(wxRibbonButtonBarEvent& event);
88  virtual void OnCloseClick(wxRibbonButtonBarEvent& event);
89  virtual void OnCopyClick(wxRibbonButtonBarEvent& event);
90  virtual void OnDataReportClick(wxRibbonButtonBarEvent& event);
91  virtual void OnDeleteClick(wxRibbonButtonBarEvent& event);
92  virtual void OnDisableSolutionClick(wxRibbonButtonBarEvent& event);
93  virtual void OnDragClick(wxRibbonButtonBarEvent& event);
94  virtual void OnEnableSolutionClick(wxRibbonButtonBarEvent& event);
95  virtual void OnExitClick(wxRibbonButtonBarEvent& event) { this->Close(); };
96  virtual void OnExpImpClick(wxRibbonButtonBarEvent& event);
97  virtual void OnFaultClick(wxRibbonButtonBarEvent& event);
98  virtual void OnFitClick(wxRibbonButtonBarEvent& event);
99  virtual void OnMoveClick(wxRibbonButtonBarEvent& event);
100  virtual void OnOpenClick(wxRibbonButtonBarEvent& event);
101  virtual void OnPSPGuideClick(wxRibbonButtonBarEvent& event);
102  virtual void OnPasteClick(wxRibbonButtonBarEvent& event);
103  virtual void OnPowerFlowClick(wxRibbonButtonBarEvent& event);
104  virtual void OnRedoClick(wxRibbonButtonBarEvent& event);
105  virtual void OnResetVoltagesClick(wxRibbonButtonBarEvent& event);
106  virtual void OnRunStabilityClick(wxRibbonButtonBarEvent& event);
107  virtual void OnSCPowerClick(wxRibbonButtonBarEvent& event);
108  virtual void OnSaveAsClick(wxRibbonButtonBarEvent& event);
109  virtual void OnSaveClick(wxRibbonButtonBarEvent& event);
110  virtual void OnSnapshotClick(wxRibbonButtonBarEvent& event);
111  virtual void OnUndoClick(wxRibbonButtonBarEvent& event);
112  virtual void OnNewClick(wxRibbonButtonBarEvent& event);
113 
114  std::vector<Workspace*> m_workspaceList;
115  int m_projectNumber = 1;
116 
117  wxRibbonMetroArtProvider* m_artMetro = NULL;
118  wxMenu* m_addElementsMenu = NULL;
119  wxLocale* m_locale = NULL;
120  PropertiesData* m_generalProperties = NULL;
121 
122  void Init();
123  void EnableCurrentProjectRibbon(bool enable = true);
124  void CreateAddElementsMenu();
125 
126  void OnAddElementsClick(wxCommandEvent& event);
127 };
128 
129 #endif // MAINFRAME_H
General and simulation data manager.
~MainFrame()
Default destructor.
Definition: MainFrame.cpp:69
MainFrame()
Default constructor.
Definition: MainFrame.cpp:38
diff --git a/docs/doxygen/html/_multiplier_8cpp_source.html b/docs/doxygen/html/_multiplier_8cpp_source.html index f60bfff..ca5ebdd 100644 --- a/docs/doxygen/html/_multiplier_8cpp_source.html +++ b/docs/doxygen/html/_multiplier_8cpp_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_multiplier_8cpp_source.html','');});
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Multiplier.h"
19 #include "ConnectionLine.h"
20 
21 Multiplier::Multiplier(int id) : ControlElement(id)
22 {
23  m_width = m_height = 36.0;
24  Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-18, -9), Node::NODE_IN, m_borderSize);
25  nodeIn1->StartMove(m_position);
26  Node* nodeIn2 = new Node(m_position + wxPoint2DDouble(-18, 9), Node::NODE_IN, m_borderSize);
27  nodeIn2->StartMove(m_position);
28  Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
29  nodeOut->SetAngle(180.0);
30  nodeOut->StartMove(m_position);
31  m_nodeList.push_back(nodeIn1);
32  m_nodeList.push_back(nodeIn2);
33  m_nodeList.push_back(nodeOut);
34 }
35 
36 Multiplier::~Multiplier() {}
37 void Multiplier::Draw(wxPoint2DDouble translation, double scale) const
38 {
39  glLineWidth(1.0);
40  if(m_selected) {
41  glColor4dv(m_selectionColour.GetRGBA());
42  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
43  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
44  }
45  glColor4d(1.0, 1.0, 1.0, 1.0);
46  DrawRectangle(m_position, m_width, m_height);
47  glColor4d(0.0, 0.0, 0.0, 1.0);
48  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
49 
50  // Plot x.
51  glLineWidth(2.0);
52  std::vector<wxPoint2DDouble> xSymbol;
53  xSymbol.push_back(m_position + wxPoint2DDouble(-5, -5));
54  xSymbol.push_back(m_position + wxPoint2DDouble(5, 5));
55  xSymbol.push_back(m_position + wxPoint2DDouble(-5, 5));
56  xSymbol.push_back(m_position + wxPoint2DDouble(5, -5));
57  glColor4d(0.0, 0.3, 1.0, 1.0);
58  DrawLine(xSymbol, GL_LINES);
59 
60  glColor4d(0.0, 0.0, 0.0, 1.0);
61  DrawNodes();
62 }
63 
64 void Multiplier::Rotate(bool clockwise)
65 {
66  if(clockwise)
67  m_angle += 90.0;
68  else
69  m_angle -= 90.0;
70  if(m_angle >= 360.0)
71  m_angle = 0.0;
72  else if(m_angle < 0)
73  m_angle = 270.0;
74 
75  UpdatePoints();
76 
77  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
78  Node* node = *it;
79  node->Rotate(clockwise);
80  }
81 }
82 
83 void Multiplier::UpdatePoints()
84 {
85  if(m_angle == 0.0) {
86  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-18, -9));
87  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-18, 9));
88  m_nodeList[2]->SetPosition(m_position + wxPoint2DDouble(18, 0));
89  } else if(m_angle == 90.0) {
90  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(9, -18));
91  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-9, -18));
92  m_nodeList[2]->SetPosition(m_position + wxPoint2DDouble(0, 18));
93  } else if(m_angle == 180.0) {
94  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(18, 9));
95  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(18, -9));
96  m_nodeList[2]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
97  } else if(m_angle == 270.0) {
98  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-9, 18));
99  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(9, 18));
100  m_nodeList[2]->SetPosition(m_position + wxPoint2DDouble(0, -18));
101  }
102 }
103 
104 bool Multiplier::Solve(double input, double timeStep)
105 {
106  std::vector<double> inputVector;
107  for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
108  Node* node = *itN;
109  if(node->GetNodeType() != Node::NODE_OUT) {
110  if(!node->IsConnected()) {
111  inputVector.push_back(1.0);
112  } else {
113  for(auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
114  ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
115  auto nodeList = cLine->GetNodeList();
116  for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
117  Node* childNode = *itCN;
118  if(childNode == node) {
119  inputVector.push_back(cLine->GetValue());
120  break;
121  }
122  }
123  }
124  }
125  }
126  }
127 
128  m_output = 1.0;
129  for(unsigned int i = 0; i < inputVector.size(); ++i) {
130  m_output *= inputVector[i];
131  }
132 
133  return true;
134 }
135 
137 {
138  Multiplier* copy = new Multiplier(m_elementID);
139  *copy = *this;
140  return copy;
141 }
Multiplies two inputs.
Definition: Multiplier.h:32
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Multiplier.cpp:64
Node of a control element. This class manages the user interaction with the connection and control el...
diff --git a/docs/doxygen/html/_multiplier_8h_source.html b/docs/doxygen/html/_multiplier_8h_source.html index 7588220..befa79b 100644 --- a/docs/doxygen/html/_multiplier_8h_source.html +++ b/docs/doxygen/html/_multiplier_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_multiplier_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MULTIPLIER_H
19 #define MULTIPLIER_H
20 
21 #include "ControlElement.h"
22 
23 class ConnectionLine;
24 
32 class Multiplier : public ControlElement
33 {
34  public:
35  Multiplier(int id);
36  ~Multiplier();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
40  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
41  virtual bool ShowForm(wxWindow* parent, Element* element) { return false; }
42  virtual void Rotate(bool clockwise = true);
43 
44  virtual void UpdatePoints();
45 
46  virtual bool Solve(double input, double timeStep);
47 
48  virtual Element* GetCopy();
49 };
50 
51 #endif // MULTIPLIER_H
Multiplies two inputs.
Definition: Multiplier.h:32
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Multiplier.cpp:64
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Multiplier.h:41
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Multiplier.h:39
diff --git a/docs/doxygen/html/_power_element_8cpp_source.html b/docs/doxygen/html/_power_element_8cpp_source.html index 1ca65f6..bc7ca72 100644 --- a/docs/doxygen/html/_power_element_8cpp_source.html +++ b/docs/doxygen/html/_power_element_8cpp_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_power_element_8cpp_source.html','');}
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "PowerElement.h"
19 #ifdef USING_WX_3_0_X
20 #include "DegreesAndRadians.h"
21 #endif
22 
24 {
25  m_busColour.SetRGBA(0.0, 0.3, 1.0, 1.0);
26  m_onlineElementColour.SetRGBA(0.2, 0.2, 0.2, 1.0);
27  m_offlineElementColour.SetRGBA(0.5, 0.5, 0.5, 1.0);
28  m_closedSwitchColour.SetRGBA(0.0, 0.4, 0.0, 1.0);
29  m_openedSwitchColour.SetRGBA(1.0, 0.1, 0.1, 1.0);
30  m_powerFlowArrowColour.SetRGBA(1.0, 0.51, 0.0, 1.0);
31  m_dynamicEventColour.SetRGBA(1.0, 0.51, 0.0, 1.0);
32 }
33 
35 void PowerElement::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
36 {
37 }
38 
39 wxPoint2DDouble PowerElement::GetSwitchPoint(Element* parent,
40  wxPoint2DDouble parentPoint,
41  wxPoint2DDouble secondPoint) const
42 {
43  double swLineSize = 25.0;
44  wxPoint2DDouble swPoint = wxPoint2DDouble(parentPoint.m_x, parentPoint.m_y - swLineSize);
45 
46  // Rotate the second point (to compare).
47  double angle = parent->GetAngle();
48 
49  secondPoint =
50  wxPoint2DDouble(std::cos(wxDegToRad(-angle)) * (secondPoint.m_x - parentPoint.m_x) -
51  std::sin(wxDegToRad(-angle)) * (secondPoint.m_y - parentPoint.m_y) + parentPoint.m_x,
52  std::sin(wxDegToRad(-angle)) * (secondPoint.m_x - parentPoint.m_x) +
53  std::cos(wxDegToRad(-angle)) * (secondPoint.m_y - parentPoint.m_y) + parentPoint.m_y);
54 
55  // Rotate
56  if(secondPoint.m_y > parentPoint.m_y) angle -= 180.0;
57  return wxPoint2DDouble(std::cos(wxDegToRad(angle)) * (swPoint.m_x - parentPoint.m_x) -
58  std::sin(wxDegToRad(angle)) * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_x,
59  std::sin(wxDegToRad(angle)) * (swPoint.m_x - parentPoint.m_x) +
60  std::cos(wxDegToRad(angle)) * (swPoint.m_y - parentPoint.m_y) + parentPoint.m_y);
61 }
62 
63 bool PowerElement::SwitchesContains(wxPoint2DDouble position) const
64 {
65  for(int i = 0; i < (int)m_switchRect.size(); i++) {
66  if(m_parentList[i]) {
67  if(m_switchRect[i].Contains(position)) return true;
68  }
69  }
70  return false;
71 }
72 
74 {
75  // General method, to one switch only.
76  wxPoint2DDouble swCenter = wxPoint2DDouble((m_pointList[0].m_x + m_pointList[1].m_x) / 2.0,
77  (m_pointList[0].m_y + m_pointList[1].m_y) / 2.0);
78  m_switchRect[0] = wxRect2DDouble(swCenter.m_x - m_switchSize / 2.0, swCenter.m_y - m_switchSize / 2.0, m_switchSize,
79  m_switchSize);
80 }
81 
83 {
84  int i = 0;
85  for(auto it = m_parentList.begin(); it != m_parentList.end(); it++) {
86  Element* parent = *it;
87  if(parent) {
88  if(m_online) {
89  glColor4dv(m_closedSwitchColour.GetRGBA());
90  } else {
91  glColor4dv(m_openedSwitchColour.GetRGBA());
92  }
93 
94  glPushMatrix();
95  glTranslated(m_switchRect[i].GetPosition().m_x + m_switchSize / 2.0,
96  m_switchRect[i].GetPosition().m_y + m_switchSize / 2.0, 0.0);
97  glRotated(parent->GetAngle(), 0.0, 0.0, 1.0);
98  glTranslated(-m_switchRect[i].GetPosition().m_x - m_switchSize / 2.0,
99  -m_switchRect[i].GetPosition().m_y - m_switchSize / 2.0, 0.0);
100 
101  DrawRectangle(m_switchRect[i].GetPosition() + wxPoint2DDouble(m_switchSize / 2.0, m_switchSize / 2.0),
102  m_switchSize, m_switchSize);
103 
104  glPopMatrix();
105  }
106  i++;
107  }
108 }
109 
110 void PowerElement::CalculatePowerFlowPts(std::vector<wxPoint2DDouble> edges)
111 {
112  double arrowRate = 100.0; // One arrow to each "arrowRate" distance in pixels.
113 
114  if(edges.size() < 2) return;
115 
116  // Clear all power flow points
117  for(int i = 0; i < (int)m_powerFlowArrow.size(); i++) m_powerFlowArrow[i].clear();
118  m_powerFlowArrow.clear();
119 
120  for(int i = 1; i < (int)edges.size(); i++) {
121  wxPoint2DDouble pt1 = edges[i - 1];
122  wxPoint2DDouble pt2 = edges[i];
123 
124  double angle = std::atan2(pt2.m_y - pt1.m_y, pt2.m_x - pt1.m_x);
125 
126  wxPoint2DDouble rotPt2(
127  std::cos(-angle) * (pt2.m_x - pt1.m_x) - std::sin(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_x,
128  std::sin(-angle) * (pt2.m_x - pt1.m_x) + std::cos(-angle) * (pt2.m_y - pt1.m_y) + pt1.m_y);
129 
130  int numArrows = std::abs(pt1.m_x - rotPt2.m_x) / arrowRate;
131  if(numArrows == 0) numArrows = 1;
132 
133  for(int i = 0; i < numArrows; i++) {
134  wxPoint2DDouble arrowCenter(pt1.m_x + ((rotPt2.m_x - pt1.m_x) / double(numArrows + 1)) * double(i + 1),
135  pt1.m_y + ((rotPt2.m_y - pt1.m_y) / double(numArrows + 1)) * double(i + 1));
136 
137  std::vector<wxPoint2DDouble> triPts;
138  triPts.push_back(arrowCenter + wxPoint2DDouble(5.0, 0.0));
139  triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, 5.0));
140  triPts.push_back(arrowCenter + wxPoint2DDouble(-5.0, -5.0));
141 
142  // Rotate back.
143  for(int i = 0; i < 3; i++) {
144  triPts[i] = wxPoint2DDouble(
145  std::cos(angle) * (triPts[i].m_x - pt1.m_x) - std::sin(angle) * (triPts[i].m_y - pt1.m_y) + pt1.m_x,
146  std::sin(angle) * (triPts[i].m_x - pt1.m_x) + std::cos(angle) * (triPts[i].m_y - pt1.m_y) +
147  pt1.m_y);
148  }
149  m_powerFlowArrow.push_back(triPts);
150  }
151  }
152 }
153 
155 {
156  if(m_online) {
157  glColor4dv(m_powerFlowArrowColour.GetRGBA());
158  for(int i = 0; i < (int)m_powerFlowArrow.size(); i++) {
159  DrawTriangle(m_powerFlowArrow[i]);
160  }
161  }
162 }
163 
164 double PowerElement::GetValueFromUnit(double value, ElectricalUnit valueUnit)
165 {
166  switch(valueUnit) {
167  case UNIT_kV:
168  case UNIT_kA:
169  case UNIT_kW:
170  case UNIT_kVA:
171  case UNIT_kVAr: {
172  return value * 1e3;
173  } break;
174  case UNIT_MW:
175  case UNIT_MVA:
176  case UNIT_MVAr: {
177  return value * 1e6;
178  }
179  default:
180  break;
181  }
182  return value;
183 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void DrawTriangle(std::vector< wxPoint2DDouble > points, GLenum mode=GL_TRIANGLES) const
Draw a triangle.
Definition: Element.cpp:60
virtual void UpdateSwitches()
Update the switch position.
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
@@ -105,7 +105,7 @@ $(document).ready(function(){initNavTree('_power_element_8cpp_source.html','');}
virtual void CalculatePowerFlowPts(std::vector< wxPoint2DDouble > edges)
Calculate the points of the power flow arrows.
virtual void DrawPowerFlowPts() const
Draw power flow arrows.
-
Switching data of power elements.
+
PowerElement()
Constructor.
~PowerElement()
Destructor.
virtual void DrawSwitches() const
Draw switch.
diff --git a/docs/doxygen/html/_power_element_8h.html b/docs/doxygen/html/_power_element_8h.html index de32ed6..5ad31ce 100644 --- a/docs/doxygen/html/_power_element_8h.html +++ b/docs/doxygen/html/_power_element_8h.html @@ -91,21 +91,21 @@ $(document).ready(function(){initNavTree('_power_element_8h.html','');});
PowerElement.h File Reference
- -

Switching data of power elements. -More...

#include "Element.h"
-#include "ElementPlotData.h"
+#include "ElementPlotData.h"

Go to the source code of this file.

+ + +

Classes

class  SwitchingData
 Switching data of power elements. More...
 
class  IntegrationConstant
 Integration constants to calculate dynamic elements through trapezoidal integration method. More...
 
class  PowerElement
 Abstract class of power elements. More...
 

@@ -169,13 +169,7 @@ Enumerations

 
-

Detailed Description

-

Switching data of power elements.

-

Base class of power elements.

-

Integration constants to calculate dynamic elements through trapezoidal integration method.

- -

Definition in file PowerElement.h.

-

Enumeration Type Documentation

+

Enumeration Type Documentation

◆ ElectricalUnit

@@ -258,11 +252,11 @@ Enumerations FAULT_LINE_GROUND 

Line-to-ground fault

-FAULT_LINE_A 

Fault on phase A or phase AB

+FAULT_LINE_A 

Fault on phase A or phase AB

-FAULT_LINE_B 

Fault on phase B or phase BC

+FAULT_LINE_B 

Fault on phase B or phase BC

-FAULT_LINE_C 

Fault on phase C or phase CA

+FAULT_LINE_C 

Fault on phase C or phase CA

@@ -286,9 +280,9 @@ Enumerations - - diff --git a/docs/doxygen/html/_power_element_8h_source.html b/docs/doxygen/html/_power_element_8h_source.html index abd7623..2dd1720 100644 --- a/docs/doxygen/html/_power_element_8h_source.html +++ b/docs/doxygen/html/_power_element_8h_source.html @@ -88,11 +88,11 @@ $(document).ready(function(){initNavTree('_power_element_8h_source.html','');});
PowerElement.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef POWERELEMENT_H
19 #define POWERELEMENT_H
20 
21 #include "Element.h"
22 #include "ElementPlotData.h"
23 
29  UNIT_PU = 0,
49 };
50 
55 enum FaultData {
63 };
64 
70  SW_INSERT = 0,
72 };
73 
79  PF_NONE = 0,
84 };
85 
93 struct SwitchingData {
94  std::vector<SwitchingType> swType;
95  std::vector<double> swTime;
96 };
97 
106  double c;
107  double m;
108 };
109 
117 class PowerElement : public Element
118 {
119  public:
123  PowerElement();
127  ~PowerElement();
128 
135  virtual wxPoint2DDouble GetSwitchPoint(Element* parent,
136  wxPoint2DDouble parentPoint,
137  wxPoint2DDouble secondPoint) const;
138 
143  virtual bool SwitchesContains(wxPoint2DDouble position) const;
144 
148  virtual void UpdateSwitches();
149 
153  virtual void DrawSwitches() const;
154 
159  virtual void CalculatePowerFlowPts(std::vector<wxPoint2DDouble> edges);
160 
164  virtual void DrawPowerFlowPts() const;
165 
171  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
172 
177  virtual void SetSwitchingData(SwitchingData data) { m_swData = data; }
182  virtual SwitchingData GetSwitchingData() { return m_swData; }
187  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection) { m_pfDirection = pfDirection; }
192  virtual PowerFlowDirection GetPowerFlowDirection() const { return m_pfDirection; }
198  virtual bool GetPlotData(ElementPlotData& plotData) { return false; }
203  virtual bool HaveDynamicEvent() const { return m_dynEvent; }
208  virtual void SetDynamicEvent(bool dynEvent = true) { m_dynEvent = dynEvent; }
209  virtual double GetValueFromUnit(double value, ElectricalUnit valueUnit);
210 
211  protected:
212  SwitchingData m_swData;
213  std::vector<std::vector<wxPoint2DDouble> > m_powerFlowArrow;
214  PowerFlowDirection m_pfDirection = PF_NONE;
215 
216  OpenGLColour m_busColour;
217  OpenGLColour m_onlineElementColour;
218  OpenGLColour m_offlineElementColour;
219  OpenGLColour m_closedSwitchColour;
220  OpenGLColour m_openedSwitchColour;
221  OpenGLColour m_powerFlowArrowColour;
222  OpenGLColour m_dynamicEventColour;
223 
224  bool m_dynEvent = false;
225 };
226 
227 #endif // POWERELEMENT_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef POWERELEMENT_H
19 #define POWERELEMENT_H
20 
21 #include "Element.h"
22 #include "ElementPlotData.h"
23 
29  UNIT_PU = 0,
49 };
50 
55 enum FaultData {
63 };
64 
70  SW_INSERT = 0,
72 };
73 
79  PF_NONE = 0,
84 };
85 
93 struct SwitchingData {
94  std::vector<SwitchingType> swType;
95  std::vector<double> swTime;
96 };
97 
106  double c;
107  double m;
108 };
109 
117 class PowerElement : public Element
118 {
119  public:
123  PowerElement();
127  ~PowerElement();
128 
135  virtual wxPoint2DDouble GetSwitchPoint(Element* parent,
136  wxPoint2DDouble parentPoint,
137  wxPoint2DDouble secondPoint) const;
138 
143  virtual bool SwitchesContains(wxPoint2DDouble position) const;
144 
148  virtual void UpdateSwitches();
149 
153  virtual void DrawSwitches() const;
154 
159  virtual void CalculatePowerFlowPts(std::vector<wxPoint2DDouble> edges);
160 
164  virtual void DrawPowerFlowPts() const;
165 
171  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
172 
177  virtual void SetSwitchingData(SwitchingData data) { m_swData = data; }
182  virtual SwitchingData GetSwitchingData() { return m_swData; }
187  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection) { m_pfDirection = pfDirection; }
192  virtual PowerFlowDirection GetPowerFlowDirection() const { return m_pfDirection; }
198  virtual bool GetPlotData(ElementPlotData& plotData) { return false; }
203  virtual bool HaveDynamicEvent() const { return m_dynEvent; }
208  virtual void SetDynamicEvent(bool dynEvent = true) { m_dynEvent = dynEvent; }
209  virtual double GetValueFromUnit(double value, ElectricalUnit valueUnit);
210 
211  protected:
212  SwitchingData m_swData;
213  std::vector<std::vector<wxPoint2DDouble> > m_powerFlowArrow;
214  PowerFlowDirection m_pfDirection = PF_NONE;
215 
216  OpenGLColour m_busColour;
217  OpenGLColour m_onlineElementColour;
218  OpenGLColour m_offlineElementColour;
219  OpenGLColour m_closedSwitchColour;
220  OpenGLColour m_openedSwitchColour;
221  OpenGLColour m_powerFlowArrowColour;
222  OpenGLColour m_dynamicEventColour;
223 
224  bool m_dynEvent = false;
225 };
226 
227 #endif // POWERELEMENT_H
std::vector< double > swTime
Definition: PowerElement.h:95
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
@@ -104,17 +104,17 @@ $(document).ready(function(){initNavTree('_power_element_8h_source.html','');});
std::vector< SwitchingType > swType
Definition: PowerElement.h:94
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- +
Integration constants to calculate dynamic elements through trapezoidal integration method...
Definition: PowerElement.h:105
virtual void SetDynamicEvent(bool dynEvent=true)
Set if the power element have dynamic event.
Definition: PowerElement.h:208
-
Class to manage color of OpenGL.
+
virtual bool GetPlotData(ElementPlotData &plotData)
Fill the plot data.
Definition: PowerElement.h:198
- +
Switching data of power elements.
Definition: PowerElement.h:93
- + @@ -125,6 +125,7 @@ $(document).ready(function(){initNavTree('_power_element_8h_source.html','');}); +
virtual PowerFlowDirection GetPowerFlowDirection() const
Return the direction of the power flow.
Definition: PowerElement.h:192
virtual SwitchingData GetSwitchingData()
Returns the switching data of the element.
Definition: PowerElement.h:182
@@ -132,9 +133,9 @@ $(document).ready(function(){initNavTree('_power_element_8h_source.html','');});
SwitchingType
Type of switching.
Definition: PowerElement.h:69
- +
Class to manage color of OpenGL.
Definition: Element.h:67
PowerFlowDirection
Direction of power flow arrows.
Definition: PowerElement.h:78
- +
Abstract class of power elements.
Definition: PowerElement.h:117
diff --git a/docs/doxygen/html/_power_flow_8cpp_source.html b/docs/doxygen/html/_power_flow_8cpp_source.html index 7143bea..d0931d7 100644 --- a/docs/doxygen/html/_power_flow_8cpp_source.html +++ b/docs/doxygen/html/_power_flow_8cpp_source.html @@ -88,18 +88,19 @@ $(document).ready(function(){initNavTree('_power_flow_8cpp_source.html','');});
PowerFlow.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "PowerFlow.h"
19 
20 PowerFlow::PowerFlow() : ElectricCalculation() {}
21 PowerFlow::PowerFlow(std::vector<Element*> elementList) : ElectricCalculation() { GetElementsFromList(elementList); }
22 PowerFlow::~PowerFlow() {}
23 bool PowerFlow::RunGaussSeidel(double systemPowerBase,
24  int maxIteration,
25  double error,
26  double initAngle,
27  double accFactor)
28 {
29  // Calculate the Ybus.
30  if(!GetYBus(m_yBus, systemPowerBase)) {
31  m_errorMsg = _("No buses found on the system.");
32  return false;
33  }
34 
35  // Number of buses on the system.
36  int numberOfBuses = static_cast<int>(m_busList.size());
37 
38  std::vector<BusType> busType; // Bus type
39  std::vector<std::complex<double> > voltage; // Voltage of buses
40  std::vector<std::complex<double> > power; // Injected power
41  std::vector<std::complex<double> > loadPower; // Only the load power
42  std::vector<ReactiveLimits> reactiveLimit; // Limit of reactive power on PV buses
43 
44  reactiveLimit.resize(numberOfBuses);
45 
46  int busNumber = 0;
47  for(auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
48  Bus* bus = *itb;
49  BusElectricalData data = bus->GetElectricalData();
50 
51  // Fill the bus type
52  if(data.slackBus) busType.push_back(BUS_SLACK);
53  // If the bus have controlled voltage, check if at least one synchronous machine is connected, then set the
54  // bus type.
55  else if(data.isVoltageControlled) {
56  bool hasSyncMachine = false;
57  // Synchronous generator
58  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
59  SyncGenerator* syncGenerator = *itsg;
60  if(bus == syncGenerator->GetParentList()[0] && syncGenerator->IsOnline()) hasSyncMachine = true;
61  }
62  // Synchronous motor
63  for(auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
64  SyncMotor* syncMotor = *itsm;
65  if(bus == syncMotor->GetParentList()[0] && syncMotor->IsOnline()) hasSyncMachine = true;
66  }
67  if(hasSyncMachine)
68  busType.push_back(BUS_PV);
69  else
70  busType.push_back(BUS_PQ);
71  } else
72  busType.push_back(BUS_PQ);
73 
74  // Fill the voltages array
75  if(data.isVoltageControlled && busType[busNumber] != BUS_PQ) {
76  voltage.push_back(std::complex<double>(data.controlledVoltage, 0.0));
77  } else {
78  voltage.push_back(std::complex<double>(1.0, 0.0));
79  }
80 
81  // Fill the power array
82  power.push_back(std::complex<double>(0.0, 0.0)); // Initial value
83  loadPower.push_back(std::complex<double>(0.0, 0.0));
84 
85  // Synchronous generator
86  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
87  SyncGenerator* syncGenerator = *itsg;
88  if(syncGenerator->IsOnline()) {
89  if(bus == syncGenerator->GetParentList()[0]) {
90  SyncGeneratorElectricalData childData = syncGenerator->GetPUElectricalData(systemPowerBase);
91  power[busNumber] += std::complex<double>(childData.activePower, childData.reactivePower);
92 
93  if(busType[busNumber] == BUS_PV) {
94  if(childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType != RL_UNLIMITED_SOURCE) {
95  reactiveLimit[busNumber].maxLimitType = RL_LIMITED;
96  reactiveLimit[busNumber].maxLimit += childData.maxReactive;
97  } else if(!childData.haveMaxReactive)
98  reactiveLimit[busNumber].maxLimitType = RL_UNLIMITED_SOURCE;
99 
100  if(childData.haveMinReactive && reactiveLimit[busNumber].minLimitType != RL_UNLIMITED_SOURCE) {
101  reactiveLimit[busNumber].minLimitType = RL_LIMITED;
102  reactiveLimit[busNumber].minLimit += childData.minReactive;
103  } else if(!childData.haveMinReactive)
104  reactiveLimit[busNumber].minLimitType = RL_UNLIMITED_SOURCE;
105  }
106  }
107  }
108  }
109  // Synchronous motor
110  for(auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
111  SyncMotor* syncMotor = *itsm;
112  if(syncMotor->IsOnline()) {
113  if(bus == syncMotor->GetParentList()[0]) {
114  SyncMotorElectricalData childData = syncMotor->GetPUElectricalData(systemPowerBase);
115  power[busNumber] += std::complex<double>(-childData.activePower, childData.reactivePower);
116  loadPower[busNumber] += std::complex<double>(-childData.activePower, 0.0);
117 
118  if(busType[busNumber] == BUS_PV) {
119  if(childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType != RL_UNLIMITED_SOURCE) {
120  reactiveLimit[busNumber].maxLimitType = RL_LIMITED;
121  reactiveLimit[busNumber].maxLimit += childData.maxReactive;
122  } else if(!childData.haveMaxReactive)
123  reactiveLimit[busNumber].maxLimitType = RL_UNLIMITED_SOURCE;
124 
125  if(childData.haveMinReactive && reactiveLimit[busNumber].minLimitType != RL_UNLIMITED_SOURCE) {
126  reactiveLimit[busNumber].minLimitType = RL_LIMITED;
127  reactiveLimit[busNumber].minLimit += childData.minReactive;
128  } else if(!childData.haveMinReactive)
129  reactiveLimit[busNumber].minLimitType = RL_UNLIMITED_SOURCE;
130  }
131  }
132  }
133  }
134  // Load
135  for(auto itl = m_loadList.begin(); itl != m_loadList.end(); itl++) {
136  Load* load = *itl;
137  if(load->IsOnline()) {
138  if(bus == load->GetParentList()[0]) {
139  LoadElectricalData childData = load->GetPUElectricalData(systemPowerBase);
140  if(childData.loadType == CONST_POWER) {
141  power[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
142  loadPower[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
143  }
144  }
145  }
146  }
147 
148  // Induction motor
149  for(auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) {
150  IndMotor* indMotor = *itim;
151  if(indMotor->IsOnline()) {
152  if(bus == indMotor->GetParentList()[0]) {
153  IndMotorElectricalData childData = indMotor->GetPUElectricalData(systemPowerBase);
154  power[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
155  loadPower[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
156  }
157  }
158  }
159 
160  busNumber++;
161  }
162 
163  // Check if have slack bus and if have generation on the slack bus
164  bool haveSlackBus = false;
165  bool slackBusHaveGeneration = false;
166  for(int i = 0; i < (int)busType.size(); i++) {
167  if(busType[i] == BUS_SLACK) {
168  auto itb = m_busList.begin();
169  std::advance(itb, i);
170  Bus* bus = *itb;
171 
172  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
173  SyncGenerator* syncGenerator = *itsg;
174  if(syncGenerator->IsOnline() && bus == syncGenerator->GetParentList()[0]) slackBusHaveGeneration = true;
175  }
176  haveSlackBus = true;
177  }
178  }
179  if(!haveSlackBus) {
180  m_errorMsg = _("There is no slack bus on the system.");
181  return false;
182  }
183  if(!slackBusHaveGeneration) {
184  m_errorMsg = _("The slack bus don't have generation.");
185  return false;
186  }
187 
188  // Gauss-Seidel method
189  std::vector<std::complex<double> > oldVoltage; // Old voltage array.
190  oldVoltage.resize(voltage.size());
191 
192  auto oldBusType = busType;
193 
194  int iteration = 0; // Current itaration number.
195 
196  while(true) {
197  // Reach the max number of iterations.
198  if(iteration >= maxIteration) {
199  m_errorMsg = _("The maximum number of iterations was reached.");
200  return false;
201  }
202 
203  // Update the old voltage array to current iteration values.
204  for(int i = 0; i < numberOfBuses; i++) oldVoltage[i] = voltage[i];
205 
206  double iterationError = 0.0;
207 
208  for(int i = 0; i < numberOfBuses; i++) {
209  if(busType[i] == BUS_PQ) {
210  std::complex<double> yeSum(0.0, 0.0);
211  for(int k = 0; k < numberOfBuses; k++) {
212  if(i != k) {
213  // Sum { Y[i,k] * E[k] } | k = 1->n; k diff i
214  yeSum += m_yBus[i][k] * voltage[k];
215  }
216  }
217 
218  // E[i] = (1/Y[i,i])*((P[i]-jQ[i])/E*[i] - Sum { Y[i,k] * E[k] (k diff i) })
219  std::complex<double> newVolt =
220  (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
221 
222  // Apply the acceleration factor.
223  newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
224  accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
225 
226  voltage[i] = newVolt;
227  }
228  if(busType[i] == BUS_PV) {
229  std::complex<double> yeSum(0.0, 0.0);
230  for(int k = 0; k < numberOfBuses; k++) {
231  if(i != k) {
232  // Sum { Y[i,k] * E[k] } | k = 1->n; k diff i
233  yeSum += m_yBus[i][k] * voltage[k];
234  }
235  }
236  std::complex<double> yeSumT = yeSum + (m_yBus[i][i] * voltage[i]);
237 
238  // Q[i] = - Im( E*[i] * Sum { Y[i,k] * E[k] } )
239  std::complex<double> qCalc = std::conj(voltage[i]) * yeSumT;
240  power[i] = std::complex<double>(power[i].real(), -qCalc.imag());
241 
242  // E[i] = (1/Y[i,i])*((P[i]-jQ[i])/E*[i] - Sum { Y[i,k] * E[k] (k diff i) })
243  std::complex<double> newVolt =
244  (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
245 
246  // Apply the acceleration factor.
247  newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
248  accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
249 
250  // Keep the same voltage magnitude.
251  voltage[i] = std::complex<double>(std::abs(voltage[i]) * std::cos(std::arg(newVolt)),
252  std::abs(voltage[i]) * std::sin(std::arg(newVolt)));
253  }
254 
255  double busError = std::max(std::abs(voltage[i].real() - oldVoltage[i].real()),
256  std::abs(voltage[i].imag() - oldVoltage[i].imag()));
257 
258  if(busError > iterationError) iterationError = busError;
259  }
260 
261  if(iterationError < error) {
262  bool limitReach = false;
263  for(int i = 0; i < numberOfBuses; i++) {
264  if(busType[i] == BUS_PV) {
265  if(reactiveLimit[i].maxLimitType == RL_LIMITED) {
266  if(power[i].imag() - loadPower[i].imag() > reactiveLimit[i].maxLimit) {
267  power[i] =
268  std::complex<double>(power[i].real(), reactiveLimit[i].maxLimit + loadPower[i].imag());
269  busType[i] = BUS_PQ;
270  reactiveLimit[i].limitReached = RL_MAX_REACHED;
271  limitReach = true;
272  }
273  }
274  if(reactiveLimit[i].minLimitType == RL_LIMITED) {
275  if(power[i].imag() - loadPower[i].imag() < reactiveLimit[i].minLimit) {
276  power[i] =
277  std::complex<double>(power[i].real(), reactiveLimit[i].minLimit + loadPower[i].imag());
278  busType[i] = BUS_PQ;
279  reactiveLimit[i].limitReached = RL_MIN_REACHED;
280  limitReach = true;
281  }
282  }
283  }
284  }
285  if(!limitReach) break;
286  }
287 
288  iteration++;
289  }
290 
291  // Adjust the power array.
292  // TODO: Only the slack bus??
293  for(int i = 0; i < numberOfBuses; i++) {
294  std::complex<double> sBus = std::complex<double>(0.0, 0.0);
295  for(int j = 0; j < numberOfBuses; j++) sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
296  power[i] = sBus;
297  }
298 
299  UpdateElementsPowerFlow(voltage, power, oldBusType, reactiveLimit, systemPowerBase);
300 
301  return true;
302 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "PowerFlow.h"
19 
20 PowerFlow::PowerFlow() : ElectricCalculation() {}
21 PowerFlow::PowerFlow(std::vector<Element*> elementList) : ElectricCalculation() { GetElementsFromList(elementList); }
22 PowerFlow::~PowerFlow() {}
23 bool PowerFlow::RunGaussSeidel(double systemPowerBase,
24  int maxIteration,
25  double error,
26  double initAngle,
27  double accFactor)
28 {
29  // Calculate the Ybus.
30  if(!GetYBus(m_yBus, systemPowerBase)) {
31  m_errorMsg = _("No buses found on the system.");
32  return false;
33  }
34 
35  // Number of buses on the system.
36  int numberOfBuses = static_cast<int>(m_busList.size());
37 
38  std::vector<BusType> busType; // Bus type
39  std::vector<std::complex<double> > voltage; // Voltage of buses
40  std::vector<std::complex<double> > power; // Injected power
41  std::vector<std::complex<double> > loadPower; // Only the load power
42  std::vector<ReactiveLimits> reactiveLimit; // Limit of reactive power on PV buses
43 
44  reactiveLimit.resize(numberOfBuses);
45 
46  int busNumber = 0;
47  for(auto itb = m_busList.begin(); itb != m_busList.end(); itb++) {
48  Bus* bus = *itb;
49  BusElectricalData data = bus->GetElectricalData();
50 
51  // Fill the bus type
52  if(data.slackBus) busType.push_back(BUS_SLACK);
53  // If the bus have controlled voltage, check if at least one synchronous machine is connected, then set the
54  // bus type.
55  else if(data.isVoltageControlled) {
56  bool hasSyncMachine = false;
57  // Synchronous generator
58  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
59  SyncGenerator* syncGenerator = *itsg;
60  if(bus == syncGenerator->GetParentList()[0] && syncGenerator->IsOnline()) hasSyncMachine = true;
61  }
62  // Synchronous motor
63  for(auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
64  SyncMotor* syncMotor = *itsm;
65  if(bus == syncMotor->GetParentList()[0] && syncMotor->IsOnline()) hasSyncMachine = true;
66  }
67  if(hasSyncMachine)
68  busType.push_back(BUS_PV);
69  else
70  busType.push_back(BUS_PQ);
71  } else
72  busType.push_back(BUS_PQ);
73 
74  // Fill the voltages array
75  if(data.isVoltageControlled && busType[busNumber] != BUS_PQ) {
76  voltage.push_back(std::complex<double>(data.controlledVoltage, 0.0));
77  } else {
78  voltage.push_back(std::complex<double>(1.0, 0.0));
79  }
80 
81  // Fill the power array
82  power.push_back(std::complex<double>(0.0, 0.0)); // Initial value
83  loadPower.push_back(std::complex<double>(0.0, 0.0));
84 
85  // Synchronous generator
86  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
87  SyncGenerator* syncGenerator = *itsg;
88  if(syncGenerator->IsOnline()) {
89  if(bus == syncGenerator->GetParentList()[0]) {
90  SyncGeneratorElectricalData childData = syncGenerator->GetPUElectricalData(systemPowerBase);
91  power[busNumber] += std::complex<double>(childData.activePower, childData.reactivePower);
92 
93  if(busType[busNumber] == BUS_PV) {
94  if(childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType != RL_UNLIMITED_SOURCE) {
95  reactiveLimit[busNumber].maxLimitType = RL_LIMITED;
96  reactiveLimit[busNumber].maxLimit += childData.maxReactive;
97  } else if(!childData.haveMaxReactive)
98  reactiveLimit[busNumber].maxLimitType = RL_UNLIMITED_SOURCE;
99 
100  if(childData.haveMinReactive && reactiveLimit[busNumber].minLimitType != RL_UNLIMITED_SOURCE) {
101  reactiveLimit[busNumber].minLimitType = RL_LIMITED;
102  reactiveLimit[busNumber].minLimit += childData.minReactive;
103  } else if(!childData.haveMinReactive)
104  reactiveLimit[busNumber].minLimitType = RL_UNLIMITED_SOURCE;
105  }
106  }
107  }
108  }
109  // Synchronous motor
110  for(auto itsm = m_syncMotorList.begin(); itsm != m_syncMotorList.end(); itsm++) {
111  SyncMotor* syncMotor = *itsm;
112  if(syncMotor->IsOnline()) {
113  if(bus == syncMotor->GetParentList()[0]) {
114  SyncMotorElectricalData childData = syncMotor->GetPUElectricalData(systemPowerBase);
115  power[busNumber] += std::complex<double>(-childData.activePower, childData.reactivePower);
116  loadPower[busNumber] += std::complex<double>(-childData.activePower, 0.0);
117 
118  if(busType[busNumber] == BUS_PV) {
119  if(childData.haveMaxReactive && reactiveLimit[busNumber].maxLimitType != RL_UNLIMITED_SOURCE) {
120  reactiveLimit[busNumber].maxLimitType = RL_LIMITED;
121  reactiveLimit[busNumber].maxLimit += childData.maxReactive;
122  } else if(!childData.haveMaxReactive)
123  reactiveLimit[busNumber].maxLimitType = RL_UNLIMITED_SOURCE;
124 
125  if(childData.haveMinReactive && reactiveLimit[busNumber].minLimitType != RL_UNLIMITED_SOURCE) {
126  reactiveLimit[busNumber].minLimitType = RL_LIMITED;
127  reactiveLimit[busNumber].minLimit += childData.minReactive;
128  } else if(!childData.haveMinReactive)
129  reactiveLimit[busNumber].minLimitType = RL_UNLIMITED_SOURCE;
130  }
131  }
132  }
133  }
134  // Load
135  for(auto itl = m_loadList.begin(); itl != m_loadList.end(); itl++) {
136  Load* load = *itl;
137  if(load->IsOnline()) {
138  if(bus == load->GetParentList()[0]) {
139  LoadElectricalData childData = load->GetPUElectricalData(systemPowerBase);
140  if(childData.loadType == CONST_POWER) {
141  power[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
142  loadPower[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
143  }
144  }
145  }
146  }
147 
148  // Induction motor
149  for(auto itim = m_indMotorList.begin(); itim != m_indMotorList.end(); itim++) {
150  IndMotor* indMotor = *itim;
151  if(indMotor->IsOnline()) {
152  if(bus == indMotor->GetParentList()[0]) {
153  IndMotorElectricalData childData = indMotor->GetPUElectricalData(systemPowerBase);
154  power[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
155  loadPower[busNumber] += std::complex<double>(-childData.activePower, -childData.reactivePower);
156  }
157  }
158  }
159 
160  busNumber++;
161  }
162 
163  // Check if have slack bus and if have generation on the slack bus
164  bool haveSlackBus = false;
165  bool slackBusHaveGeneration = false;
166  for(int i = 0; i < (int)busType.size(); i++) {
167  if(busType[i] == BUS_SLACK) {
168  auto itb = m_busList.begin();
169  std::advance(itb, i);
170  Bus* bus = *itb;
171 
172  for(auto itsg = m_syncGeneratorList.begin(); itsg != m_syncGeneratorList.end(); itsg++) {
173  SyncGenerator* syncGenerator = *itsg;
174  if(syncGenerator->IsOnline() && bus == syncGenerator->GetParentList()[0]) slackBusHaveGeneration = true;
175  }
176  haveSlackBus = true;
177  }
178  }
179  if(!haveSlackBus) {
180  m_errorMsg = _("There is no slack bus on the system.");
181  return false;
182  }
183  if(!slackBusHaveGeneration) {
184  m_errorMsg = _("The slack bus don't have generation.");
185  return false;
186  }
187 
188  // Gauss-Seidel method
189  std::vector<std::complex<double> > oldVoltage; // Old voltage array.
190  oldVoltage.resize(voltage.size());
191 
192  auto oldBusType = busType;
193 
194  int iteration = 0; // Current itaration number.
195 
196  while(true) {
197  // Reach the max number of iterations.
198  if(iteration >= maxIteration) {
199  m_errorMsg = _("The maximum number of iterations was reached.");
200  return false;
201  }
202 
203  // Update the old voltage array to current iteration values.
204  for(int i = 0; i < numberOfBuses; i++) oldVoltage[i] = voltage[i];
205 
206  double iterationError = 0.0;
207 
208  for(int i = 0; i < numberOfBuses; i++) {
209  if(busType[i] == BUS_PQ) {
210  std::complex<double> yeSum(0.0, 0.0);
211  for(int k = 0; k < numberOfBuses; k++) {
212  if(i != k) {
213  // Sum { Y[i,k] * E[k] } | k = 1->n; k diff i
214  yeSum += m_yBus[i][k] * voltage[k];
215  }
216  }
217 
218  // E[i] = (1/Y[i,i])*((P[i]-jQ[i])/E*[i] - Sum { Y[i,k] * E[k] (k diff i) })
219  std::complex<double> newVolt =
220  (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
221 
222  // Apply the acceleration factor.
223  newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
224  accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
225 
226  voltage[i] = newVolt;
227  }
228  if(busType[i] == BUS_PV) {
229  std::complex<double> yeSum(0.0, 0.0);
230  for(int k = 0; k < numberOfBuses; k++) {
231  if(i != k) {
232  // Sum { Y[i,k] * E[k] } | k = 1->n; k diff i
233  yeSum += m_yBus[i][k] * voltage[k];
234  }
235  }
236  std::complex<double> yeSumT = yeSum + (m_yBus[i][i] * voltage[i]);
237 
238  // Q[i] = - Im( E*[i] * Sum { Y[i,k] * E[k] } )
239  std::complex<double> qCalc = std::conj(voltage[i]) * yeSumT;
240  power[i] = std::complex<double>(power[i].real(), -qCalc.imag());
241 
242  // E[i] = (1/Y[i,i])*((P[i]-jQ[i])/E*[i] - Sum { Y[i,k] * E[k] (k diff i) })
243  std::complex<double> newVolt =
244  (1.0 / m_yBus[i][i]) * (std::conj(power[i]) / std::conj(voltage[i]) - yeSum);
245 
246  // Apply the acceleration factor.
247  newVolt = std::complex<double>(accFactor * (newVolt.real() - voltage[i].real()) + voltage[i].real(),
248  accFactor * (newVolt.imag() - voltage[i].imag()) + voltage[i].imag());
249 
250  // Keep the same voltage magnitude.
251  voltage[i] = std::complex<double>(std::abs(voltage[i]) * std::cos(std::arg(newVolt)),
252  std::abs(voltage[i]) * std::sin(std::arg(newVolt)));
253  }
254 
255  double busError = std::max(std::abs(voltage[i].real() - oldVoltage[i].real()),
256  std::abs(voltage[i].imag() - oldVoltage[i].imag()));
257 
258  if(busError > iterationError) iterationError = busError;
259  }
260 
261  if(iterationError < error) {
262  bool limitReach = false;
263  for(int i = 0; i < numberOfBuses; i++) {
264  if(busType[i] == BUS_PV) {
265  if(reactiveLimit[i].maxLimitType == RL_LIMITED) {
266  if(power[i].imag() - loadPower[i].imag() > reactiveLimit[i].maxLimit) {
267  power[i] =
268  std::complex<double>(power[i].real(), reactiveLimit[i].maxLimit + loadPower[i].imag());
269  busType[i] = BUS_PQ;
270  reactiveLimit[i].limitReached = RL_MAX_REACHED;
271  limitReach = true;
272  }
273  }
274  if(reactiveLimit[i].minLimitType == RL_LIMITED) {
275  if(power[i].imag() - loadPower[i].imag() < reactiveLimit[i].minLimit) {
276  power[i] =
277  std::complex<double>(power[i].real(), reactiveLimit[i].minLimit + loadPower[i].imag());
278  busType[i] = BUS_PQ;
279  reactiveLimit[i].limitReached = RL_MIN_REACHED;
280  limitReach = true;
281  }
282  }
283  }
284  }
285  if(!limitReach) break;
286  }
287 
288  iteration++;
289  }
290 
291  // Adjust the power array.
292  // TODO: Only the slack bus??
293  for(int i = 0; i < numberOfBuses; i++) {
294  std::complex<double> sBus = std::complex<double>(0.0, 0.0);
295  for(int j = 0; j < numberOfBuses; j++) sBus += voltage[i] * std::conj(voltage[j]) * std::conj(m_yBus[i][j]);
296  power[i] = sBus;
297  }
298 
299  UpdateElementsPowerFlow(voltage, power, oldBusType, reactiveLimit, systemPowerBase);
300 
301  return true;
302 }
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
- +
Synchronous generator power element.
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
-
Definition: Load.h:35
+
Loas shunt power element.
Definition: Load.h:42
- - - +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+ +
Induction motor power element.
Definition: IndMotor.h:40
+
Base class of electric calculations, with general methods.
diff --git a/docs/doxygen/html/_power_flow_8h.html b/docs/doxygen/html/_power_flow_8h.html new file mode 100644 index 0000000..25a2ff6 --- /dev/null +++ b/docs/doxygen/html/_power_flow_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/PowerFlow.h File Reference + + + + + + + + + + + + + + + +
+
+
Enumerator
PF_NONE 

No direction (no arrows printed)

PF_TO_BUS 

Element to bus

+
PF_TO_BUS 

Element to bus

PF_TO_ELEMENT 

Bus to element

+
PF_TO_ELEMENT 

Bus to element

PF_BUS1_TO_BUS2 

First bus to secont bus (branch elements)

+ + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
PowerFlow.h File Reference
+
+
+
#include "ElectricCalculation.h"
+#include <wx/string.h>
+#include <wx/intl.h>
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  PowerFlow
 Calculate the power flow. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_power_flow_8h_source.html b/docs/doxygen/html/_power_flow_8h_source.html index 677dd50..1828677 100644 --- a/docs/doxygen/html/_power_flow_8h_source.html +++ b/docs/doxygen/html/_power_flow_8h_source.html @@ -88,15 +88,15 @@ $(document).ready(function(){initNavTree('_power_flow_8h_source.html','');});
PowerFlow.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef POWERFLOW_H
19 #define POWERFLOW_H
20 
21 #include "ElectricCalculation.h"
22 
23 #include <wx/string.h>
24 #include <wx/intl.h> //_()
25 
27 {
28  public:
29  PowerFlow();
30  PowerFlow(std::vector<Element*> elementList);
31  ~PowerFlow();
32  virtual bool RunGaussSeidel(double systemPowerBase = 100e6,
33  int maxIteration = 5000,
34  double error = 1e-6,
35  double initAngle = 0.0,
36  double accFactor = 1.0);
37 
38  virtual wxString GetErrorMessage() { return m_errorMsg; }
39  protected:
40  std::vector<std::vector<std::complex<double> > > m_yBus;
41  wxString m_errorMsg = "";
42 };
43 
44 #endif // POWERFLOW_H
-
Base class of electric calculations, with general methods.
- +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef POWERFLOW_H
19 #define POWERFLOW_H
20 
21 #include "ElectricCalculation.h"
22 
23 #include <wx/string.h>
24 #include <wx/intl.h> //_()
25 
34 {
35  public:
36  PowerFlow();
37  PowerFlow(std::vector<Element*> elementList);
38  ~PowerFlow();
39  virtual bool RunGaussSeidel(double systemPowerBase = 100e6,
40  int maxIteration = 5000,
41  double error = 1e-6,
42  double initAngle = 0.0,
43  double accFactor = 1.0);
44 
45  virtual wxString GetErrorMessage() { return m_errorMsg; }
46  protected:
47  std::vector<std::vector<std::complex<double> > > m_yBus;
48  wxString m_errorMsg = "";
49 };
50 
51 #endif // POWERFLOW_H
Calculate the power flow.
Definition: PowerFlow.h:33
+ +
Base class of electric calculations, with general methods.
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "PropertiesData.h"
19 
20 PropertiesData::PropertiesData() {}
21 PropertiesData::~PropertiesData() {}
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "PropertiesData.h"
19 
20 PropertiesData::PropertiesData() {}
21 PropertiesData::~PropertiesData() {}
+
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef PROPERTIESDATA_H
19 #define PROPERTIESDATA_H
20 
21 #include "wx/language.h"
22 #include "Element.h"
23 #include "PowerElement.h"
24 
25 enum PowerFlowMethod { GAUSS_SEIDEL = 0, NEWTON_RAPHSON };
26 enum GUITheme { THEME_LIGHT = 0, THEME_DARK };
27 
29  // General simulation data
30  double basePower = 100.0;
31  ElectricalUnit basePowerUnit = UNIT_MVA;
32  bool faultAfterPowerFlow = true;
33  bool scPowerAfterPowerFlow = true;
34 
35  // Power flow
36  PowerFlowMethod powerFlowMethod = GAUSS_SEIDEL;
37  double accFator = 1.0;
38  double powerFlowTolerance = 1e-7;
39  int powerFlowMaxIterations = 5000;
40 
41  // Stability
42  double stabilityFrequency = 60.0;
43  double timeStep = 1e-2;
44  double stabilitySimulationTime = 10.0;
45  double stabilityTolerance = 1e-8;
46  int stabilityMaxIterations = 100;
47  int controlTimeStepRatio = 10;
48  double plotTime = 1e-2;
49  bool useCOI = true;
50 };
51 
52 struct GeneralData {
53  wxLanguage language = wxLANGUAGE_ENGLISH;
54  GUITheme theme = THEME_LIGHT;
55 };
56 
58 {
59  public:
61  ~PropertiesData();
62 
63  SimulationData GetSimulationPropertiesData() const { return m_simulData; }
64  void SetSimulationPropertiesData(SimulationData simulationData) { m_simulData = simulationData; }
65  GeneralData GetGeneralPropertiesData() const { return m_genData; }
66  void SetGeneralPropertiesData(GeneralData generalData) { m_genData = generalData; }
67  protected:
68  SimulationData m_simulData;
69  GeneralData m_genData;
70 };
71 
72 #endif // PROPERTIESDATA_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef PROPERTIESDATA_H
19 #define PROPERTIESDATA_H
20 
21 #include "wx/language.h"
22 #include "Element.h"
23 #include "PowerElement.h"
24 
25 enum PowerFlowMethod { GAUSS_SEIDEL = 0, NEWTON_RAPHSON };
26 enum GUITheme { THEME_LIGHT = 0, THEME_DARK };
27 
29  // General simulation data
30  double basePower = 100.0;
31  ElectricalUnit basePowerUnit = UNIT_MVA;
32  bool faultAfterPowerFlow = true;
33  bool scPowerAfterPowerFlow = true;
34 
35  // Power flow
36  PowerFlowMethod powerFlowMethod = GAUSS_SEIDEL;
37  double accFator = 1.0;
38  double powerFlowTolerance = 1e-7;
39  int powerFlowMaxIterations = 5000;
40 
41  // Stability
42  double stabilityFrequency = 60.0;
43  double timeStep = 1e-2;
44  double stabilitySimulationTime = 10.0;
45  double stabilityTolerance = 1e-8;
46  int stabilityMaxIterations = 100;
47  int controlTimeStepRatio = 10;
48  double plotTime = 1e-2;
49  bool useCOI = true;
50 };
51 
52 struct GeneralData {
53  wxLanguage language = wxLANGUAGE_ENGLISH;
54  GUITheme theme = THEME_LIGHT;
55 };
56 
65 {
66  public:
68  ~PropertiesData();
69 
70  SimulationData GetSimulationPropertiesData() const { return m_simulData; }
71  void SetSimulationPropertiesData(SimulationData simulationData) { m_simulData = simulationData; }
72  GeneralData GetGeneralPropertiesData() const { return m_genData; }
73  void SetGeneralPropertiesData(GeneralData generalData) { m_genData = generalData; }
74  protected:
75  SimulationData m_simulData;
76  GeneralData m_genData;
77 };
78 
79 #endif // PROPERTIESDATA_H
General and simulation data manager.
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
-
Class to manage color of OpenGL.
+ -
Switching data of power elements.
+
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "RateLimiter.h"
19 #include "RateLimiterForm.h"
20 
21 RateLimiter::RateLimiter(int id) : ControlElement(id)
22 {
23  m_width = m_height = 36.0;
24  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize);
25  nodeIn->StartMove(m_position);
26  Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
27  nodeOut->SetAngle(180.0);
28  nodeOut->StartMove(m_position);
29  m_nodeList.push_back(nodeIn);
30  m_nodeList.push_back(nodeOut);
31 }
32 
33 RateLimiter::~RateLimiter() {}
34 void RateLimiter::Draw(wxPoint2DDouble translation, double scale) const
35 {
36  glLineWidth(1.0);
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
41  }
42  glColor4d(1.0, 1.0, 1.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
46 
47  // Plot symbol.
48  std::vector<wxPoint2DDouble> axis;
49  axis.push_back(m_position + wxPoint2DDouble(-13, 0));
50  axis.push_back(m_position + wxPoint2DDouble(13, 0));
51  axis.push_back(m_position + wxPoint2DDouble(0, -13));
52  axis.push_back(m_position + wxPoint2DDouble(0, 13));
53  DrawLine(axis, GL_LINES);
54 
55  glLineWidth(2.0);
56  std::vector<wxPoint2DDouble> limSymbol;
57  limSymbol.push_back(m_position + wxPoint2DDouble(10, -10));
58  limSymbol.push_back(m_position + wxPoint2DDouble(-10, 10));
59  glColor4d(0.0, 0.3, 1.0, 1.0);
60  DrawLine(limSymbol);
61 
62  glColor4d(0.0, 0.0, 0.0, 1.0);
63  DrawNodes();
64 }
65 
66 bool RateLimiter::ShowForm(wxWindow* parent, Element* element)
67 {
68  RateLimiterForm* form = new RateLimiterForm(parent, this);
69  if(form->ShowModal() == wxID_OK) {
70  form->Destroy();
71  return true;
72  }
73  form->Destroy();
74  return false;
75 }
76 
77 void RateLimiter::Rotate(bool clockwise)
78 {
79  if(clockwise)
80  m_angle += 90.0;
81  else
82  m_angle -= 90.0;
83  if(m_angle >= 360.0)
84  m_angle = 0.0;
85  else if(m_angle < 0)
86  m_angle = 270.0;
87 
88  UpdatePoints();
89 
90  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
91  Node* node = *it;
92  node->Rotate(clockwise);
93  }
94 }
95 
96 void RateLimiter::UpdatePoints()
97 {
98  if(m_angle == 0.0) {
99  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
100  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(18, 0));
101  } else if(m_angle == 90.0) {
102  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -18));
103  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, 18));
104  } else if(m_angle == 180.0) {
105  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(18, 0));
106  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
107  } else if(m_angle == 270.0) {
108  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, 18));
109  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
110  }
111 }
112 
113 bool RateLimiter::Solve(double input, double timeStep)
114 {
115  double rate = (input - m_output) / timeStep;
116 
117  bool reachLimit = false;
118  if(rate > m_upLimit) {
119  rate = m_upLimit;
120  reachLimit = true;
121  } else if(rate < m_lowLimit) {
122  rate = m_lowLimit;
123  reachLimit = true;
124  }
125 
126  if(reachLimit)
127  m_output += rate * timeStep;
128  else
129  m_output = input;
130  return true;
131 }
132 
134 {
135  RateLimiter* copy = new RateLimiter(m_elementID);
136  *copy = *this;
137  return copy;
138 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "RateLimiter.h"
19 #include "RateLimiterForm.h"
20 
21 RateLimiter::RateLimiter(int id) : ControlElement(id)
22 {
23  m_width = m_height = 36.0;
24  Node* nodeIn = new Node(m_position + wxPoint2DDouble(-18, 0), Node::NODE_IN, m_borderSize);
25  nodeIn->StartMove(m_position);
26  Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
27  nodeOut->SetAngle(180.0);
28  nodeOut->StartMove(m_position);
29  m_nodeList.push_back(nodeIn);
30  m_nodeList.push_back(nodeOut);
31 }
32 
33 RateLimiter::~RateLimiter() {}
34 void RateLimiter::Draw(wxPoint2DDouble translation, double scale) const
35 {
36  glLineWidth(1.0);
37  if(m_selected) {
38  glColor4dv(m_selectionColour.GetRGBA());
39  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
40  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
41  }
42  glColor4d(1.0, 1.0, 1.0, 1.0);
43  DrawRectangle(m_position, m_width, m_height);
44  glColor4d(0.0, 0.0, 0.0, 1.0);
45  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
46 
47  // Plot symbol.
48  std::vector<wxPoint2DDouble> axis;
49  axis.push_back(m_position + wxPoint2DDouble(-13, 0));
50  axis.push_back(m_position + wxPoint2DDouble(13, 0));
51  axis.push_back(m_position + wxPoint2DDouble(0, -13));
52  axis.push_back(m_position + wxPoint2DDouble(0, 13));
53  DrawLine(axis, GL_LINES);
54 
55  glLineWidth(2.0);
56  std::vector<wxPoint2DDouble> limSymbol;
57  limSymbol.push_back(m_position + wxPoint2DDouble(10, -10));
58  limSymbol.push_back(m_position + wxPoint2DDouble(-10, 10));
59  glColor4d(0.0, 0.3, 1.0, 1.0);
60  DrawLine(limSymbol);
61 
62  glColor4d(0.0, 0.0, 0.0, 1.0);
63  DrawNodes();
64 }
65 
66 bool RateLimiter::ShowForm(wxWindow* parent, Element* element)
67 {
68  RateLimiterForm* form = new RateLimiterForm(parent, this);
69  if(form->ShowModal() == wxID_OK) {
70  form->Destroy();
71  return true;
72  }
73  form->Destroy();
74  return false;
75 }
76 
77 void RateLimiter::Rotate(bool clockwise)
78 {
79  if(clockwise)
80  m_angle += 90.0;
81  else
82  m_angle -= 90.0;
83  if(m_angle >= 360.0)
84  m_angle = 0.0;
85  else if(m_angle < 0)
86  m_angle = 270.0;
87 
88  UpdatePoints();
89 
90  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
91  Node* node = *it;
92  node->Rotate(clockwise);
93  }
94 }
95 
96 void RateLimiter::UpdatePoints()
97 {
98  if(m_angle == 0.0) {
99  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
100  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(18, 0));
101  } else if(m_angle == 90.0) {
102  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -18));
103  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, 18));
104  } else if(m_angle == 180.0) {
105  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(18, 0));
106  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-18, 0));
107  } else if(m_angle == 270.0) {
108  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, 18));
109  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
110  }
111 }
112 
113 bool RateLimiter::Solve(double input, double timeStep)
114 {
115  double rate = (input - m_output) / timeStep;
116 
117  bool reachLimit = false;
118  if(rate > m_upLimit) {
119  rate = m_upLimit;
120  reachLimit = true;
121  } else if(rate < m_lowLimit) {
122  rate = m_lowLimit;
123  reachLimit = true;
124  }
125 
126  if(reachLimit)
127  m_output += rate * timeStep;
128  else
129  m_output = input;
130  return true;
131 }
132 
134 {
135  RateLimiter* copy = new RateLimiter(m_elementID);
136  *copy = *this;
137  return copy;
138 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Node of a control element. This class manages the user interaction with the connection and control el...
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: RateLimiter.cpp:66
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
-
virtual bool Solve(double input, double timeStep)
Calculate the rate and limits it if exceeds. The rate is calculated by: is the current input a...
+
virtual bool Solve(double input, double timeStep)
Calculate the rate and limits it if exceeds.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: RateLimiter.cpp:77
diff --git a/docs/doxygen/html/_rate_limiter_8h_source.html b/docs/doxygen/html/_rate_limiter_8h_source.html index b956dd1..3374e92 100644 --- a/docs/doxygen/html/_rate_limiter_8h_source.html +++ b/docs/doxygen/html/_rate_limiter_8h_source.html @@ -88,11 +88,11 @@ $(document).ready(function(){initNavTree('_rate_limiter_8h_source.html','');});
RateLimiter.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef RATELIMITER_H
19 #define RATELIMITER_H
20 
21 #include "ControlElement.h"
22 
23 class RateLimiterForm;
24 
33 {
34  public:
35  RateLimiter(int id);
36  ~RateLimiter();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
40  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
41  virtual bool ShowForm(wxWindow* parent, Element* element);
42  virtual void Rotate(bool clockwise = true);
43 
44  virtual void UpdatePoints();
45 
46  double GetUpLimit() const { return m_upLimit; }
47  double GetLowLimit() const { return m_lowLimit; }
48  void SetUpLimit(double upLimit) { m_upLimit = upLimit; }
49  void SetLowLimit(double lowLimit) { m_lowLimit = lowLimit; }
65  virtual bool Solve(double input, double timeStep);
66 
67  virtual Element* GetCopy();
68 
69  protected:
70  double m_upLimit = 5.0;
71  double m_lowLimit = -5.0;
72 };
73 
74 #endif // RATELIMITER_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef RATELIMITER_H
19 #define RATELIMITER_H
20 
21 #include "ControlElement.h"
22 
23 class RateLimiterForm;
24 
33 {
34  public:
35  RateLimiter(int id);
36  ~RateLimiter();
37 
38  virtual void Draw(wxPoint2DDouble translation, double scale) const;
39  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
40  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
41  virtual bool ShowForm(wxWindow* parent, Element* element);
42  virtual void Rotate(bool clockwise = true);
43 
44  virtual void UpdatePoints();
45 
46  double GetUpLimit() const { return m_upLimit; }
47  double GetLowLimit() const { return m_lowLimit; }
48  void SetUpLimit(double upLimit) { m_upLimit = upLimit; }
49  void SetLowLimit(double lowLimit) { m_lowLimit = lowLimit; }
66  virtual bool Solve(double input, double timeStep);
67 
68  virtual Element* GetCopy();
69 
70  protected:
71  double m_upLimit = 5.0;
72  double m_lowLimit = -5.0;
73 };
74 
75 #endif // RATELIMITER_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: RateLimiter.cpp:66
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: RateLimiter.h:40
Limits the rising and/or falling rate.
Definition: RateLimiter.h:32
-
virtual bool Solve(double input, double timeStep)
Calculate the rate and limits it if exceeds. The rate is calculated by: is the current input a...
+
virtual bool Solve(double input, double timeStep)
Calculate the rate and limits it if exceeds.
Base class of a control element. Provide general methods to other control classes.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: RateLimiter.cpp:77
diff --git a/docs/doxygen/html/_reactive_shunt_element_form_8cpp_source.html b/docs/doxygen/html/_reactive_shunt_element_form_8cpp_source.html index 0b4af60..223e470 100644 --- a/docs/doxygen/html/_reactive_shunt_element_form_8cpp_source.html +++ b/docs/doxygen/html/_reactive_shunt_element_form_8cpp_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_reactive_shunt_element_form_8cpp_sour
ReactiveShuntElementForm.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "SwitchingForm.h"
20 #include "Capacitor.h"
21 #include "Inductor.h"
22 
23 ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Capacitor* capacitor)
25 {
26  SetSize(GetBestSize());
27  CapacitorElectricalData data = capacitor->GetElectricalData();
28 
29  m_textCtrlName->SetValue(data.name);
30 
31  m_textCtrlReactivePower->SetValue(Capacitor::StringFromDouble(data.reactivePower));
32  switch(data.reactivePowerUnit) {
33  case UNIT_PU: {
34  m_choiceReactivePower->SetSelection(0);
35  } break;
36  case UNIT_VAr: {
37  m_choiceReactivePower->SetSelection(1);
38  } break;
39  case UNIT_kVAr: {
40  m_choiceReactivePower->SetSelection(2);
41  } break;
42  case UNIT_MVAr: {
43  m_choiceReactivePower->SetSelection(3);
44  } break;
45  default:
46  break;
47  }
48 
49  m_parent = parent;
50  m_capacitor = capacitor;
51 }
52 
53 ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Inductor* inductor)
55 {
56  InductorElectricalData data = inductor->GetElectricalData();
57 
58  m_textCtrlName->SetValue(data.name);
59 
60  m_textCtrlReactivePower->SetValue(Inductor::StringFromDouble(data.reactivePower));
61  switch(data.reactivePowerUnit) {
62  case UNIT_PU: {
63  m_choiceReactivePower->SetSelection(0);
64  } break;
65  case UNIT_VAr: {
66  m_choiceReactivePower->SetSelection(1);
67  } break;
68  case UNIT_kVAr: {
69  m_choiceReactivePower->SetSelection(2);
70  } break;
71  case UNIT_MVAr: {
72  m_choiceReactivePower->SetSelection(3);
73  } break;
74  default:
75  break;
76  }
77 
78  m_parent = parent;
79  m_inductor = inductor;
80 }
81 
82 ReactiveShuntElementForm::~ReactiveShuntElementForm() {}
83 void ReactiveShuntElementForm::OnOKButtonClick(wxCommandEvent& event)
84 {
85  if(ValidateData()) EndModal(wxID_OK);
86 }
87 
88 void ReactiveShuntElementForm::OnStabilityButtonClick(wxCommandEvent& event)
89 {
90  if(ValidateData()) {
91  if(m_capacitor) {
92  SwitchingForm swForm(m_parent, m_capacitor);
93  swForm.SetTitle(_("Capacitor: Switching"));
94  swForm.ShowModal();
95  } else if(m_inductor) {
96  SwitchingForm swForm(m_parent, m_inductor);
97  swForm.SetTitle(_("Inductor: Switching"));
98  swForm.ShowModal();
99  }
100 
101  EndModal(wxID_OK);
102  }
103 }
104 
105 bool ReactiveShuntElementForm::ValidateData()
106 {
107  if(m_capacitor) {
109 
110  data.name = m_textCtrlName->GetValue();
111 
112  if(!m_capacitor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
113  _("Value entered incorrectly in the field \"Reactive power\".")))
114  return false;
115  switch(m_choiceReactivePower->GetSelection()) {
116  case 0: {
117  data.reactivePowerUnit = UNIT_PU;
118  } break;
119  case 1: {
120  data.reactivePowerUnit = UNIT_VAr;
121  } break;
122  case 2: {
123  data.reactivePowerUnit = UNIT_kVAr;
124  } break;
125  case 3: {
126  data.reactivePowerUnit = UNIT_MVAr;
127  } break;
128  }
129 
130  m_capacitor->SetElectricalData(data);
131  } else if(m_inductor) {
133 
134  data.name = m_textCtrlName->GetValue();
135 
136  if(!m_inductor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
137  _("Value entered incorrectly in the field \"Reactive power\".")))
138  return false;
139  switch(m_choiceReactivePower->GetSelection()) {
140  case 0: {
141  data.reactivePowerUnit = UNIT_PU;
142  } break;
143  case 1: {
144  data.reactivePowerUnit = UNIT_VAr;
145  } break;
146  case 2: {
147  data.reactivePowerUnit = UNIT_kVAr;
148  } break;
149  case 3: {
150  data.reactivePowerUnit = UNIT_MVAr;
151  } break;
152  }
153 
154  m_inductor->SetElectricalData(data);
155  }
156  return true;
157 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "SwitchingForm.h"
20 #include "Capacitor.h"
21 #include "Inductor.h"
22 
23 ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Capacitor* capacitor)
25 {
26  SetSize(GetBestSize());
27  CapacitorElectricalData data = capacitor->GetElectricalData();
28 
29  m_textCtrlName->SetValue(data.name);
30 
31  m_textCtrlReactivePower->SetValue(Capacitor::StringFromDouble(data.reactivePower));
32  switch(data.reactivePowerUnit) {
33  case UNIT_PU: {
34  m_choiceReactivePower->SetSelection(0);
35  } break;
36  case UNIT_VAr: {
37  m_choiceReactivePower->SetSelection(1);
38  } break;
39  case UNIT_kVAr: {
40  m_choiceReactivePower->SetSelection(2);
41  } break;
42  case UNIT_MVAr: {
43  m_choiceReactivePower->SetSelection(3);
44  } break;
45  default:
46  break;
47  }
48 
49  m_parent = parent;
50  m_capacitor = capacitor;
51 }
52 
53 ReactiveShuntElementForm::ReactiveShuntElementForm(wxWindow* parent, Inductor* inductor)
55 {
56  InductorElectricalData data = inductor->GetElectricalData();
57 
58  m_textCtrlName->SetValue(data.name);
59 
60  m_textCtrlReactivePower->SetValue(Inductor::StringFromDouble(data.reactivePower));
61  switch(data.reactivePowerUnit) {
62  case UNIT_PU: {
63  m_choiceReactivePower->SetSelection(0);
64  } break;
65  case UNIT_VAr: {
66  m_choiceReactivePower->SetSelection(1);
67  } break;
68  case UNIT_kVAr: {
69  m_choiceReactivePower->SetSelection(2);
70  } break;
71  case UNIT_MVAr: {
72  m_choiceReactivePower->SetSelection(3);
73  } break;
74  default:
75  break;
76  }
77 
78  m_parent = parent;
79  m_inductor = inductor;
80 }
81 
82 ReactiveShuntElementForm::~ReactiveShuntElementForm() {}
83 void ReactiveShuntElementForm::OnOKButtonClick(wxCommandEvent& event)
84 {
85  if(ValidateData()) EndModal(wxID_OK);
86 }
87 
88 void ReactiveShuntElementForm::OnStabilityButtonClick(wxCommandEvent& event)
89 {
90  if(ValidateData()) {
91  if(m_capacitor) {
92  SwitchingForm swForm(m_parent, m_capacitor);
93  swForm.SetTitle(_("Capacitor: Switching"));
94  swForm.ShowModal();
95  } else if(m_inductor) {
96  SwitchingForm swForm(m_parent, m_inductor);
97  swForm.SetTitle(_("Inductor: Switching"));
98  swForm.ShowModal();
99  }
100 
101  EndModal(wxID_OK);
102  }
103 }
104 
105 bool ReactiveShuntElementForm::ValidateData()
106 {
107  if(m_capacitor) {
109 
110  data.name = m_textCtrlName->GetValue();
111 
112  if(!m_capacitor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
113  _("Value entered incorrectly in the field \"Reactive power\".")))
114  return false;
115  switch(m_choiceReactivePower->GetSelection()) {
116  case 0: {
117  data.reactivePowerUnit = UNIT_PU;
118  } break;
119  case 1: {
120  data.reactivePowerUnit = UNIT_VAr;
121  } break;
122  case 2: {
123  data.reactivePowerUnit = UNIT_kVAr;
124  } break;
125  case 3: {
126  data.reactivePowerUnit = UNIT_MVAr;
127  } break;
128  }
129 
130  m_capacitor->SetElectricalData(data);
131  } else if(m_inductor) {
133 
134  data.name = m_textCtrlName->GetValue();
135 
136  if(!m_inductor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
137  _("Value entered incorrectly in the field \"Reactive power\".")))
138  return false;
139  switch(m_choiceReactivePower->GetSelection()) {
140  case 0: {
141  data.reactivePowerUnit = UNIT_PU;
142  } break;
143  case 1: {
144  data.reactivePowerUnit = UNIT_VAr;
145  } break;
146  case 2: {
147  data.reactivePowerUnit = UNIT_kVAr;
148  } break;
149  case 3: {
150  data.reactivePowerUnit = UNIT_MVAr;
151  } break;
152  }
153 
154  m_inductor->SetElectricalData(data);
155  }
156  return true;
157 }
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
@@ -97,9 +97,11 @@ $(document).ready(function(){initNavTree('_reactive_shunt_element_form_8cpp_sour +
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
- - +
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
+
diff --git a/docs/doxygen/html/_reactive_shunt_element_form_8h_source.html b/docs/doxygen/html/_reactive_shunt_element_form_8h_source.html index 484283a..90b36ac 100644 --- a/docs/doxygen/html/_reactive_shunt_element_form_8h_source.html +++ b/docs/doxygen/html/_reactive_shunt_element_form_8h_source.html @@ -90,8 +90,8 @@ $(document).ready(function(){initNavTree('_reactive_shunt_element_form_8h_source
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef REACTIVESHUNTELEMENTFORM_H
19 #define REACTIVESHUNTELEMENTFORM_H
20 #include "ElementForm.h"
21 #include <wx/log.h>
22 
23 class Capacitor;
24 class Inductor;
25 class SwitchingForm;
26 
35 {
36  public:
37  ReactiveShuntElementForm(wxWindow* parent, Capacitor* capacitor);
38  ReactiveShuntElementForm(wxWindow* parent, Inductor* inductor);
39  virtual ~ReactiveShuntElementForm();
40  virtual bool ValidateData();
41 
42  protected:
43  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
44  virtual void OnOKButtonClick(wxCommandEvent& event);
45  virtual void OnStabilityButtonClick(wxCommandEvent& event);
46 
47  wxWindow* m_parent;
48  Capacitor* m_capacitor = NULL;
49  Inductor* m_inductor = NULL;
50 };
51 #endif // REACTIVESHUNTELEMENTFORM_H
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
- - +
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
Form to edit the reactive shunt element power data.
diff --git a/docs/doxygen/html/_shunt_8cpp_source.html b/docs/doxygen/html/_shunt_8cpp_source.html index 5ac6c86..5823fd9 100644 --- a/docs/doxygen/html/_shunt_8cpp_source.html +++ b/docs/doxygen/html/_shunt_8cpp_source.html @@ -88,8 +88,9 @@ $(document).ready(function(){initNavTree('_shunt_8cpp_source.html','');});
Shunt.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Shunt.h"
19 
20 Shunt::Shunt() : PowerElement() {}
21 Shunt::~Shunt() {}
22 void Shunt::UpdateSwitchesPosition()
23 {
24  if(m_parentList[0]) {
25  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
26  } else {
27  m_pointList[1] = m_pointList[0];
28  }
29  UpdateSwitches();
30 }
31 
32 void Shunt::Move(wxPoint2DDouble position)
33 {
34  SetPosition(m_movePos + position - m_moveStartPt);
35  for(int i = 2; i < (int)m_pointList.size(); i++) {
36  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
37  }
38  if(!m_parentList[0]) {
39  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
40  }
41  UpdateSwitchesPosition();
42  UpdatePowerFlowArrowsPosition();
43 }
44 
45 void Shunt::MoveNode(Element* element, wxPoint2DDouble position)
46 {
47  if(element) {
48  if(element == m_parentList[0]) {
49  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
50  }
51  } else {
52  if(m_activeNodeID == 1) {
53  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
54  if(m_parentList[0]) {
55  m_parentList[0]->RemoveChild(this);
56  m_parentList[0] = NULL;
57  m_online = false;
58  }
59  }
60  }
61 
62  // Recalculate switches positions
63  UpdateSwitchesPosition();
64  UpdatePowerFlowArrowsPosition();
65 }
66 
67 void Shunt::StartMove(wxPoint2DDouble position)
68 {
69  m_moveStartPt = position;
70  m_movePts = m_pointList;
71  m_movePos = m_position;
72 }
73 
75 {
76  if(parent == m_parentList[0]) {
77  m_parentList[0] = NULL;
78  m_online = false;
79  UpdateSwitchesPosition();
80  UpdatePowerFlowArrowsPosition();
81  }
82 }
83 
84 bool Shunt::NodeContains(wxPoint2DDouble position)
85 {
86  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
87  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
88 
89  if(nodeRect.Contains(position)) {
90  m_activeNodeID = 1;
91  return true;
92  }
93 
94  m_activeNodeID = 0;
95  return false;
96 }
97 
99 {
100  if(parent && m_activeNodeID != 0) {
101  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
102  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
103 
104  if(parent->Intersects(nodeRect)) {
105  m_parentList[0] = parent;
106 
107  // Centralize the node on bus.
108  wxPoint2DDouble parentPt =
109  parent->RotateAtPosition(m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
110  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
111  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
112  m_pointList[0] = parentPt;
113 
114  UpdateSwitchesPosition();
115  UpdatePowerFlowArrowsPosition();
116  return true;
117  } else {
118  m_parentList[0] = NULL;
119  m_online = false;
120  }
121  }
122  return false;
123 }
124 
126 {
127  if(m_parentList[0]) {
128  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
129  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
130 
131  if(!m_parentList[0]->Intersects(nodeRect)) {
132  m_parentList[0]->RemoveChild(this);
133  m_parentList[0] = NULL;
134  m_online = false;
135  UpdateSwitchesPosition();
136  UpdatePowerFlowArrowsPosition();
137  }
138  }
139 }
140 
141 void Shunt::RotateNode(Element* parent, bool clockwise)
142 {
143  double rotAngle = m_rotationAngle;
144  if(!clockwise) rotAngle = -m_rotationAngle;
145 
146  if(parent == m_parentList[0]) {
147  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
148  UpdateSwitchesPosition();
149  UpdatePowerFlowArrowsPosition();
150  }
151 }
152 
153 void Shunt::DrawGround(wxPoint2DDouble position) const
154 {
155  std::vector<wxPoint2DDouble> groundPts;
156  groundPts.push_back(position);
157  groundPts.push_back(position + wxPoint2DDouble(0, 10));
158  groundPts.push_back(position + wxPoint2DDouble(-10, 10));
159  groundPts.push_back(position + wxPoint2DDouble(10, 10));
160  groundPts.push_back(position + wxPoint2DDouble(-6, 15));
161  groundPts.push_back(position + wxPoint2DDouble(6, 15));
162  groundPts.push_back(position + wxPoint2DDouble(-3, 20));
163  groundPts.push_back(position + wxPoint2DDouble(3, 20));
164 
165  DrawLine(groundPts, GL_LINES);
166 }
167 
168 void Shunt::UpdatePowerFlowArrowsPosition()
169 {
170  std::vector<wxPoint2DDouble> edges;
171  switch(m_pfDirection) {
172  case PF_NONE: {
173  m_powerFlowArrow.clear();
174  } break;
175  case PF_TO_BUS: {
176  edges.push_back(m_pointList[2]);
177  edges.push_back(m_pointList[1]);
178  } break;
179  case PF_TO_ELEMENT: {
180  edges.push_back(m_pointList[1]);
181  edges.push_back(m_pointList[2]);
182  } break;
183  default:
184  break;
185  }
186  CalculatePowerFlowPts(edges);
187 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Shunt.h"
19 
20 Shunt::Shunt() : PowerElement() {}
21 Shunt::~Shunt() {}
22 void Shunt::UpdateSwitchesPosition()
23 {
24  if(m_parentList[0]) {
25  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], m_pointList[2]);
26  } else {
27  m_pointList[1] = m_pointList[0];
28  }
29  UpdateSwitches();
30 }
31 
32 void Shunt::Move(wxPoint2DDouble position)
33 {
34  SetPosition(m_movePos + position - m_moveStartPt);
35  for(int i = 2; i < (int)m_pointList.size(); i++) {
36  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
37  }
38  if(!m_parentList[0]) {
39  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
40  }
41  UpdateSwitchesPosition();
42  UpdatePowerFlowArrowsPosition();
43 }
44 
45 void Shunt::MoveNode(Element* element, wxPoint2DDouble position)
46 {
47  if(element) {
48  if(element == m_parentList[0]) {
49  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
50  }
51  } else {
52  if(m_activeNodeID == 1) {
53  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
54  if(m_parentList[0]) {
55  m_parentList[0]->RemoveChild(this);
56  m_parentList[0] = NULL;
57  m_online = false;
58  }
59  }
60  }
61 
62  // Recalculate switches positions
63  UpdateSwitchesPosition();
64  UpdatePowerFlowArrowsPosition();
65 }
66 
67 void Shunt::StartMove(wxPoint2DDouble position)
68 {
69  m_moveStartPt = position;
70  m_movePts = m_pointList;
71  m_movePos = m_position;
72 }
73 
75 {
76  if(parent == m_parentList[0]) {
77  m_parentList[0] = NULL;
78  m_online = false;
79  UpdateSwitchesPosition();
80  UpdatePowerFlowArrowsPosition();
81  }
82 }
83 
84 bool Shunt::NodeContains(wxPoint2DDouble position)
85 {
86  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
87  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
88 
89  if(nodeRect.Contains(position)) {
90  m_activeNodeID = 1;
91  return true;
92  }
93 
94  m_activeNodeID = 0;
95  return false;
96 }
97 
99 {
100  if(parent && m_activeNodeID != 0) {
101  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
102  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
103 
104  if(parent->Intersects(nodeRect)) {
105  m_parentList[0] = parent;
106 
107  // Centralize the node on bus.
108  wxPoint2DDouble parentPt =
109  parent->RotateAtPosition(m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
110  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
111  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
112  m_pointList[0] = parentPt;
113 
114  UpdateSwitchesPosition();
115  UpdatePowerFlowArrowsPosition();
116  return true;
117  } else {
118  m_parentList[0] = NULL;
119  m_online = false;
120  }
121  }
122  return false;
123 }
124 
126 {
127  if(m_parentList[0]) {
128  wxRect2DDouble nodeRect(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
129  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
130 
131  if(!m_parentList[0]->Intersects(nodeRect)) {
132  m_parentList[0]->RemoveChild(this);
133  m_parentList[0] = NULL;
134  m_online = false;
135  UpdateSwitchesPosition();
136  UpdatePowerFlowArrowsPosition();
137  }
138  }
139 }
140 
141 void Shunt::RotateNode(Element* parent, bool clockwise)
142 {
143  double rotAngle = m_rotationAngle;
144  if(!clockwise) rotAngle = -m_rotationAngle;
145 
146  if(parent == m_parentList[0]) {
147  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
148  UpdateSwitchesPosition();
149  UpdatePowerFlowArrowsPosition();
150  }
151 }
152 
153 void Shunt::DrawGround(wxPoint2DDouble position) const
154 {
155  std::vector<wxPoint2DDouble> groundPts;
156  groundPts.push_back(position);
157  groundPts.push_back(position + wxPoint2DDouble(0, 10));
158  groundPts.push_back(position + wxPoint2DDouble(-10, 10));
159  groundPts.push_back(position + wxPoint2DDouble(10, 10));
160  groundPts.push_back(position + wxPoint2DDouble(-6, 15));
161  groundPts.push_back(position + wxPoint2DDouble(6, 15));
162  groundPts.push_back(position + wxPoint2DDouble(-3, 20));
163  groundPts.push_back(position + wxPoint2DDouble(3, 20));
164 
165  DrawLine(groundPts, GL_LINES);
166 }
167 
168 void Shunt::UpdatePowerFlowArrowsPosition()
169 {
170  std::vector<wxPoint2DDouble> edges;
171  switch(m_pfDirection) {
172  case PF_NONE: {
173  m_powerFlowArrow.clear();
174  } break;
175  case PF_TO_BUS: {
176  edges.push_back(m_pointList[2]);
177  edges.push_back(m_pointList[1]);
178  } break;
179  case PF_TO_ELEMENT: {
180  edges.push_back(m_pointList[1]);
181  edges.push_back(m_pointList[2]);
182  } break;
183  default:
184  break;
185  }
186  CalculatePowerFlowPts(edges);
187 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Shunt.cpp:45
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Shunt.cpp:125
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Shunt.cpp:74
@@ -103,7 +104,7 @@ $(document).ready(function(){initNavTree('_shunt_8cpp_source.html','');});
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Shunt.cpp:98
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement...
Definition: Shunt.cpp:84
- +
Abstract class of power elements.
Definition: PowerElement.h:117
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
diff --git a/docs/doxygen/html/_shunt_8h.html b/docs/doxygen/html/_shunt_8h.html new file mode 100644 index 0000000..6562b7d --- /dev/null +++ b/docs/doxygen/html/_shunt_8h.html @@ -0,0 +1,116 @@ + + + + + + + + + +Project/Shunt.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Shunt.h File Reference
+
+
+
#include "PowerElement.h"
+#include "Bus.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  Shunt
 Abstract class for shunt power elements. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_shunt_8h_source.html b/docs/doxygen/html/_shunt_8h_source.html index a047246..193f8f3 100644 --- a/docs/doxygen/html/_shunt_8h_source.html +++ b/docs/doxygen/html/_shunt_8h_source.html @@ -88,26 +88,27 @@ $(document).ready(function(){initNavTree('_shunt_8h_source.html','');});
Shunt.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SHUNT_H
19 #define SHUNT_H
20 
21 #include "PowerElement.h"
22 #include "Bus.h"
23 
24 class Shunt : public PowerElement
25 {
26  public:
27  Shunt();
28  ~Shunt();
29 
30  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
31  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
32  virtual void Move(wxPoint2DDouble position);
33  virtual void MoveNode(Element* element, wxPoint2DDouble position);
34  virtual void StartMove(wxPoint2DDouble position);
35  virtual void RotateNode(Element* parent, bool clockwise = true);
36  virtual void RemoveParent(Element* parent);
37  virtual bool NodeContains(wxPoint2DDouble position);
38  virtual bool SetNodeParent(Element* parent);
39  virtual void UpdateNodes();
40 
41  protected:
42  void UpdateSwitchesPosition();
43  void UpdatePowerFlowArrowsPosition();
44  void DrawGround(wxPoint2DDouble position) const;
45  bool m_inserted = false;
46 };
47 
48 #endif // SHUNT_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SHUNT_H
19 #define SHUNT_H
20 
21 #include "PowerElement.h"
22 #include "Bus.h"
23 
31 class Shunt : public PowerElement
32 {
33  public:
34  Shunt();
35  ~Shunt();
36 
37  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
38  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
39  virtual void Move(wxPoint2DDouble position);
40  virtual void MoveNode(Element* element, wxPoint2DDouble position);
41  virtual void StartMove(wxPoint2DDouble position);
42  virtual void RotateNode(Element* parent, bool clockwise = true);
43  virtual void RemoveParent(Element* parent);
44  virtual bool NodeContains(wxPoint2DDouble position);
45  virtual bool SetNodeParent(Element* parent);
46  virtual void UpdateNodes();
47 
48  protected:
49  void UpdateSwitchesPosition();
50  void UpdatePowerFlowArrowsPosition();
51  void DrawGround(wxPoint2DDouble position) const;
52  bool m_inserted = false;
53 };
54 
55 #endif // SHUNT_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void MoveNode(Element *element, wxPoint2DDouble position)
Move a node. StartMove(wxPoint2DDouble position) before start moving.
Definition: Shunt.cpp:45
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Shunt.cpp:125
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Shunt.cpp:74
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition: Shunt.cpp:141
+
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Shunt.cpp:32
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Shunt.h:30
-
Switching data of power elements.
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Shunt.h:37
+
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Shunt.cpp:67
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Shunt.cpp:98
virtual bool NodeContains(wxPoint2DDouble position)
Check if a node contains a point. If contains, set the attributes related to node movement...
Definition: Shunt.cpp:84
- -
Definition: Shunt.h:24
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Shunt.h:31
+
Abstract class of power elements.
Definition: PowerElement.h:117
+
Abstract class for shunt power elements.
Definition: Shunt.h:31
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Shunt.h:38
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "PropertiesData.h"
20 
21 SimulationsSettingsForm::SimulationsSettingsForm(wxWindow* parent, PropertiesData* properties)
23 {
24  m_properties = properties;
25  auto data = m_properties->GetSimulationPropertiesData();
26 
27  m_textCtrlbasePower->SetValue(Element::StringFromDouble(data.basePower));
28  switch(data.basePowerUnit) {
29  case UNIT_VA: {
30  m_choiceBasePower->SetSelection(0);
31  } break;
32  case UNIT_kVA: {
33  m_choiceBasePower->SetSelection(1);
34  } break;
35  case UNIT_MVA: {
36  m_choiceBasePower->SetSelection(2);
37  } break;
38  default: {
39  m_choiceBasePower->SetSelection(wxNOT_FOUND);
40  } break;
41  }
42  m_checkBoxFaultAfterPF->SetValue(data.faultAfterPowerFlow);
43  m_checkBoxSCPowerAfterPF->SetValue(data.scPowerAfterPowerFlow);
44  switch(data.powerFlowMethod) {
45  case GAUSS_SEIDEL: {
46  m_choicePFMethod->SetSelection(0);
47  } break;
48  case NEWTON_RAPHSON: {
49  m_choicePFMethod->SetSelection(1);
50  m_textCtrlAccFactor->Enable(false);
51  } break;
52  default: {
53  m_choicePFMethod->SetSelection(wxNOT_FOUND);
54  } break;
55  }
56  m_textCtrlAccFactor->SetValue(Element::StringFromDouble(data.accFator));
57  m_textCtrlPFTolerance->SetValue(wxString::Format("%g", data.powerFlowTolerance));
58  m_textCtrlPFMaxIterations->SetValue(wxString::Format("%d", data.powerFlowMaxIterations));
59  m_textCtrlTimeStep->SetValue(wxString::Format("%g", data.timeStep));
60  m_textCtrlSimTime->SetValue(Element::StringFromDouble(data.stabilitySimulationTime));
61  m_textCtrlFreq->SetValue(Element::StringFromDouble(data.stabilityFrequency));
62  m_textCtrlStabTolerance->SetValue(wxString::Format("%g", data.stabilityTolerance));
63  m_textCtrlStabMaxIterations->SetValue(wxString::Format("%d", data.stabilityMaxIterations));
64  m_textCtrlCtrlStepRatio->SetValue(wxString::Format("%d", data.controlTimeStepRatio));
65  m_textCtrlPrintTime->SetValue(wxString::Format("%g", data.plotTime));
66 
67  m_checkBoxUseCOI->SetValue(data.useCOI);
68 }
69 
70 SimulationsSettingsForm::~SimulationsSettingsForm() {}
71 void SimulationsSettingsForm::OnButtonOKClick(wxCommandEvent& event)
72 {
73  if(ValidateData()) EndModal(wxID_OK);
74 }
75 
76 bool SimulationsSettingsForm::ValidateData()
77 {
78  auto data = m_properties->GetSimulationPropertiesData();
79  if(!Element::DoubleFromString(this, m_textCtrlbasePower->GetValue(), data.basePower,
80  _("Value entered incorrectly in the field \"Base power\".")))
81  return false;
82  switch(m_choiceBasePower->GetSelection()) {
83  case 0: {
84  data.basePowerUnit = UNIT_VA;
85  } break;
86  case 1: {
87  data.basePowerUnit = UNIT_kVA;
88  } break;
89  default: {
90  data.basePowerUnit = UNIT_MVA;
91  } break;
92  }
93  data.faultAfterPowerFlow = m_checkBoxFaultAfterPF->GetValue();
94  data.scPowerAfterPowerFlow = m_checkBoxSCPowerAfterPF->GetValue();
95  switch(m_choicePFMethod->GetSelection()) {
96  case 0: {
97  data.powerFlowMethod = GAUSS_SEIDEL;
98  } break;
99  case 1: {
100  data.powerFlowMethod = NEWTON_RAPHSON;
101  } break;
102  }
103  if(!Element::DoubleFromString(this, m_textCtrlAccFactor->GetValue(), data.accFator,
104  _("Value entered incorrectly in the field \"Acceleration factor\".")))
105  return false;
106  if(!Element::DoubleFromString(this, m_textCtrlPFTolerance->GetValue(), data.powerFlowTolerance,
107  _("Value entered incorrectly in the field \"Tolerance (Power flow)\".")))
108  return false;
109  if(!Element::IntFromString(this, m_textCtrlPFMaxIterations->GetValue(), data.powerFlowMaxIterations,
110  _("Value entered incorrectly in the field \"Max. iterations (Power flow)\".")))
111  return false;
112  if(!Element::DoubleFromString(this, m_textCtrlTimeStep->GetValue(), data.timeStep,
113  _("Value entered incorrectly in the field \"Time step\".")))
114  return false;
115  if(!Element::DoubleFromString(this, m_textCtrlSimTime->GetValue(), data.stabilitySimulationTime,
116  _("Value entered incorrectly in the field \"Simulation time\".")))
117  return false;
118  if(!Element::DoubleFromString(this, m_textCtrlFreq->GetValue(), data.stabilityFrequency,
119  _("Value entered incorrectly in the field \"System frequency\".")))
120  return false;
121  if(!Element::DoubleFromString(this, m_textCtrlStabTolerance->GetValue(), data.stabilityTolerance,
122  _("Value entered incorrectly in the field \"Tolerance (Stability)\".")))
123  return false;
124  if(!Element::IntFromString(this, m_textCtrlStabMaxIterations->GetValue(), data.stabilityMaxIterations,
125  _("Value entered incorrectly in the field \"Max. iterations (Stability)\".")))
126  return false;
127  if(!Element::IntFromString(this, m_textCtrlCtrlStepRatio->GetValue(), data.controlTimeStepRatio,
128  _("Value entered incorrectly in the field \"Controls step ratio\".")))
129  return false;
130  if(!Element::DoubleFromString(this, m_textCtrlPrintTime->GetValue(), data.plotTime,
131  _("Value entered incorrectly in the field \"Plot time\".")))
132  return false;
133  data.useCOI = m_checkBoxUseCOI->GetValue();
134 
135  m_properties->SetSimulationPropertiesData(data);
136  return true;
137 }
138 void SimulationsSettingsForm::OnPFMethodChoiceSelected(wxCommandEvent& event)
139 {
140  if(m_choicePFMethod->GetSelection() == 0)
141  m_textCtrlAccFactor->Enable();
142  else
143  m_textCtrlAccFactor->Enable(false);
144 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
19 #include "PropertiesData.h"
20 
21 SimulationsSettingsForm::SimulationsSettingsForm(wxWindow* parent, PropertiesData* properties)
23 {
24  m_properties = properties;
25  auto data = m_properties->GetSimulationPropertiesData();
26 
27  m_textCtrlbasePower->SetValue(Element::StringFromDouble(data.basePower));
28  switch(data.basePowerUnit) {
29  case UNIT_VA: {
30  m_choiceBasePower->SetSelection(0);
31  } break;
32  case UNIT_kVA: {
33  m_choiceBasePower->SetSelection(1);
34  } break;
35  case UNIT_MVA: {
36  m_choiceBasePower->SetSelection(2);
37  } break;
38  default: {
39  m_choiceBasePower->SetSelection(wxNOT_FOUND);
40  } break;
41  }
42  m_checkBoxFaultAfterPF->SetValue(data.faultAfterPowerFlow);
43  m_checkBoxSCPowerAfterPF->SetValue(data.scPowerAfterPowerFlow);
44  switch(data.powerFlowMethod) {
45  case GAUSS_SEIDEL: {
46  m_choicePFMethod->SetSelection(0);
47  } break;
48  case NEWTON_RAPHSON: {
49  m_choicePFMethod->SetSelection(1);
50  m_textCtrlAccFactor->Enable(false);
51  } break;
52  default: {
53  m_choicePFMethod->SetSelection(wxNOT_FOUND);
54  } break;
55  }
56  m_textCtrlAccFactor->SetValue(Element::StringFromDouble(data.accFator));
57  m_textCtrlPFTolerance->SetValue(wxString::Format("%g", data.powerFlowTolerance));
58  m_textCtrlPFMaxIterations->SetValue(wxString::Format("%d", data.powerFlowMaxIterations));
59  m_textCtrlTimeStep->SetValue(wxString::Format("%g", data.timeStep));
60  m_textCtrlSimTime->SetValue(Element::StringFromDouble(data.stabilitySimulationTime));
61  m_textCtrlFreq->SetValue(Element::StringFromDouble(data.stabilityFrequency));
62  m_textCtrlStabTolerance->SetValue(wxString::Format("%g", data.stabilityTolerance));
63  m_textCtrlStabMaxIterations->SetValue(wxString::Format("%d", data.stabilityMaxIterations));
64  m_textCtrlCtrlStepRatio->SetValue(wxString::Format("%d", data.controlTimeStepRatio));
65  m_textCtrlPrintTime->SetValue(wxString::Format("%g", data.plotTime));
66 
67  m_checkBoxUseCOI->SetValue(data.useCOI);
68 }
69 
70 SimulationsSettingsForm::~SimulationsSettingsForm() {}
71 void SimulationsSettingsForm::OnButtonOKClick(wxCommandEvent& event)
72 {
73  if(ValidateData()) EndModal(wxID_OK);
74 }
75 
76 bool SimulationsSettingsForm::ValidateData()
77 {
78  auto data = m_properties->GetSimulationPropertiesData();
79  if(!Element::DoubleFromString(this, m_textCtrlbasePower->GetValue(), data.basePower,
80  _("Value entered incorrectly in the field \"Base power\".")))
81  return false;
82  switch(m_choiceBasePower->GetSelection()) {
83  case 0: {
84  data.basePowerUnit = UNIT_VA;
85  } break;
86  case 1: {
87  data.basePowerUnit = UNIT_kVA;
88  } break;
89  default: {
90  data.basePowerUnit = UNIT_MVA;
91  } break;
92  }
93  data.faultAfterPowerFlow = m_checkBoxFaultAfterPF->GetValue();
94  data.scPowerAfterPowerFlow = m_checkBoxSCPowerAfterPF->GetValue();
95  switch(m_choicePFMethod->GetSelection()) {
96  case 0: {
97  data.powerFlowMethod = GAUSS_SEIDEL;
98  } break;
99  case 1: {
100  data.powerFlowMethod = NEWTON_RAPHSON;
101  } break;
102  }
103  if(!Element::DoubleFromString(this, m_textCtrlAccFactor->GetValue(), data.accFator,
104  _("Value entered incorrectly in the field \"Acceleration factor\".")))
105  return false;
106  if(!Element::DoubleFromString(this, m_textCtrlPFTolerance->GetValue(), data.powerFlowTolerance,
107  _("Value entered incorrectly in the field \"Tolerance (Power flow)\".")))
108  return false;
109  if(!Element::IntFromString(this, m_textCtrlPFMaxIterations->GetValue(), data.powerFlowMaxIterations,
110  _("Value entered incorrectly in the field \"Max. iterations (Power flow)\".")))
111  return false;
112  if(!Element::DoubleFromString(this, m_textCtrlTimeStep->GetValue(), data.timeStep,
113  _("Value entered incorrectly in the field \"Time step\".")))
114  return false;
115  if(!Element::DoubleFromString(this, m_textCtrlSimTime->GetValue(), data.stabilitySimulationTime,
116  _("Value entered incorrectly in the field \"Simulation time\".")))
117  return false;
118  if(!Element::DoubleFromString(this, m_textCtrlFreq->GetValue(), data.stabilityFrequency,
119  _("Value entered incorrectly in the field \"System frequency\".")))
120  return false;
121  if(!Element::DoubleFromString(this, m_textCtrlStabTolerance->GetValue(), data.stabilityTolerance,
122  _("Value entered incorrectly in the field \"Tolerance (Stability)\".")))
123  return false;
124  if(!Element::IntFromString(this, m_textCtrlStabMaxIterations->GetValue(), data.stabilityMaxIterations,
125  _("Value entered incorrectly in the field \"Max. iterations (Stability)\".")))
126  return false;
127  if(!Element::IntFromString(this, m_textCtrlCtrlStepRatio->GetValue(), data.controlTimeStepRatio,
128  _("Value entered incorrectly in the field \"Controls step ratio\".")))
129  return false;
130  if(!Element::DoubleFromString(this, m_textCtrlPrintTime->GetValue(), data.plotTime,
131  _("Value entered incorrectly in the field \"Plot time\".")))
132  return false;
133  data.useCOI = m_checkBoxUseCOI->GetValue();
134 
135  m_properties->SetSimulationPropertiesData(data);
136  return true;
137 }
138 void SimulationsSettingsForm::OnPFMethodChoiceSelected(wxCommandEvent& event)
139 {
140  if(m_choicePFMethod->GetSelection() == 0)
141  m_textCtrlAccFactor->Enable();
142  else
143  m_textCtrlAccFactor->Enable(false);
144 }
General and simulation data manager.
+
static bool DoubleFromString(wxWindow *parent, wxString strValue, double &value, wxString errorMsg)
Get a double value from a string. Show a error message if the conversion fail.
Definition: Element.cpp:292
diff --git a/docs/doxygen/html/_simulations_settings_form_8h_source.html b/docs/doxygen/html/_simulations_settings_form_8h_source.html index 2cf48f0..f10796a 100644 --- a/docs/doxygen/html/_simulations_settings_form_8h_source.html +++ b/docs/doxygen/html/_simulations_settings_form_8h_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_simulations_settings_form_8h_source.h
SimulationsSettingsForm.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SIMULATIONSSETTINGSFORM_H
19 #define SIMULATIONSSETTINGSFORM_H
20 
21 #include "PropertiesForm.h"
22 
23 class PropertiesData;
24 
33 {
34  public:
35  SimulationsSettingsForm(wxWindow* parent, PropertiesData* properties);
36  virtual ~SimulationsSettingsForm();
37 
38  protected:
39  virtual void OnPFMethodChoiceSelected(wxCommandEvent& event);
40  virtual void OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
41  virtual void OnButtonOKClick(wxCommandEvent& event);
42  virtual bool ValidateData();
43 
44  PropertiesData* m_properties;
45 };
46 #endif // SIMULATIONSSETTINGSFORM_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SIMULATIONSSETTINGSFORM_H
19 #define SIMULATIONSSETTINGSFORM_H
20 
21 #include "PropertiesForm.h"
22 
23 class PropertiesData;
24 
33 {
34  public:
35  SimulationsSettingsForm(wxWindow* parent, PropertiesData* properties);
36  virtual ~SimulationsSettingsForm();
37 
38  protected:
39  virtual void OnPFMethodChoiceSelected(wxCommandEvent& event);
40  virtual void OnButtonCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
41  virtual void OnButtonOKClick(wxCommandEvent& event);
42  virtual bool ValidateData();
43 
44  PropertiesData* m_properties;
45 };
46 #endif // SIMULATIONSSETTINGSFORM_H
General and simulation data manager.
Form to edit the simulation data.
diff --git a/docs/doxygen/html/_sum_8cpp_source.html b/docs/doxygen/html/_sum_8cpp_source.html index 46f2a05..953673a 100644 --- a/docs/doxygen/html/_sum_8cpp_source.html +++ b/docs/doxygen/html/_sum_8cpp_source.html @@ -88,15 +88,16 @@ $(document).ready(function(){initNavTree('_sum_8cpp_source.html','');});
Sum.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Sum.h"
19 #include "SumForm.h"
20 #include "ConnectionLine.h"
21 
22 Sum::Sum(int id) : ControlElement(id)
23 {
24  m_width = m_height = 36.0;
25  Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NODE_IN, m_borderSize);
26  nodeIn1->StartMove(m_position);
27  Node* nodeIn2 =
28  new Node(m_position + wxPoint2DDouble(-m_width / 2, 27 - m_height / 2), Node::NODE_IN, m_borderSize);
29  nodeIn2->StartMove(m_position);
30  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
31  nodeOut->SetAngle(180.0);
32  nodeOut->StartMove(m_position);
33  m_nodeList.push_back(nodeIn1);
34  m_nodeList.push_back(nodeIn2);
35  m_nodeList.push_back(nodeOut);
36  m_signalList.push_back(SIGNAL_POSITIVE);
37  m_signalList.push_back(SIGNAL_NEGATIVE);
38 
39  UpdatePoints();
40 }
41 
42 Sum::~Sum() {}
43 void Sum::Draw(wxPoint2DDouble translation, double scale) const
44 {
45  glLineWidth(1.0);
46  if(m_selected) {
47  glColor4dv(m_selectionColour.GetRGBA());
48  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
49  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
50  }
51  glColor4d(1.0, 1.0, 1.0, 1.0);
52  DrawRectangle(m_position, m_width, m_height);
53  glColor4d(0.0, 0.0, 0.0, 1.0);
54  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
55 
56  // Plot signals.
57  glLineWidth(2.0);
58  wxPoint2DDouble signalOffset[4];
59  wxPoint2DDouble sigmaOffset;
60  if(m_angle == 0.0) {
61  signalOffset[0] = wxPoint2DDouble(6, 0);
62  signalOffset[1] = wxPoint2DDouble(12, 0);
63  signalOffset[2] = wxPoint2DDouble(9, -3);
64  signalOffset[3] = wxPoint2DDouble(9, 3);
65  sigmaOffset = wxPoint2DDouble(6, 0);
66  } else if(m_angle == 90.0) {
67  signalOffset[0] = wxPoint2DDouble(-3, 9);
68  signalOffset[1] = wxPoint2DDouble(3, 9);
69  signalOffset[2] = wxPoint2DDouble(0, 6);
70  signalOffset[3] = wxPoint2DDouble(0, 12);
71  sigmaOffset = wxPoint2DDouble(0, 6);
72  } else if(m_angle == 180.0) {
73  signalOffset[0] = wxPoint2DDouble(-6, 0);
74  signalOffset[1] = wxPoint2DDouble(-12, 0);
75  signalOffset[2] = wxPoint2DDouble(-9, -3);
76  signalOffset[3] = wxPoint2DDouble(-9, 3);
77  sigmaOffset = wxPoint2DDouble(-6, 0);
78  } else if(m_angle == 270.0) {
79  signalOffset[0] = wxPoint2DDouble(-3, -9);
80  signalOffset[1] = wxPoint2DDouble(3, -9);
81  signalOffset[2] = wxPoint2DDouble(0, -6);
82  signalOffset[3] = wxPoint2DDouble(0, -12);
83  sigmaOffset = wxPoint2DDouble(0, -6);
84  }
85  for(int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
86  std::vector<wxPoint2DDouble> hLine;
87  hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[0]);
88  hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[1]);
89  DrawLine(hLine);
90  if(m_signalList[i] == SIGNAL_POSITIVE) {
91  std::vector<wxPoint2DDouble> vLine;
92  vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[2]);
93  vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[3]);
94  DrawLine(vLine);
95  }
96  }
97 
98  // Plot sigma.
99  std::vector<wxPoint2DDouble> sigma;
100  sigma.push_back(m_position + wxPoint2DDouble(4, 9) + sigmaOffset);
101  sigma.push_back(m_position + wxPoint2DDouble(-6, 9) + sigmaOffset);
102  sigma.push_back(m_position + wxPoint2DDouble(0, 0) + sigmaOffset);
103  sigma.push_back(m_position + wxPoint2DDouble(-6, -9) + sigmaOffset);
104  sigma.push_back(m_position + wxPoint2DDouble(4, -9) + sigmaOffset);
105  glColor4d(0.0, 0.3, 1.0, 1.0);
106  DrawLine(sigma);
107 
108  glColor4d(0.0, 0.0, 0.0, 1.0);
109  DrawNodes();
110 }
111 
112 bool Sum::ShowForm(wxWindow* parent, Element* element)
113 {
114  SumForm* sumForm = new SumForm(parent, this);
115  if(sumForm->ShowModal() == wxID_OK) {
116  sumForm->Destroy();
117  return true;
118  }
119  sumForm->Destroy();
120  return false;
121 }
122 
123 void Sum::UpdatePoints()
124 {
125  if(m_angle == 0.0 || m_angle == 180.0) {
126  m_height = 18.0 * (m_nodeList.size() - 1);
127  m_width = 36.0;
128  } else {
129  m_width = 18.0 * (m_nodeList.size() - 1);
130  m_height = 42.0;
131  }
132 
133  for(int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
134  if(m_angle == 0.0)
135  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
136  else if(m_angle == 90.0)
137  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
138  else if(m_angle == 180.0)
139  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
140  else if(m_angle == 270.0)
141  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
142  }
143  if(m_angle == 0.0)
144  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
145  else if(m_angle == 90.0)
146  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
147  else if(m_angle == 180.0)
148  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
149  else if(m_angle == 270.0)
150  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
151 
152  SetPosition(m_position); // Update rect.
153 }
154 
155 void Sum::AddInNode()
156 {
157  Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NODE_IN, m_borderSize);
158  newNode->SetAngle(m_angle);
159  m_nodeList.insert(m_nodeList.end() - 1, newNode);
160 }
161 
162 void Sum::RemoveInNode()
163 {
164  Node* nodeToRemove = *(m_nodeList.end() - 2);
165  bool foundChild = false;
166  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
167  ControlElement* child = static_cast<ControlElement*>(*it);
168  auto childNodeList = child->GetNodeList();
169  for(auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
170  Node* node = *itN;
171  if(node == nodeToRemove) {
172  child->RemoveParent(this);
173  RemoveChild(child);
174  foundChild = true;
175  break;
176  }
177  }
178  if(foundChild) break;
179  }
180  m_nodeList.erase(m_nodeList.end() - 2);
181 }
182 
183 void Sum::Rotate(bool clockwise)
184 {
185  if(clockwise)
186  m_angle += 90.0;
187  else
188  m_angle -= 90.0;
189  if(m_angle >= 360.0)
190  m_angle = 0.0;
191  else if(m_angle < 0)
192  m_angle = 270.0;
193 
194  UpdatePoints();
195 
196  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
197  Node* node = *it;
198  node->Rotate(clockwise);
199  }
200 }
201 
202 bool Sum::Solve(double input, double timeStep)
203 {
204  std::vector<double> inputVector;
205  for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
206  Node* node = *itN;
207  if(node->GetNodeType() != Node::NODE_OUT) {
208  if(!node->IsConnected()) {
209  inputVector.push_back(0.0);
210  } else {
211  for(auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
212  ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
213  auto nodeList = cLine->GetNodeList();
214  for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
215  Node* childNode = *itCN;
216  if(childNode == node) {
217  inputVector.push_back(cLine->GetValue());
218  break;
219  }
220  }
221  }
222  }
223  }
224  }
225 
226  if(m_signalList.size() != inputVector.size()) return false;
227 
228  m_output = 0.0;
229  for(unsigned int i = 0; i < m_signalList.size(); ++i) {
230  if(m_signalList[i] == SIGNAL_POSITIVE)
231  m_output += inputVector[i];
232  else if(m_signalList[i] == SIGNAL_NEGATIVE)
233  m_output -= inputVector[i];
234  }
235  return true;
236 }
237 
239 {
240  Sum* copy = new Sum(m_elementID);
241  *copy = *this;
242  return copy;
243 }
Form to edit the sum control data.
Definition: SumForm.h:32
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Sum.h"
19 #include "SumForm.h"
20 #include "ConnectionLine.h"
21 
22 Sum::Sum(int id) : ControlElement(id)
23 {
24  m_width = m_height = 36.0;
25  Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NODE_IN, m_borderSize);
26  nodeIn1->StartMove(m_position);
27  Node* nodeIn2 =
28  new Node(m_position + wxPoint2DDouble(-m_width / 2, 27 - m_height / 2), Node::NODE_IN, m_borderSize);
29  nodeIn2->StartMove(m_position);
30  Node* nodeOut = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
31  nodeOut->SetAngle(180.0);
32  nodeOut->StartMove(m_position);
33  m_nodeList.push_back(nodeIn1);
34  m_nodeList.push_back(nodeIn2);
35  m_nodeList.push_back(nodeOut);
36  m_signalList.push_back(SIGNAL_POSITIVE);
37  m_signalList.push_back(SIGNAL_NEGATIVE);
38 
39  UpdatePoints();
40 }
41 
42 Sum::~Sum() {}
43 void Sum::Draw(wxPoint2DDouble translation, double scale) const
44 {
45  glLineWidth(1.0);
46  if(m_selected) {
47  glColor4dv(m_selectionColour.GetRGBA());
48  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
49  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
50  }
51  glColor4d(1.0, 1.0, 1.0, 1.0);
52  DrawRectangle(m_position, m_width, m_height);
53  glColor4d(0.0, 0.0, 0.0, 1.0);
54  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
55 
56  // Plot signals.
57  glLineWidth(2.0);
58  wxPoint2DDouble signalOffset[4];
59  wxPoint2DDouble sigmaOffset;
60  if(m_angle == 0.0) {
61  signalOffset[0] = wxPoint2DDouble(6, 0);
62  signalOffset[1] = wxPoint2DDouble(12, 0);
63  signalOffset[2] = wxPoint2DDouble(9, -3);
64  signalOffset[3] = wxPoint2DDouble(9, 3);
65  sigmaOffset = wxPoint2DDouble(6, 0);
66  } else if(m_angle == 90.0) {
67  signalOffset[0] = wxPoint2DDouble(-3, 9);
68  signalOffset[1] = wxPoint2DDouble(3, 9);
69  signalOffset[2] = wxPoint2DDouble(0, 6);
70  signalOffset[3] = wxPoint2DDouble(0, 12);
71  sigmaOffset = wxPoint2DDouble(0, 6);
72  } else if(m_angle == 180.0) {
73  signalOffset[0] = wxPoint2DDouble(-6, 0);
74  signalOffset[1] = wxPoint2DDouble(-12, 0);
75  signalOffset[2] = wxPoint2DDouble(-9, -3);
76  signalOffset[3] = wxPoint2DDouble(-9, 3);
77  sigmaOffset = wxPoint2DDouble(-6, 0);
78  } else if(m_angle == 270.0) {
79  signalOffset[0] = wxPoint2DDouble(-3, -9);
80  signalOffset[1] = wxPoint2DDouble(3, -9);
81  signalOffset[2] = wxPoint2DDouble(0, -6);
82  signalOffset[3] = wxPoint2DDouble(0, -12);
83  sigmaOffset = wxPoint2DDouble(0, -6);
84  }
85  for(int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
86  std::vector<wxPoint2DDouble> hLine;
87  hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[0]);
88  hLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[1]);
89  DrawLine(hLine);
90  if(m_signalList[i] == SIGNAL_POSITIVE) {
91  std::vector<wxPoint2DDouble> vLine;
92  vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[2]);
93  vLine.push_back(m_nodeList[i]->GetPosition() + signalOffset[3]);
94  DrawLine(vLine);
95  }
96  }
97 
98  // Plot sigma.
99  std::vector<wxPoint2DDouble> sigma;
100  sigma.push_back(m_position + wxPoint2DDouble(4, 9) + sigmaOffset);
101  sigma.push_back(m_position + wxPoint2DDouble(-6, 9) + sigmaOffset);
102  sigma.push_back(m_position + wxPoint2DDouble(0, 0) + sigmaOffset);
103  sigma.push_back(m_position + wxPoint2DDouble(-6, -9) + sigmaOffset);
104  sigma.push_back(m_position + wxPoint2DDouble(4, -9) + sigmaOffset);
105  glColor4d(0.0, 0.3, 1.0, 1.0);
106  DrawLine(sigma);
107 
108  glColor4d(0.0, 0.0, 0.0, 1.0);
109  DrawNodes();
110 }
111 
112 bool Sum::ShowForm(wxWindow* parent, Element* element)
113 {
114  SumForm* sumForm = new SumForm(parent, this);
115  if(sumForm->ShowModal() == wxID_OK) {
116  sumForm->Destroy();
117  return true;
118  }
119  sumForm->Destroy();
120  return false;
121 }
122 
123 void Sum::UpdatePoints()
124 {
125  if(m_angle == 0.0 || m_angle == 180.0) {
126  m_height = 18.0 * (m_nodeList.size() - 1);
127  m_width = 36.0;
128  } else {
129  m_width = 18.0 * (m_nodeList.size() - 1);
130  m_height = 42.0;
131  }
132 
133  for(int i = 0; i < (int)m_nodeList.size() - 1; ++i) {
134  if(m_angle == 0.0)
135  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 9 + 18 * i - m_height / 2));
136  else if(m_angle == 90.0)
137  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2 - 9 - 18 * i, -m_height / 2));
138  else if(m_angle == 180.0)
139  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, m_height / 2 - 9 - 18 * i));
140  else if(m_angle == 270.0)
141  m_nodeList[i]->SetPosition(m_position + wxPoint2DDouble(9 + 18 * i - m_width / 2, m_height / 2));
142  }
143  if(m_angle == 0.0)
144  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
145  else if(m_angle == 90.0)
146  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
147  else if(m_angle == 180.0)
148  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
149  else if(m_angle == 270.0)
150  m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
151 
152  SetPosition(m_position); // Update rect.
153 }
154 
155 void Sum::AddInNode()
156 {
157  Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NODE_IN, m_borderSize);
158  newNode->SetAngle(m_angle);
159  m_nodeList.insert(m_nodeList.end() - 1, newNode);
160 }
161 
162 void Sum::RemoveInNode()
163 {
164  Node* nodeToRemove = *(m_nodeList.end() - 2);
165  bool foundChild = false;
166  for(auto it = m_childList.begin(), itEnd = m_childList.end(); it != itEnd; ++it) {
167  ControlElement* child = static_cast<ControlElement*>(*it);
168  auto childNodeList = child->GetNodeList();
169  for(auto itN = childNodeList.begin(), itEndN = childNodeList.end(); itN != itEndN; ++itN) {
170  Node* node = *itN;
171  if(node == nodeToRemove) {
172  child->RemoveParent(this);
173  RemoveChild(child);
174  foundChild = true;
175  break;
176  }
177  }
178  if(foundChild) break;
179  }
180  m_nodeList.erase(m_nodeList.end() - 2);
181 }
182 
183 void Sum::Rotate(bool clockwise)
184 {
185  if(clockwise)
186  m_angle += 90.0;
187  else
188  m_angle -= 90.0;
189  if(m_angle >= 360.0)
190  m_angle = 0.0;
191  else if(m_angle < 0)
192  m_angle = 270.0;
193 
194  UpdatePoints();
195 
196  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
197  Node* node = *it;
198  node->Rotate(clockwise);
199  }
200 }
201 
202 bool Sum::Solve(double input, double timeStep)
203 {
204  std::vector<double> inputVector;
205  for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
206  Node* node = *itN;
207  if(node->GetNodeType() != Node::NODE_OUT) {
208  if(!node->IsConnected()) {
209  inputVector.push_back(0.0);
210  } else {
211  for(auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
212  ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
213  auto nodeList = cLine->GetNodeList();
214  for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
215  Node* childNode = *itCN;
216  if(childNode == node) {
217  inputVector.push_back(cLine->GetValue());
218  break;
219  }
220  }
221  }
222  }
223  }
224  }
225 
226  if(m_signalList.size() != inputVector.size()) return false;
227 
228  m_output = 0.0;
229  for(unsigned int i = 0; i < m_signalList.size(); ++i) {
230  if(m_signalList[i] == SIGNAL_POSITIVE)
231  m_output += inputVector[i];
232  else if(m_signalList[i] == SIGNAL_NEGATIVE)
233  m_output -= inputVector[i];
234  }
235  return true;
236 }
237 
239 {
240  Sum* copy = new Sum(m_elementID);
241  *copy = *this;
242  return copy;
243 }
Form to edit the sum control data.
Definition: SumForm.h:32
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Sum.cpp:112
-
Definition: Sum.h:26
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
Node of a control element. This class manages the user interaction with the connection and control el...
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Sum.cpp:183
virtual Element * GetCopy()
Get a the element copy.
Definition: Sum.cpp:238
+
Connection between two control elements or other connection line and an element.
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Element.h:359
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Sum.cpp:43
diff --git a/docs/doxygen/html/_sum_8h.html b/docs/doxygen/html/_sum_8h.html new file mode 100644 index 0000000..5747052 --- /dev/null +++ b/docs/doxygen/html/_sum_8h.html @@ -0,0 +1,115 @@ + + + + + + + + + +Project/Sum.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Sum.h File Reference
+
+
+
#include "ControlElement.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  Sum
 Sum the all inputs (can choose the input signal). More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_sum_8h_source.html b/docs/doxygen/html/_sum_8h_source.html index bb4d08e..7bcc3be 100644 --- a/docs/doxygen/html/_sum_8h_source.html +++ b/docs/doxygen/html/_sum_8h_source.html @@ -88,15 +88,15 @@ $(document).ready(function(){initNavTree('_sum_8h_source.html','');});
Sum.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SUM_H
19 #define SUM_H
20 
21 #include "ControlElement.h"
22 
23 class SumForm;
24 class ConnectionLine;
25 
26 class Sum : public ControlElement
27 {
28  public:
29  enum Signal { SIGNAL_POSITIVE = 0, SIGNAL_NEGATIVE };
30  Sum(int id);
31  ~Sum();
32 
33  virtual void Draw(wxPoint2DDouble translation, double scale) const;
34  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
35  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
36  virtual bool ShowForm(wxWindow* parent, Element* element);
37  virtual void Rotate(bool clockwise = true);
38 
39  virtual std::vector<Signal> GetSignalList() const { return m_signalList; }
40  virtual void SetSignalList(std::vector<Signal> signalList) { m_signalList = signalList; }
41  virtual bool Solve(double input, double timeStep);
42 
43  virtual void UpdatePoints();
44  void AddInNode();
45  void RemoveInNode();
46 
47  virtual Element* GetCopy();
48 
49  protected:
50  std::vector<Signal> m_signalList;
51 };
52 
53 #endif // SUM_H
Form to edit the sum control data.
Definition: SumForm.h:32
- +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SUM_H
19 #define SUM_H
20 
21 #include "ControlElement.h"
22 
23 class SumForm;
24 class ConnectionLine;
25 
33 class Sum : public ControlElement
34 {
35  public:
36  enum Signal { SIGNAL_POSITIVE = 0, SIGNAL_NEGATIVE };
37  Sum(int id);
38  ~Sum();
39 
40  virtual void Draw(wxPoint2DDouble translation, double scale) const;
41  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
42  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
43  virtual bool ShowForm(wxWindow* parent, Element* element);
44  virtual void Rotate(bool clockwise = true);
45 
46  virtual std::vector<Signal> GetSignalList() const { return m_signalList; }
47  virtual void SetSignalList(std::vector<Signal> signalList) { m_signalList = signalList; }
48  virtual bool Solve(double input, double timeStep);
49 
50  virtual void UpdatePoints();
51  void AddInNode();
52  void RemoveInNode();
53 
54  virtual Element* GetCopy();
55 
56  protected:
57  std::vector<Signal> m_signalList;
58 };
59 
60 #endif // SUM_H
Form to edit the sum control data.
Definition: SumForm.h:32
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Sum.cpp:112
-
Definition: Sum.h:26
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Sum.cpp:183
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Sum.h:34
+
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Sum.h:41
virtual Element * GetCopy()
Get a the element copy.
Definition: Sum.cpp:238
Connection between two control elements or other connection line and an element.
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Sum.h:35
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Sum.h:42
Base class of a control element. Provide general methods to other control classes.
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Sum.cpp:43
@@ -105,7 +105,7 @@ $(document).ready(function(){initNavTree('_sum_8h_source.html','');});
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SumForm.h"
19 #include "Sum.h"
20 
21 SumForm::SumForm(wxWindow* parent, Sum* sum) : SumFormBase(parent)
22 {
23  SetSize(GetBestSize());
24 
25  m_parent = parent;
26  m_sum = sum;
27 
28  wxString signalStr = "";
29  auto signalList = m_sum->GetSignalList();
30  for(auto it = signalList.begin(), itEnd = signalList.end(); it != itEnd; ++it) {
31  Sum::Signal signal = *it;
32  switch(signal) {
33  case Sum::SIGNAL_POSITIVE: {
34  signalStr += "+";
35  } break;
36  case Sum::SIGNAL_NEGATIVE: {
37  signalStr += "-";
38  } break;
39  }
40  if(it != itEnd - 1) signalStr += " ";
41  }
42  m_textCtrlSigns->SetValue(signalStr);
43 }
44 
45 SumForm::~SumForm() {}
46 void SumForm::OnOKClick(wxCommandEvent& event)
47 {
48  if(ValidateData()) EndModal(wxID_OK);
49 }
50 
51 bool SumForm::ValidateData()
52 {
53  wxString signalStr = "";
54  for(int i = 0; i < (int)m_textCtrlSigns->GetValue().length(); ++i) {
55  if(m_textCtrlSigns->GetValue()[i] != ' ') signalStr += m_textCtrlSigns->GetValue()[i];
56  }
57  if(signalStr.size() < 2) {
58  wxMessageDialog msg(this, _("You must assign at least two signals."), _("Error"),
59  wxOK | wxCENTRE | wxICON_ERROR);
60  msg.ShowModal();
61  return false;
62  }
63 
64  std::vector<Sum::Signal> signalList;
65  for(int i = 0; i < (int)signalStr.length(); ++i) {
66  switch(signalStr[i].GetValue()) {
67  case '+': {
68  signalList.push_back(Sum::SIGNAL_POSITIVE);
69  } break;
70  case '-': {
71  signalList.push_back(Sum::SIGNAL_NEGATIVE);
72  } break;
73  default: {
74  wxMessageDialog msg(this, _("Value entered incorrectly in the field \"Signs\"."), _("Error"),
75  wxOK | wxCENTRE | wxICON_ERROR);
76  msg.ShowModal();
77  return false;
78  }
79  }
80  }
81 
82  int diff = (int)signalList.size() - (int)m_sum->GetSignalList().size();
83 
84  if(diff < 0) {
85  diff = std::abs(diff);
86  for(int i = 0; i < diff; ++i) {
87  m_sum->RemoveInNode();
88  }
89  } else if(diff > 0) {
90  for(int i = 0; i < diff; ++i) {
91  m_sum->AddInNode();
92  }
93  }
94  m_sum->SetSignalList(signalList);
95  m_sum->UpdatePoints();
96  return true;
97 }
Definition: Sum.h:26
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SumForm.h"
19 #include "Sum.h"
20 
21 SumForm::SumForm(wxWindow* parent, Sum* sum) : SumFormBase(parent)
22 {
23  SetSize(GetBestSize());
24 
25  m_parent = parent;
26  m_sum = sum;
27 
28  wxString signalStr = "";
29  auto signalList = m_sum->GetSignalList();
30  for(auto it = signalList.begin(), itEnd = signalList.end(); it != itEnd; ++it) {
31  Sum::Signal signal = *it;
32  switch(signal) {
33  case Sum::SIGNAL_POSITIVE: {
34  signalStr += "+";
35  } break;
36  case Sum::SIGNAL_NEGATIVE: {
37  signalStr += "-";
38  } break;
39  }
40  if(it != itEnd - 1) signalStr += " ";
41  }
42  m_textCtrlSigns->SetValue(signalStr);
43 }
44 
45 SumForm::~SumForm() {}
46 void SumForm::OnOKClick(wxCommandEvent& event)
47 {
48  if(ValidateData()) EndModal(wxID_OK);
49 }
50 
51 bool SumForm::ValidateData()
52 {
53  wxString signalStr = "";
54  for(int i = 0; i < (int)m_textCtrlSigns->GetValue().length(); ++i) {
55  if(m_textCtrlSigns->GetValue()[i] != ' ') signalStr += m_textCtrlSigns->GetValue()[i];
56  }
57  if(signalStr.size() < 2) {
58  wxMessageDialog msg(this, _("You must assign at least two signals."), _("Error"),
59  wxOK | wxCENTRE | wxICON_ERROR);
60  msg.ShowModal();
61  return false;
62  }
63 
64  std::vector<Sum::Signal> signalList;
65  for(int i = 0; i < (int)signalStr.length(); ++i) {
66  switch(signalStr[i].GetValue()) {
67  case '+': {
68  signalList.push_back(Sum::SIGNAL_POSITIVE);
69  } break;
70  case '-': {
71  signalList.push_back(Sum::SIGNAL_NEGATIVE);
72  } break;
73  default: {
74  wxMessageDialog msg(this, _("Value entered incorrectly in the field \"Signs\"."), _("Error"),
75  wxOK | wxCENTRE | wxICON_ERROR);
76  msg.ShowModal();
77  return false;
78  }
79  }
80  }
81 
82  int diff = (int)signalList.size() - (int)m_sum->GetSignalList().size();
83 
84  if(diff < 0) {
85  diff = std::abs(diff);
86  for(int i = 0; i < diff; ++i) {
87  m_sum->RemoveInNode();
88  }
89  } else if(diff > 0) {
90  for(int i = 0; i < diff; ++i) {
91  m_sum->AddInNode();
92  }
93  }
94  m_sum->SetSignalList(signalList);
95  m_sum->UpdatePoints();
96  return true;
97 }
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
+
diff --git a/docs/doxygen/html/_sum_form_8h_source.html b/docs/doxygen/html/_sum_form_8h_source.html index 6e71e39..d5fa8d7 100644 --- a/docs/doxygen/html/_sum_form_8h_source.html +++ b/docs/doxygen/html/_sum_form_8h_source.html @@ -89,7 +89,7 @@ $(document).ready(function(){initNavTree('_sum_form_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SUMFORM_H
19 #define SUMFORM_H
20 
21 #include "ElementForm.h"
22 
23 class Sum;
24 
32 class SumForm : public SumFormBase
33 {
34  public:
35  SumForm(wxWindow* parent, Sum* sum);
36  virtual ~SumForm();
37 
38  bool ValidateData();
39 
40  protected:
41  virtual void OnCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
42  virtual void OnOKClick(wxCommandEvent& event);
43  wxWindow* m_parent = NULL;
44  Sum* m_sum = NULL;
45 };
46 #endif // SUMFORM_H
Form to edit the sum control data.
Definition: SumForm.h:32
-
Definition: Sum.h:26
+
Sum the all inputs (can choose the input signal).
Definition: Sum.h:33
diff --git a/docs/doxygen/html/_switching_form_8cpp_source.html b/docs/doxygen/html/_switching_form_8cpp_source.html index 476a801..0c4cba4 100644 --- a/docs/doxygen/html/_switching_form_8cpp_source.html +++ b/docs/doxygen/html/_switching_form_8cpp_source.html @@ -92,11 +92,11 @@ $(document).ready(function(){initNavTree('_switching_form_8cpp_source.html','');
std::vector< SwitchingType > swType
Definition: PowerElement.h:94
- +
Switching data of power elements.
Definition: PowerElement.h:93
-
Switching data of power elements.
+
virtual SwitchingData GetSwitchingData()
Returns the switching data of the element.
Definition: PowerElement.h:182
- +
Abstract class of power elements.
Definition: PowerElement.h:117
diff --git a/docs/doxygen/html/_switching_form_8h_source.html b/docs/doxygen/html/_switching_form_8h_source.html index 51cbf31..42c55b4 100644 --- a/docs/doxygen/html/_switching_form_8h_source.html +++ b/docs/doxygen/html/_switching_form_8h_source.html @@ -90,7 +90,7 @@ $(document).ready(function(){initNavTree('_switching_form_8h_source.html','');})
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SWITCHINGFORM_H
19 #define SWITCHINGFORM_H
20 
21 #include "ElementForm.h"
22 
23 class PowerElement;
24 
33 {
34  public:
35  SwitchingForm(wxWindow* parent);
36  SwitchingForm(wxWindow* parent, PowerElement* element);
37  virtual ~SwitchingForm();
38 
39  protected:
40  virtual void OnDownButtonClick(wxCommandEvent& event);
41  virtual void OnUpButtonClick(wxCommandEvent& event);
42  virtual void OnChangeProperties(wxPropertyGridEvent& event);
43  virtual void OnSelectItem(wxListEvent& event);
44  virtual void OnCancelButtonClick(wxCommandEvent& event);
45  virtual void OnInsertButtonClick(wxCommandEvent& event);
46  virtual void OnOKButtonClick(wxCommandEvent& event);
47  virtual void OnRemoveButtonClick(wxCommandEvent& event);
48 
49  int m_maxID = 0;
50 
51  PowerElement* m_element = NULL;
52 };
53 #endif // SWITCHINGFORM_H
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
- +
Abstract class of power elements.
Definition: PowerElement.h:117
diff --git a/docs/doxygen/html/_sync_generator_8cpp_source.html b/docs/doxygen/html/_sync_generator_8cpp_source.html index a4d6412..337f0d2 100644 --- a/docs/doxygen/html/_sync_generator_8cpp_source.html +++ b/docs/doxygen/html/_sync_generator_8cpp_source.html @@ -88,18 +88,19 @@ $(document).ready(function(){initNavTree('_sync_generator_8cpp_source.html','');
SyncGenerator.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SyncMachineForm.h"
19 #include "SyncGenerator.h"
21 
22 SyncGenerator::SyncGenerator() : Machines() { Init(); }
23 SyncGenerator::SyncGenerator(wxString name) : Machines()
24 {
25  Init();
26  m_electricalData.name = name;
27 }
28 
29 SyncGenerator::~SyncGenerator() {}
30 void SyncGenerator::Init()
31 {
32  int numPtsSine = 10;
33  double mx = 15.0;
34  double my = 10.0;
35  double pi = 3.14159265359;
36 
37  for(int i = 0; i <= numPtsSine; i++) {
38  double x = (2.0 * pi / double(numPtsSine)) * double(i) - pi;
39  double y = std::sin(x);
40  m_sinePts.push_back(wxPoint2DDouble((x / pi) * mx, y * my));
41  }
42 
43  m_electricalData.avr = new ControlElementContainer();
44  m_electricalData.speedGov = new ControlElementContainer();
45 }
46 
47 void SyncGenerator::DrawSymbol() const
48 {
49  // Draw sine.
50  std::vector<wxPoint2DDouble> sinePts;
51  for(int i = 0; i < (int)m_sinePts.size(); i++) {
52  sinePts.push_back(m_sinePts[i] + m_position);
53  }
54  DrawLine(sinePts);
55 }
57 {
58  menu.Append(ID_EDIT_ELEMENT, _("Edit Generator"));
59  GeneralMenuItens(menu);
60  return true;
61 }
62 
63 bool SyncGenerator::ShowForm(wxWindow* parent, Element* element)
64 {
65  SyncMachineForm* generatorForm = new SyncMachineForm(parent, this);
66  generatorForm->SetTitle(_("Generator"));
67  if(generatorForm->ShowModal() == wxID_OK) {
68  generatorForm->Destroy();
69  return true;
70  }
71 
72  generatorForm->Destroy();
73  return false;
74 }
75 
76 SyncGeneratorElectricalData SyncGenerator::GetPUElectricalData(double systemPowerBase)
77 {
78  SyncGeneratorElectricalData data = m_electricalData;
79  double machineBasePower = 1.0;
80  if(data.useMachineBase) {
81  machineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
82  }
83 
84  // Active power
85  double activePower = GetValueFromUnit(data.activePower, data.activePowerUnit);
86  if(!m_online) activePower = 0.0;
87  if(data.activePowerUnit == UNIT_PU) {
88  if(data.useMachineBase) data.activePower = (activePower * machineBasePower) / systemPowerBase;
89  } else {
90  data.activePower = activePower / systemPowerBase;
91  }
92  data.activePowerUnit = UNIT_PU;
93 
94  // Reactive power
95  double reactivePower = GetValueFromUnit(data.reactivePower, data.reactivePowerUnit);
96  if(!m_online) reactivePower = 0.0;
97  if(data.reactivePowerUnit == UNIT_PU) {
98  if(data.useMachineBase) data.reactivePower = (reactivePower * machineBasePower) / systemPowerBase;
99  } else {
100  data.reactivePower = reactivePower / systemPowerBase;
101  }
102  data.reactivePowerUnit = UNIT_PU;
103 
104  // Max reactive power
105  double maxReactive = GetValueFromUnit(data.maxReactive, data.maxReactiveUnit);
106  if(data.maxReactiveUnit == UNIT_PU) {
107  if(data.useMachineBase) data.maxReactive = (maxReactive * machineBasePower) / systemPowerBase;
108  } else {
109  data.maxReactive = maxReactive / systemPowerBase;
110  }
111  data.maxReactiveUnit = UNIT_PU;
112 
113  // Min reactive power
114  double minReactive = GetValueFromUnit(data.minReactive, data.minReactiveUnit);
115  if(data.minReactiveUnit == UNIT_PU) {
116  if(data.useMachineBase) data.minReactive = (minReactive * machineBasePower) / systemPowerBase;
117  } else {
118  data.minReactive = minReactive / systemPowerBase;
119  }
120  data.minReactiveUnit = UNIT_PU;
121 
122  double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
123  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemPowerBase;
124  double machineBaseImpedance = (baseVoltage * baseVoltage) / machineBasePower;
125 
126  // Fault data
127  if(data.useMachineBase) {
128  data.positiveResistance = (data.positiveResistance * machineBaseImpedance) / systemBaseImpedance;
129  data.positiveReactance = (data.positiveReactance * machineBaseImpedance) / systemBaseImpedance;
130  data.negativeResistance = (data.negativeResistance * machineBaseImpedance) / systemBaseImpedance;
131  data.negativeReactance = (data.negativeReactance * machineBaseImpedance) / systemBaseImpedance;
132  data.zeroResistance = (data.zeroResistance * machineBaseImpedance) / systemBaseImpedance;
133  data.zeroReactance = (data.zeroReactance * machineBaseImpedance) / systemBaseImpedance;
134  data.groundResistance = (data.groundResistance * machineBaseImpedance) / systemBaseImpedance;
135  data.groundReactance = (data.groundReactance * machineBaseImpedance) / systemBaseImpedance;
136  }
137 
138  if(!m_online) {
139  data.faultCurrent[0] = std::complex<double>(0, 0);
140  data.faultCurrent[1] = std::complex<double>(0, 0);
141  data.faultCurrent[2] = std::complex<double>(0, 0);
142  }
143 
144  return data;
145 }
146 
147 void SyncGenerator::SetNominalVoltage(std::vector<double> nominalVoltage,
148  std::vector<ElectricalUnit> nominalVoltageUnit)
149 {
150  if(nominalVoltage.size() > 0) {
151  m_electricalData.nominalVoltage = nominalVoltage[0];
152  m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
153  }
154 }
155 
157 {
158  SyncGenerator* copy = new SyncGenerator();
159  *copy = *this;
160  auto data = copy->GetElectricalData();
161 
162  // Copy AVR
163  std::vector<ConnectionLine*> cLineList;
164  std::vector<ControlElement*> elementList;
165  m_electricalData.avr->GetContainerCopy(elementList, cLineList);
166 
168  avrCopy->FillContainer(elementList, cLineList);
169  data.avr = avrCopy;
170 
171  // Copy Speed Governor
172  cLineList.clear();
173  elementList.clear();
174  m_electricalData.speedGov->GetContainerCopy(elementList, cLineList);
175 
176  ControlElementContainer* speedGovCopy = new ControlElementContainer();
177  speedGovCopy->FillContainer(elementList, cLineList);
178  data.speedGov = speedGovCopy;
179 
180  copy->SetElectricalData(data);
181  return copy;
182 }
183 
185 {
186  wxString tipText = m_electricalData.name;
187  tipText += "\n";
188  double activePower = m_electricalData.activePower;
189  if(!m_online) activePower = 0.0;
190  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
191  switch(m_electricalData.activePowerUnit) {
192  case UNIT_PU: {
193  tipText += _(" p.u.");
194  } break;
195  case UNIT_W: {
196  tipText += _(" W");
197  } break;
198  case UNIT_kW: {
199  tipText += _(" kW");
200  } break;
201  case UNIT_MW: {
202  tipText += _(" MW");
203  } break;
204  default:
205  break;
206  }
207  double reactivePower = m_electricalData.reactivePower;
208  if(!m_online) reactivePower = 0.0;
209  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
210  switch(m_electricalData.reactivePowerUnit) {
211  case UNIT_PU: {
212  tipText += _(" p.u.");
213  } break;
214  case UNIT_VAr: {
215  tipText += _(" VAr");
216  } break;
217  case UNIT_kVAr: {
218  tipText += _(" kVAr");
219  } break;
220  case UNIT_MVAr: {
221  tipText += _(" MVAr");
222  } break;
223  default:
224  break;
225  }
226 
227  return tipText;
228 }
229 
231 {
232  if(!m_electricalData.plotSyncMachine) return false;
233  plotData.SetName(m_electricalData.name);
234  plotData.SetCurveType(ElementPlotData::CT_SYNC_GENERATOR);
235 
236  std::vector<double> absTerminalVoltage, activePower, reactivePower;
237  for(unsigned int i = 0; i < m_electricalData.terminalVoltageVector.size(); ++i) {
238  absTerminalVoltage.push_back(std::abs(m_electricalData.terminalVoltageVector[i]));
239  activePower.push_back(std::real(m_electricalData.electricalPowerVector[i]));
240  reactivePower.push_back(std::imag(m_electricalData.electricalPowerVector[i]));
241  }
242  plotData.AddData(absTerminalVoltage, _("Terminal voltage"));
243  plotData.AddData(activePower, _("Active power"));
244  plotData.AddData(reactivePower, _("Reactive power"));
245  plotData.AddData(m_electricalData.mechanicalPowerVector, _("Mechanical power"));
246  plotData.AddData(m_electricalData.freqVector, _("Frequency"));
247  plotData.AddData(m_electricalData.fieldVoltageVector, _("Field voltage"));
248  plotData.AddData(m_electricalData.deltaVector, _("Delta"));
249  return true;
250 }
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SyncMachineForm.h"
19 #include "SyncGenerator.h"
21 
22 SyncGenerator::SyncGenerator() : Machines() { Init(); }
23 SyncGenerator::SyncGenerator(wxString name) : Machines()
24 {
25  Init();
26  m_electricalData.name = name;
27 }
28 
29 SyncGenerator::~SyncGenerator() {}
30 void SyncGenerator::Init()
31 {
32  int numPtsSine = 10;
33  double mx = 15.0;
34  double my = 10.0;
35  double pi = 3.14159265359;
36 
37  for(int i = 0; i <= numPtsSine; i++) {
38  double x = (2.0 * pi / double(numPtsSine)) * double(i) - pi;
39  double y = std::sin(x);
40  m_sinePts.push_back(wxPoint2DDouble((x / pi) * mx, y * my));
41  }
42 
43  m_electricalData.avr = new ControlElementContainer();
44  m_electricalData.speedGov = new ControlElementContainer();
45 }
46 
47 void SyncGenerator::DrawSymbol() const
48 {
49  // Draw sine.
50  std::vector<wxPoint2DDouble> sinePts;
51  for(int i = 0; i < (int)m_sinePts.size(); i++) {
52  sinePts.push_back(m_sinePts[i] + m_position);
53  }
54  DrawLine(sinePts);
55 }
57 {
58  menu.Append(ID_EDIT_ELEMENT, _("Edit Generator"));
59  GeneralMenuItens(menu);
60  return true;
61 }
62 
63 bool SyncGenerator::ShowForm(wxWindow* parent, Element* element)
64 {
65  SyncMachineForm* generatorForm = new SyncMachineForm(parent, this);
66  generatorForm->SetTitle(_("Generator"));
67  if(generatorForm->ShowModal() == wxID_OK) {
68  generatorForm->Destroy();
69  return true;
70  }
71 
72  generatorForm->Destroy();
73  return false;
74 }
75 
76 SyncGeneratorElectricalData SyncGenerator::GetPUElectricalData(double systemPowerBase)
77 {
78  SyncGeneratorElectricalData data = m_electricalData;
79  double machineBasePower = 1.0;
80  if(data.useMachineBase) {
81  machineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
82  }
83 
84  // Active power
85  double activePower = GetValueFromUnit(data.activePower, data.activePowerUnit);
86  if(!m_online) activePower = 0.0;
87  if(data.activePowerUnit == UNIT_PU) {
88  if(data.useMachineBase) data.activePower = (activePower * machineBasePower) / systemPowerBase;
89  } else {
90  data.activePower = activePower / systemPowerBase;
91  }
92  data.activePowerUnit = UNIT_PU;
93 
94  // Reactive power
95  double reactivePower = GetValueFromUnit(data.reactivePower, data.reactivePowerUnit);
96  if(!m_online) reactivePower = 0.0;
97  if(data.reactivePowerUnit == UNIT_PU) {
98  if(data.useMachineBase) data.reactivePower = (reactivePower * machineBasePower) / systemPowerBase;
99  } else {
100  data.reactivePower = reactivePower / systemPowerBase;
101  }
102  data.reactivePowerUnit = UNIT_PU;
103 
104  // Max reactive power
105  double maxReactive = GetValueFromUnit(data.maxReactive, data.maxReactiveUnit);
106  if(data.maxReactiveUnit == UNIT_PU) {
107  if(data.useMachineBase) data.maxReactive = (maxReactive * machineBasePower) / systemPowerBase;
108  } else {
109  data.maxReactive = maxReactive / systemPowerBase;
110  }
111  data.maxReactiveUnit = UNIT_PU;
112 
113  // Min reactive power
114  double minReactive = GetValueFromUnit(data.minReactive, data.minReactiveUnit);
115  if(data.minReactiveUnit == UNIT_PU) {
116  if(data.useMachineBase) data.minReactive = (minReactive * machineBasePower) / systemPowerBase;
117  } else {
118  data.minReactive = minReactive / systemPowerBase;
119  }
120  data.minReactiveUnit = UNIT_PU;
121 
122  double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
123  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemPowerBase;
124  double machineBaseImpedance = (baseVoltage * baseVoltage) / machineBasePower;
125 
126  // Fault data
127  if(data.useMachineBase) {
128  data.positiveResistance = (data.positiveResistance * machineBaseImpedance) / systemBaseImpedance;
129  data.positiveReactance = (data.positiveReactance * machineBaseImpedance) / systemBaseImpedance;
130  data.negativeResistance = (data.negativeResistance * machineBaseImpedance) / systemBaseImpedance;
131  data.negativeReactance = (data.negativeReactance * machineBaseImpedance) / systemBaseImpedance;
132  data.zeroResistance = (data.zeroResistance * machineBaseImpedance) / systemBaseImpedance;
133  data.zeroReactance = (data.zeroReactance * machineBaseImpedance) / systemBaseImpedance;
134  data.groundResistance = (data.groundResistance * machineBaseImpedance) / systemBaseImpedance;
135  data.groundReactance = (data.groundReactance * machineBaseImpedance) / systemBaseImpedance;
136  }
137 
138  if(!m_online) {
139  data.faultCurrent[0] = std::complex<double>(0, 0);
140  data.faultCurrent[1] = std::complex<double>(0, 0);
141  data.faultCurrent[2] = std::complex<double>(0, 0);
142  }
143 
144  return data;
145 }
146 
147 void SyncGenerator::SetNominalVoltage(std::vector<double> nominalVoltage,
148  std::vector<ElectricalUnit> nominalVoltageUnit)
149 {
150  if(nominalVoltage.size() > 0) {
151  m_electricalData.nominalVoltage = nominalVoltage[0];
152  m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
153  }
154 }
155 
157 {
158  SyncGenerator* copy = new SyncGenerator();
159  *copy = *this;
160  auto data = copy->GetElectricalData();
161 
162  // Copy AVR
163  std::vector<ConnectionLine*> cLineList;
164  std::vector<ControlElement*> elementList;
165  m_electricalData.avr->GetContainerCopy(elementList, cLineList);
166 
168  avrCopy->FillContainer(elementList, cLineList);
169  data.avr = avrCopy;
170 
171  // Copy Speed Governor
172  cLineList.clear();
173  elementList.clear();
174  m_electricalData.speedGov->GetContainerCopy(elementList, cLineList);
175 
176  ControlElementContainer* speedGovCopy = new ControlElementContainer();
177  speedGovCopy->FillContainer(elementList, cLineList);
178  data.speedGov = speedGovCopy;
179 
180  copy->SetElectricalData(data);
181  return copy;
182 }
183 
185 {
186  wxString tipText = m_electricalData.name;
187  tipText += "\n";
188  double activePower = m_electricalData.activePower;
189  if(!m_online) activePower = 0.0;
190  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
191  switch(m_electricalData.activePowerUnit) {
192  case UNIT_PU: {
193  tipText += _(" p.u.");
194  } break;
195  case UNIT_W: {
196  tipText += _(" W");
197  } break;
198  case UNIT_kW: {
199  tipText += _(" kW");
200  } break;
201  case UNIT_MW: {
202  tipText += _(" MW");
203  } break;
204  default:
205  break;
206  }
207  double reactivePower = m_electricalData.reactivePower;
208  if(!m_online) reactivePower = 0.0;
209  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
210  switch(m_electricalData.reactivePowerUnit) {
211  case UNIT_PU: {
212  tipText += _(" p.u.");
213  } break;
214  case UNIT_VAr: {
215  tipText += _(" VAr");
216  } break;
217  case UNIT_kVAr: {
218  tipText += _(" kVAr");
219  } break;
220  case UNIT_MVAr: {
221  tipText += _(" MVAr");
222  } break;
223  default:
224  break;
225  }
226 
227  return tipText;
228 }
229 
231 {
232  if(!m_electricalData.plotSyncMachine) return false;
233  plotData.SetName(m_electricalData.name);
234  plotData.SetCurveType(ElementPlotData::CT_SYNC_GENERATOR);
235 
236  std::vector<double> absTerminalVoltage, activePower, reactivePower;
237  for(unsigned int i = 0; i < m_electricalData.terminalVoltageVector.size(); ++i) {
238  absTerminalVoltage.push_back(std::abs(m_electricalData.terminalVoltageVector[i]));
239  activePower.push_back(std::real(m_electricalData.electricalPowerVector[i]));
240  reactivePower.push_back(std::imag(m_electricalData.electricalPowerVector[i]));
241  }
242  plotData.AddData(absTerminalVoltage, _("Terminal voltage"));
243  plotData.AddData(activePower, _("Active power"));
244  plotData.AddData(reactivePower, _("Reactive power"));
245  plotData.AddData(m_electricalData.mechanicalPowerVector, _("Mechanical power"));
246  plotData.AddData(m_electricalData.freqVector, _("Frequency"));
247  plotData.AddData(m_electricalData.fieldVoltageVector, _("Field voltage"));
248  plotData.AddData(m_electricalData.deltaVector, _("Delta"));
249  return true;
250 }
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool GetPlotData(ElementPlotData &plotData)
Fill the plot data.
+ - +
Synchronous generator power element.
Form to edit the synchronous machine power data.
virtual Element * GetCopy()
Get a the element copy.
- +
virtual wxString GetTipText() const
Get the tip text.
@@ -109,7 +110,7 @@ $(document).ready(function(){initNavTree('_sync_generator_8cpp_source.html','');
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
- +
Abstract class for rotary machines power elements.
Definition: Machines.h:33
diff --git a/docs/doxygen/html/_sync_generator_8h.html b/docs/doxygen/html/_sync_generator_8h.html new file mode 100644 index 0000000..3385685 --- /dev/null +++ b/docs/doxygen/html/_sync_generator_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/SyncGenerator.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SyncGenerator.h File Reference
+
+
+
#include "Machines.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  SyncGeneratorElectricalData
 
class  SyncGenerator
 Synchronous generator power element. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_sync_generator_8h_source.html b/docs/doxygen/html/_sync_generator_8h_source.html index 8e16b85..98223ed 100644 --- a/docs/doxygen/html/_sync_generator_8h_source.html +++ b/docs/doxygen/html/_sync_generator_8h_source.html @@ -88,26 +88,27 @@ $(document).ready(function(){initNavTree('_sync_generator_8h_source.html','');})
SyncGenerator.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCGENERATOR_H
19 #define SYNCGENERATOR_H
20 
21 #include "Machines.h"
22 
23 class SyncMachineForm;
24 
26  // General
27  wxString name = "";
28  double nominalPower = 100.0;
29  ElectricalUnit nominalPowerUnit = UNIT_MVA;
30  double nominalVoltage = 13.8;
31  ElectricalUnit nominalVoltageUnit = UNIT_kV;
32  double activePower = 100.0;
33  ElectricalUnit activePowerUnit = UNIT_MW;
34  double reactivePower = 0.0;
35  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
36  bool haveMaxReactive = false;
37  double maxReactive = 9999.0;
38  ElectricalUnit maxReactiveUnit = UNIT_MVAr;
39  bool haveMinReactive = false;
40  double minReactive = -9999.0;
41  ElectricalUnit minReactiveUnit = UNIT_MVAr;
42  bool useMachineBase = true;
43 
44  // Fault
45  double positiveResistance = 0.0;
46  double positiveReactance = 1.0;
47  double negativeResistance = 0.0;
48  double negativeReactance = 1.0;
49  double zeroResistance = 0.0;
50  double zeroReactance = 1.0;
51  double groundResistance = 0.0;
52  double groundReactance = 0.0;
53  bool groundNeutral = true;
54  // p.u. fault data
55  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
56  std::complex<double>(0.0, 0.0)};
57 
58  // Stability
59  bool plotSyncMachine = false;
60  double inertia = 1.0;
61  double damping = 0.0;
62  bool useAVR = false;
63  bool useSpeedGovernor = false;
64 
65  double armResistance = 0.0;
66  double potierReactance = 0.0;
67  double satFactor = 0.0;
68 
69  double syncXd = 0.0;
70  double syncXq = 0.0;
71  double transXd = 1.0;
72  double transXq = 0.0;
73  double transTd0 = 0.0;
74  double transTq0 = 0.0;
75  double subXd = 0.0;
76  double subXq = 0.0;
77  double subTd0 = 0.0;
78  double subTq0 = 0.0;
79 
80  // Machine state variables
81  std::complex<double> terminalVoltage;
82  std::vector<std::complex<double> > terminalVoltageVector;
83  std::complex<double> electricalPower;
84  std::vector<std::complex<double> > electricalPowerVector;
85  double pm;
86  std::vector<double> mechanicalPowerVector;
87  double speed;
88  std::vector<double> freqVector;
89  double fieldVoltage;
90  std::vector<double> fieldVoltageVector;
91  double delta;
92  std::vector<double> deltaVector;
93 
94  double initialFieldVoltage;
95 
96  // Internal machine variables
97  double tranEq;
98  double tranEd;
99  double subEq;
100  double subEd;
101  double pe;
102  double id;
103  double iq;
104  double sd;
105  double sq;
106 
107  // Variables to extrapolate
108  double oldId;
109  double oldIq;
110  double oldPe;
111  double oldSd;
112  double oldSq;
113 
114  // Integration constants
115  IntegrationConstant icSpeed;
116  IntegrationConstant icDelta;
117  IntegrationConstant icTranEq;
118  IntegrationConstant icTranEd;
119  IntegrationConstant icSubEq;
120  IntegrationConstant icSubEd;
121 
122  // Control
123  ControlElementContainer* avr = NULL;
124  ControlElementContainer* speedGov = NULL;
125 
126  // Control solvers
127  ControlElementSolver* avrSolver = NULL;
128  ControlElementSolver* speedGovSolver = NULL;
129 
130  Machines::SyncMachineModel model = Machines::SM_MODEL_1;
131 };
132 
133 class SyncGenerator : public Machines
134 {
135  public:
136  SyncGenerator();
137  SyncGenerator(wxString name);
138  ~SyncGenerator();
139 
140  virtual Element* GetCopy();
141  virtual void Init();
142  virtual void DrawSymbol() const;
143  virtual bool GetContextMenu(wxMenu& menu);
144  virtual bool ShowForm(wxWindow* parent, Element* element);
145  virtual wxString GetTipText() const;
146  virtual SyncGeneratorElectricalData GetElectricalData() { return m_electricalData; }
147  virtual SyncGeneratorElectricalData GetPUElectricalData(double systemPowerBase);
148  virtual void SetElectricalData(SyncGeneratorElectricalData electricalData) { m_electricalData = electricalData; }
149  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
150  virtual bool GetPlotData(ElementPlotData& plotData);
151 
152  protected:
153  std::vector<wxPoint2DDouble> m_sinePts;
154 
155  SyncGeneratorElectricalData m_electricalData;
156 };
157 
158 #endif // SYNCGENERATOR_H
- +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCGENERATOR_H
19 #define SYNCGENERATOR_H
20 
21 #include "Machines.h"
22 
23 class SyncMachineForm;
24 
26  // General
27  wxString name = "";
28  double nominalPower = 100.0;
29  ElectricalUnit nominalPowerUnit = UNIT_MVA;
30  double nominalVoltage = 13.8;
31  ElectricalUnit nominalVoltageUnit = UNIT_kV;
32  double activePower = 100.0;
33  ElectricalUnit activePowerUnit = UNIT_MW;
34  double reactivePower = 0.0;
35  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
36  bool haveMaxReactive = false;
37  double maxReactive = 9999.0;
38  ElectricalUnit maxReactiveUnit = UNIT_MVAr;
39  bool haveMinReactive = false;
40  double minReactive = -9999.0;
41  ElectricalUnit minReactiveUnit = UNIT_MVAr;
42  bool useMachineBase = true;
43 
44  // Fault
45  double positiveResistance = 0.0;
46  double positiveReactance = 1.0;
47  double negativeResistance = 0.0;
48  double negativeReactance = 1.0;
49  double zeroResistance = 0.0;
50  double zeroReactance = 1.0;
51  double groundResistance = 0.0;
52  double groundReactance = 0.0;
53  bool groundNeutral = true;
54  // p.u. fault data
55  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
56  std::complex<double>(0.0, 0.0)};
57 
58  // Stability
59  bool plotSyncMachine = false;
60  double inertia = 1.0;
61  double damping = 0.0;
62  bool useAVR = false;
63  bool useSpeedGovernor = false;
64 
65  double armResistance = 0.0;
66  double potierReactance = 0.0;
67  double satFactor = 0.0;
68 
69  double syncXd = 0.0;
70  double syncXq = 0.0;
71  double transXd = 1.0;
72  double transXq = 0.0;
73  double transTd0 = 0.0;
74  double transTq0 = 0.0;
75  double subXd = 0.0;
76  double subXq = 0.0;
77  double subTd0 = 0.0;
78  double subTq0 = 0.0;
79 
80  // Machine state variables
81  std::complex<double> terminalVoltage;
82  std::vector<std::complex<double> > terminalVoltageVector;
83  std::complex<double> electricalPower;
84  std::vector<std::complex<double> > electricalPowerVector;
85  double pm;
86  std::vector<double> mechanicalPowerVector;
87  double speed;
88  std::vector<double> freqVector;
89  double fieldVoltage;
90  std::vector<double> fieldVoltageVector;
91  double delta;
92  std::vector<double> deltaVector;
93 
94  double initialFieldVoltage;
95 
96  // Internal machine variables
97  double tranEq;
98  double tranEd;
99  double subEq;
100  double subEd;
101  double pe;
102  double id;
103  double iq;
104  double sd;
105  double sq;
106 
107  // Variables to extrapolate
108  double oldId;
109  double oldIq;
110  double oldPe;
111  double oldSd;
112  double oldSq;
113 
114  // Integration constants
115  IntegrationConstant icSpeed;
116  IntegrationConstant icDelta;
117  IntegrationConstant icTranEq;
118  IntegrationConstant icTranEd;
119  IntegrationConstant icSubEq;
120  IntegrationConstant icSubEd;
121 
122  // Control
123  ControlElementContainer* avr = NULL;
124  ControlElementContainer* speedGov = NULL;
125 
126  // Control solvers
127  ControlElementSolver* avrSolver = NULL;
128  ControlElementSolver* speedGovSolver = NULL;
129 
130  Machines::SyncMachineModel model = Machines::SM_MODEL_1;
131 };
132 
140 class SyncGenerator : public Machines
141 {
142  public:
143  SyncGenerator();
144  SyncGenerator(wxString name);
145  ~SyncGenerator();
146 
147  virtual Element* GetCopy();
148  virtual void Init();
149  virtual void DrawSymbol() const;
150  virtual bool GetContextMenu(wxMenu& menu);
151  virtual bool ShowForm(wxWindow* parent, Element* element);
152  virtual wxString GetTipText() const;
153  virtual SyncGeneratorElectricalData GetElectricalData() { return m_electricalData; }
154  virtual SyncGeneratorElectricalData GetPUElectricalData(double systemPowerBase);
155  virtual void SetElectricalData(SyncGeneratorElectricalData electricalData) { m_electricalData = electricalData; }
156  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
157  virtual bool GetPlotData(ElementPlotData& plotData);
158 
159  protected:
160  std::vector<wxPoint2DDouble> m_sinePts;
161 
162  SyncGeneratorElectricalData m_electricalData;
163 };
164 
165 #endif // SYNCGENERATOR_H
+ +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
- +
Synchronous generator power element.
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- +
Integration constants to calculate dynamic elements through trapezoidal integration method...
Definition: PowerElement.h:105
Form to edit the synchronous machine power data.
- +
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
- +
Abstract class for rotary machines power elements.
Definition: Machines.h:33
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneratorStabForm.h"
19 #include "SyncMachineForm.h"
20 #include "SyncGenerator.h"
21 #include "SyncMotor.h"
22 
23 SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator) : SyncMachineFormBase(parent)
24 {
25  SetSize(GetBestSize());
26  ReplaceStaticTextLabelChar(m_staticTextPosResistance, L'\u2081');
27  ReplaceStaticTextLabelChar(m_staticTextPosReactance, L'\u2081');
28  ReplaceStaticTextLabelChar(m_staticTextNegResistance, L'\u2082');
29  ReplaceStaticTextLabelChar(m_staticTextNegReactance, L'\u2082');
30  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
31  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
32  Layout();
33  m_syncGenerator = syncGenerator;
34  m_parent = parent;
35 
36  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
37 
38  m_textCtrlName->SetValue(data.name);
39 
40  m_textCtrlnominalPower->SetValue(SyncGenerator::StringFromDouble(data.nominalPower));
41  switch(data.nominalPowerUnit) {
42  case UNIT_VA:
43  m_choiceNominalPower->SetSelection(0);
44  break;
45  case UNIT_kVA:
46  m_choiceNominalPower->SetSelection(1);
47  break;
48  case UNIT_MVA:
49  m_choiceNominalPower->SetSelection(2);
50  break;
51  default:
52  break;
53  }
54 
55  m_textCtrlActivePower->SetValue(SyncGenerator::StringFromDouble(data.activePower));
56  switch(data.activePowerUnit) {
57  case UNIT_PU:
58  m_choiceActivePower->SetSelection(0);
59  break;
60  case UNIT_W:
61  m_choiceActivePower->SetSelection(1);
62  break;
63  case UNIT_kW:
64  m_choiceActivePower->SetSelection(2);
65  break;
66  case UNIT_MW:
67  m_choiceActivePower->SetSelection(3);
68  break;
69  default:
70  break;
71  }
72 
73  m_textCtrlReactivePower->SetValue(SyncGenerator::StringFromDouble(data.reactivePower));
74  switch(data.reactivePowerUnit) {
75  case UNIT_PU:
76  m_choiceReactivePower->SetSelection(0);
77  break;
78  case UNIT_VAr:
79  m_choiceReactivePower->SetSelection(1);
80  break;
81  case UNIT_kVAr:
82  m_choiceReactivePower->SetSelection(2);
83  break;
84  case UNIT_MVAr:
85  m_choiceReactivePower->SetSelection(3);
86  break;
87  default:
88  break;
89  }
90  m_checkBoxMaxReactive->SetValue(data.haveMaxReactive);
91 
92  m_textCtrlMaxRectivePower->SetValue(SyncGenerator::StringFromDouble(data.maxReactive));
93  switch(data.maxReactiveUnit) {
94  case UNIT_PU:
95  m_choiceMaxRectivePower->SetSelection(0);
96  break;
97  case UNIT_VAr:
98  m_choiceMaxRectivePower->SetSelection(1);
99  break;
100  case UNIT_kVAr:
101  m_choiceMaxRectivePower->SetSelection(2);
102  break;
103  case UNIT_MVAr:
104  m_choiceMaxRectivePower->SetSelection(3);
105  break;
106  default:
107  break;
108  }
109  m_textCtrlMaxRectivePower->Enable(data.haveMaxReactive);
110  m_choiceMaxRectivePower->Enable(data.haveMaxReactive);
111 
112  m_checkBoxMinReactive->SetValue(data.haveMinReactive);
113  m_textCtrlMinRectivePower->SetValue(SyncGenerator::StringFromDouble(data.minReactive));
114  switch(data.minReactiveUnit) {
115  case UNIT_PU:
116  m_choiceMinRectivePower->SetSelection(0);
117  break;
118  case UNIT_VAr:
119  m_choiceMinRectivePower->SetSelection(1);
120  break;
121  case UNIT_kVAr:
122  m_choiceMinRectivePower->SetSelection(2);
123  break;
124  case UNIT_MVAr:
125  m_choiceMinRectivePower->SetSelection(3);
126  break;
127  default:
128  break;
129  }
130  m_textCtrlMinRectivePower->Enable(data.haveMinReactive);
131  m_choiceMinRectivePower->Enable(data.haveMinReactive);
132 
133  m_checkBoxUseMachinePower->SetValue(data.useMachineBase);
134 
135  m_textCtrlPosResistance->SetValue(SyncGenerator::StringFromDouble(data.positiveResistance));
136  m_textCtrlPosReactance->SetValue(SyncGenerator::StringFromDouble(data.positiveReactance));
137  m_textCtrlNegResistance->SetValue(SyncGenerator::StringFromDouble(data.negativeResistance));
138  m_textCtrlNegReactance->SetValue(SyncGenerator::StringFromDouble(data.negativeReactance));
139  m_textCtrlZeroResistance->SetValue(SyncGenerator::StringFromDouble(data.zeroResistance));
140  m_textCtrlZeroReactance->SetValue(SyncGenerator::StringFromDouble(data.zeroReactance));
141  m_textCtrlGrdResistance->SetValue(SyncGenerator::StringFromDouble(data.groundResistance));
142  m_textCtrlGrdReactance->SetValue(SyncGenerator::StringFromDouble(data.groundReactance));
143  m_checkBoxGroundNeutral->SetValue(data.groundNeutral);
144 }
145 
146 SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncMotor* syncMotor) : SyncMachineFormBase(parent)
147 {
148  m_buttonStab->Enable(false);
149  SetSize(GetBestSize());
150  ReplaceStaticTextLabelChar(m_staticTextPosResistance, L'\u2081');
151  ReplaceStaticTextLabelChar(m_staticTextPosReactance, L'\u2081');
152  ReplaceStaticTextLabelChar(m_staticTextNegResistance, L'\u2082');
153  ReplaceStaticTextLabelChar(m_staticTextNegReactance, L'\u2082');
154  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
155  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
156  Layout();
157  m_syncMotor = syncMotor;
158  m_parent = parent;
159 
160  SyncMotorElectricalData data = syncMotor->GetElectricalData();
161 
162  m_textCtrlName->SetValue(data.name);
163 
164  m_textCtrlnominalPower->SetValue(SyncMotor::StringFromDouble(data.nominalPower));
165  switch(data.nominalPowerUnit) {
166  case UNIT_VA:
167  m_choiceNominalPower->SetSelection(0);
168  break;
169  case UNIT_kVA:
170  m_choiceNominalPower->SetSelection(1);
171  break;
172  case UNIT_MVA:
173  m_choiceNominalPower->SetSelection(2);
174  break;
175  default:
176  break;
177  }
178 
179  m_textCtrlActivePower->SetValue(SyncMotor::StringFromDouble(data.activePower));
180  switch(data.activePowerUnit) {
181  case UNIT_PU:
182  m_choiceActivePower->SetSelection(0);
183  break;
184  case UNIT_W:
185  m_choiceActivePower->SetSelection(1);
186  break;
187  case UNIT_kW:
188  m_choiceActivePower->SetSelection(2);
189  break;
190  case UNIT_MW:
191  m_choiceActivePower->SetSelection(3);
192  break;
193  default:
194  break;
195  }
196 
197  m_textCtrlReactivePower->SetValue(SyncMotor::StringFromDouble(data.reactivePower));
198  switch(data.reactivePowerUnit) {
199  case UNIT_PU:
200  m_choiceReactivePower->SetSelection(0);
201  break;
202  case UNIT_VAr:
203  m_choiceReactivePower->SetSelection(1);
204  break;
205  case UNIT_kVAr:
206  m_choiceReactivePower->SetSelection(2);
207  break;
208  case UNIT_MVAr:
209  m_choiceReactivePower->SetSelection(3);
210  break;
211  default:
212  break;
213  }
214  m_checkBoxMaxReactive->SetValue(data.haveMaxReactive);
215 
216  m_textCtrlMaxRectivePower->SetValue(SyncMotor::StringFromDouble(data.maxReactive));
217  switch(data.maxReactiveUnit) {
218  case UNIT_PU:
219  m_choiceMaxRectivePower->SetSelection(0);
220  break;
221  case UNIT_VAr:
222  m_choiceMaxRectivePower->SetSelection(1);
223  break;
224  case UNIT_kVAr:
225  m_choiceMaxRectivePower->SetSelection(2);
226  break;
227  case UNIT_MVAr:
228  m_choiceMaxRectivePower->SetSelection(3);
229  break;
230  default:
231  break;
232  }
233  m_textCtrlMaxRectivePower->Enable(data.haveMaxReactive);
234  m_choiceMaxRectivePower->Enable(data.haveMaxReactive);
235 
236  m_checkBoxMinReactive->SetValue(data.haveMinReactive);
237  m_textCtrlMinRectivePower->SetValue(SyncMotor::StringFromDouble(data.minReactive));
238  switch(data.minReactiveUnit) {
239  case UNIT_PU:
240  m_choiceMinRectivePower->SetSelection(0);
241  break;
242  case UNIT_VAr:
243  m_choiceMinRectivePower->SetSelection(1);
244  break;
245  case UNIT_kVAr:
246  m_choiceMinRectivePower->SetSelection(2);
247  break;
248  case UNIT_MVAr:
249  m_choiceMinRectivePower->SetSelection(3);
250  break;
251  default:
252  break;
253  }
254  m_textCtrlMinRectivePower->Enable(data.haveMinReactive);
255  m_choiceMinRectivePower->Enable(data.haveMinReactive);
256 
257  m_checkBoxUseMachinePower->SetValue(data.useMachineBase);
258 
259  m_textCtrlPosResistance->SetValue(SyncMotor::StringFromDouble(data.positiveResistance));
260  m_textCtrlPosReactance->SetValue(SyncMotor::StringFromDouble(data.positiveReactance));
261  m_textCtrlNegResistance->SetValue(SyncMotor::StringFromDouble(data.negativeResistance));
262  m_textCtrlNegReactance->SetValue(SyncMotor::StringFromDouble(data.negativeReactance));
263  m_textCtrlZeroResistance->SetValue(SyncMotor::StringFromDouble(data.zeroResistance));
264  m_textCtrlZeroReactance->SetValue(SyncMotor::StringFromDouble(data.zeroReactance));
265  m_textCtrlGrdResistance->SetValue(SyncMotor::StringFromDouble(data.groundResistance));
266  m_textCtrlGrdReactance->SetValue(SyncMotor::StringFromDouble(data.groundReactance));
267  m_checkBoxGroundNeutral->SetValue(data.groundNeutral);
268 }
269 
270 SyncMachineForm::~SyncMachineForm() {}
271 void SyncMachineForm::OnCheckMaxReactive(wxCommandEvent& event)
272 {
273  m_textCtrlMaxRectivePower->Enable(m_checkBoxMaxReactive->GetValue());
274  m_choiceMaxRectivePower->Enable(m_checkBoxMaxReactive->GetValue());
275 }
276 void SyncMachineForm::OnCheckMinReactive(wxCommandEvent& event)
277 {
278  m_textCtrlMinRectivePower->Enable(m_checkBoxMinReactive->GetValue());
279  m_choiceMinRectivePower->Enable(m_checkBoxMinReactive->GetValue());
280 }
281 void SyncMachineForm::OnOKButtonClick(wxCommandEvent& event)
282 {
283  if(ValidateData()) EndModal(wxID_OK);
284 }
285 void SyncMachineForm::OnStabilityButtonClick(wxCommandEvent& event)
286 {
287  if(ValidateData()) {
288  if(m_syncGenerator) {
289  GeneratorStabForm* stabForm = new GeneratorStabForm(m_parent, m_syncGenerator);
290  if(stabForm->ShowModal() == wxID_OK) {
291  stabForm->Destroy();
292  EndModal(wxID_OK);
293  }
294 
295  stabForm->Destroy();
296  EndModal(wxID_CANCEL);
297  }
298  }
299 }
300 
301 bool SyncMachineForm::ValidateData()
302 {
303  if(m_syncGenerator) {
304  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
305  data.name = m_textCtrlName->GetValue();
306 
307  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlnominalPower->GetValue(), data.nominalPower,
308  _("Value entered incorrectly in the field \"Nominal power\".")))
309  return false;
310  switch(m_choiceNominalPower->GetSelection()) {
311  case 0:
312  data.nominalPowerUnit = UNIT_VA;
313  break;
314  case 1:
315  data.nominalPowerUnit = UNIT_kVA;
316  break;
317  case 2:
318  data.nominalPowerUnit = UNIT_MVA;
319  break;
320  }
321 
322  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
323  _("Value entered incorrectly in the field \"Active power\".")))
324  return false;
325  switch(m_choiceActivePower->GetSelection()) {
326  case 0:
327  data.activePowerUnit = UNIT_PU;
328  break;
329  case 1:
330  data.activePowerUnit = UNIT_W;
331  break;
332  case 2:
333  data.activePowerUnit = UNIT_kW;
334  break;
335  case 3:
336  data.activePowerUnit = UNIT_MW;
337  break;
338  }
339 
340  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
341  _("Value entered incorrectly in the field \"Reactive power\".")))
342  return false;
343  switch(m_choiceReactivePower->GetSelection()) {
344  case 0:
345  data.reactivePowerUnit = UNIT_PU;
346  break;
347  case 1:
348  data.reactivePowerUnit = UNIT_VAr;
349  break;
350  case 2:
351  data.reactivePowerUnit = UNIT_kVAr;
352  break;
353  case 3:
354  data.reactivePowerUnit = UNIT_MVAr;
355  break;
356  }
357 
358  data.haveMaxReactive = m_checkBoxMaxReactive->GetValue();
359  if(data.haveMaxReactive) {
360  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlMaxRectivePower->GetValue(), data.maxReactive,
361  _("Value entered incorrectly in the field \"Max reactive power\".")))
362  return false;
363  switch(m_choiceMaxRectivePower->GetSelection()) {
364  case 0:
365  data.maxReactiveUnit = UNIT_PU;
366  break;
367  case 1:
368  data.maxReactiveUnit = UNIT_VAr;
369  break;
370  case 2:
371  data.maxReactiveUnit = UNIT_kVAr;
372  break;
373  case 3:
374  data.maxReactiveUnit = UNIT_MVAr;
375  break;
376  }
377  }
378 
379  data.haveMinReactive = m_checkBoxMinReactive->GetValue();
380  if(data.haveMinReactive) {
381  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlMinRectivePower->GetValue(), data.minReactive,
382  _("Value entered incorrectly in the field \"Min reactive power\".")))
383  return false;
384  switch(m_choiceMinRectivePower->GetSelection()) {
385  case 0:
386  data.minReactiveUnit = UNIT_PU;
387  break;
388  case 1:
389  data.minReactiveUnit = UNIT_VAr;
390  break;
391  case 2:
392  data.minReactiveUnit = UNIT_kVAr;
393  break;
394  case 3:
395  data.minReactiveUnit = UNIT_MVAr;
396  break;
397  }
398  }
399 
400  data.useMachineBase = m_checkBoxUseMachinePower->GetValue();
401 
402  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlPosResistance->GetValue(), data.positiveResistance,
403  _("Value entered incorrectly in the field \"Positive resistance\".")))
404  return false;
405 
406  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlPosReactance->GetValue(), data.positiveReactance,
407  _("Value entered incorrectly in the field \"Positive reactance\".")))
408  return false;
409 
410  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlNegResistance->GetValue(), data.negativeResistance,
411  _("Value entered incorrectly in the field \"Negative resistance\".")))
412  return false;
413 
414  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlNegReactance->GetValue(), data.negativeReactance,
415  _("Value entered incorrectly in the field \"Negative reactance\".")))
416  return false;
417 
418  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
419  _("Value entered incorrectly in the field \"Zero resistance\".")))
420  return false;
421 
422  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroReactance,
423  _("Value entered incorrectly in the field \"Zero reactance\".")))
424  return false;
425 
426  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlGrdResistance->GetValue(), data.groundResistance,
427  _("Value entered incorrectly in the field \"Ground resistance\".")))
428  return false;
429 
430  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlGrdReactance->GetValue(), data.groundReactance,
431  _("Value entered incorrectly in the field \"Ground reactance\".")))
432  return false;
433 
434  data.groundNeutral = m_checkBoxGroundNeutral->GetValue();
435 
436  m_syncGenerator->SetElectricalData(data);
437  } else if(m_syncMotor) {
438  SyncMotorElectricalData data = m_syncMotor->GetElectricalData();
439  data.name = m_textCtrlName->GetValue();
440 
441  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlnominalPower->GetValue(), data.nominalPower,
442  _("Value entered incorrectly in the field \"Nominal power\".")))
443  return false;
444  switch(m_choiceNominalPower->GetSelection()) {
445  case 0:
446  data.nominalPowerUnit = UNIT_VA;
447  break;
448  case 1:
449  data.nominalPowerUnit = UNIT_kVA;
450  break;
451  case 2:
452  data.nominalPowerUnit = UNIT_MVA;
453  break;
454  }
455 
456  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
457  _("Value entered incorrectly in the field \"Active power\".")))
458  return false;
459  switch(m_choiceActivePower->GetSelection()) {
460  case 0:
461  data.activePowerUnit = UNIT_PU;
462  break;
463  case 1:
464  data.activePowerUnit = UNIT_W;
465  break;
466  case 2:
467  data.activePowerUnit = UNIT_kW;
468  break;
469  case 3:
470  data.activePowerUnit = UNIT_MW;
471  break;
472  }
473 
474  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
475  _("Value entered incorrectly in the field \"Reactive power\".")))
476  return false;
477  switch(m_choiceReactivePower->GetSelection()) {
478  case 0:
479  data.reactivePowerUnit = UNIT_PU;
480  break;
481  case 1:
482  data.reactivePowerUnit = UNIT_VAr;
483  break;
484  case 2:
485  data.reactivePowerUnit = UNIT_kVAr;
486  break;
487  case 3:
488  data.reactivePowerUnit = UNIT_MVAr;
489  break;
490  }
491 
492  data.haveMaxReactive = m_checkBoxMaxReactive->GetValue();
493  if(data.haveMaxReactive) {
494  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlMaxRectivePower->GetValue(), data.maxReactive,
495  _("Value entered incorrectly in the field \"Max reactive power\".")))
496  return false;
497  switch(m_choiceMaxRectivePower->GetSelection()) {
498  case 0:
499  data.maxReactiveUnit = UNIT_PU;
500  break;
501  case 1:
502  data.maxReactiveUnit = UNIT_VAr;
503  break;
504  case 2:
505  data.maxReactiveUnit = UNIT_kVAr;
506  break;
507  case 3:
508  data.maxReactiveUnit = UNIT_MVAr;
509  break;
510  }
511  }
512 
513  data.haveMinReactive = m_checkBoxMinReactive->GetValue();
514  if(data.haveMinReactive) {
515  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlMinRectivePower->GetValue(), data.minReactive,
516  _("Value entered incorrectly in the field \"Min reactive power\".")))
517  return false;
518  switch(m_choiceMinRectivePower->GetSelection()) {
519  case 0:
520  data.minReactiveUnit = UNIT_PU;
521  break;
522  case 1:
523  data.minReactiveUnit = UNIT_VAr;
524  break;
525  case 2:
526  data.minReactiveUnit = UNIT_kVAr;
527  break;
528  case 3:
529  data.minReactiveUnit = UNIT_MVAr;
530  break;
531  }
532  }
533 
534  data.useMachineBase = m_checkBoxUseMachinePower->GetValue();
535 
536  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlPosResistance->GetValue(), data.positiveResistance,
537  _("Value entered incorrectly in the field \"Positive resistance\".")))
538  return false;
539 
540  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlPosReactance->GetValue(), data.positiveReactance,
541  _("Value entered incorrectly in the field \"Positive reactance\".")))
542  return false;
543 
544  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlNegResistance->GetValue(), data.negativeResistance,
545  _("Value entered incorrectly in the field \"Negative resistance\".")))
546  return false;
547 
548  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlNegReactance->GetValue(), data.negativeReactance,
549  _("Value entered incorrectly in the field \"Negative reactance\".")))
550  return false;
551 
552  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
553  _("Value entered incorrectly in the field \"Zero resistance\".")))
554  return false;
555 
556  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroReactance,
557  _("Value entered incorrectly in the field \"Zero reactance\".")))
558  return false;
559 
560  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlGrdResistance->GetValue(), data.groundResistance,
561  _("Value entered incorrectly in the field \"Ground resistance\".")))
562  return false;
563 
564  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlGrdReactance->GetValue(), data.groundReactance,
565  _("Value entered incorrectly in the field \"Ground reactance\".")))
566  return false;
567 
568  data.groundNeutral = m_checkBoxGroundNeutral->GetValue();
569 
570  m_syncMotor->SetElectricalData(data);
571  }
572  return true;
573 }
574 
575 void SyncMachineForm::ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar)
576 {
577  wxString label = staticText->GetLabel();
578  label[label.length() - 2] = newChar;
579  staticText->SetLabel(label);
580 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "GeneratorStabForm.h"
19 #include "SyncMachineForm.h"
20 #include "SyncGenerator.h"
21 #include "SyncMotor.h"
22 
23 SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator) : SyncMachineFormBase(parent)
24 {
25  SetSize(GetBestSize());
26  ReplaceStaticTextLabelChar(m_staticTextPosResistance, L'\u2081');
27  ReplaceStaticTextLabelChar(m_staticTextPosReactance, L'\u2081');
28  ReplaceStaticTextLabelChar(m_staticTextNegResistance, L'\u2082');
29  ReplaceStaticTextLabelChar(m_staticTextNegReactance, L'\u2082');
30  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
31  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
32  Layout();
33  m_syncGenerator = syncGenerator;
34  m_parent = parent;
35 
36  SyncGeneratorElectricalData data = syncGenerator->GetElectricalData();
37 
38  m_textCtrlName->SetValue(data.name);
39 
40  m_textCtrlnominalPower->SetValue(SyncGenerator::StringFromDouble(data.nominalPower));
41  switch(data.nominalPowerUnit) {
42  case UNIT_VA:
43  m_choiceNominalPower->SetSelection(0);
44  break;
45  case UNIT_kVA:
46  m_choiceNominalPower->SetSelection(1);
47  break;
48  case UNIT_MVA:
49  m_choiceNominalPower->SetSelection(2);
50  break;
51  default:
52  break;
53  }
54 
55  m_textCtrlActivePower->SetValue(SyncGenerator::StringFromDouble(data.activePower));
56  switch(data.activePowerUnit) {
57  case UNIT_PU:
58  m_choiceActivePower->SetSelection(0);
59  break;
60  case UNIT_W:
61  m_choiceActivePower->SetSelection(1);
62  break;
63  case UNIT_kW:
64  m_choiceActivePower->SetSelection(2);
65  break;
66  case UNIT_MW:
67  m_choiceActivePower->SetSelection(3);
68  break;
69  default:
70  break;
71  }
72 
73  m_textCtrlReactivePower->SetValue(SyncGenerator::StringFromDouble(data.reactivePower));
74  switch(data.reactivePowerUnit) {
75  case UNIT_PU:
76  m_choiceReactivePower->SetSelection(0);
77  break;
78  case UNIT_VAr:
79  m_choiceReactivePower->SetSelection(1);
80  break;
81  case UNIT_kVAr:
82  m_choiceReactivePower->SetSelection(2);
83  break;
84  case UNIT_MVAr:
85  m_choiceReactivePower->SetSelection(3);
86  break;
87  default:
88  break;
89  }
90  m_checkBoxMaxReactive->SetValue(data.haveMaxReactive);
91 
92  m_textCtrlMaxRectivePower->SetValue(SyncGenerator::StringFromDouble(data.maxReactive));
93  switch(data.maxReactiveUnit) {
94  case UNIT_PU:
95  m_choiceMaxRectivePower->SetSelection(0);
96  break;
97  case UNIT_VAr:
98  m_choiceMaxRectivePower->SetSelection(1);
99  break;
100  case UNIT_kVAr:
101  m_choiceMaxRectivePower->SetSelection(2);
102  break;
103  case UNIT_MVAr:
104  m_choiceMaxRectivePower->SetSelection(3);
105  break;
106  default:
107  break;
108  }
109  m_textCtrlMaxRectivePower->Enable(data.haveMaxReactive);
110  m_choiceMaxRectivePower->Enable(data.haveMaxReactive);
111 
112  m_checkBoxMinReactive->SetValue(data.haveMinReactive);
113  m_textCtrlMinRectivePower->SetValue(SyncGenerator::StringFromDouble(data.minReactive));
114  switch(data.minReactiveUnit) {
115  case UNIT_PU:
116  m_choiceMinRectivePower->SetSelection(0);
117  break;
118  case UNIT_VAr:
119  m_choiceMinRectivePower->SetSelection(1);
120  break;
121  case UNIT_kVAr:
122  m_choiceMinRectivePower->SetSelection(2);
123  break;
124  case UNIT_MVAr:
125  m_choiceMinRectivePower->SetSelection(3);
126  break;
127  default:
128  break;
129  }
130  m_textCtrlMinRectivePower->Enable(data.haveMinReactive);
131  m_choiceMinRectivePower->Enable(data.haveMinReactive);
132 
133  m_checkBoxUseMachinePower->SetValue(data.useMachineBase);
134 
135  m_textCtrlPosResistance->SetValue(SyncGenerator::StringFromDouble(data.positiveResistance));
136  m_textCtrlPosReactance->SetValue(SyncGenerator::StringFromDouble(data.positiveReactance));
137  m_textCtrlNegResistance->SetValue(SyncGenerator::StringFromDouble(data.negativeResistance));
138  m_textCtrlNegReactance->SetValue(SyncGenerator::StringFromDouble(data.negativeReactance));
139  m_textCtrlZeroResistance->SetValue(SyncGenerator::StringFromDouble(data.zeroResistance));
140  m_textCtrlZeroReactance->SetValue(SyncGenerator::StringFromDouble(data.zeroReactance));
141  m_textCtrlGrdResistance->SetValue(SyncGenerator::StringFromDouble(data.groundResistance));
142  m_textCtrlGrdReactance->SetValue(SyncGenerator::StringFromDouble(data.groundReactance));
143  m_checkBoxGroundNeutral->SetValue(data.groundNeutral);
144 }
145 
146 SyncMachineForm::SyncMachineForm(wxWindow* parent, SyncMotor* syncMotor) : SyncMachineFormBase(parent)
147 {
148  m_buttonStab->Enable(false);
149  SetSize(GetBestSize());
150  ReplaceStaticTextLabelChar(m_staticTextPosResistance, L'\u2081');
151  ReplaceStaticTextLabelChar(m_staticTextPosReactance, L'\u2081');
152  ReplaceStaticTextLabelChar(m_staticTextNegResistance, L'\u2082');
153  ReplaceStaticTextLabelChar(m_staticTextNegReactance, L'\u2082');
154  ReplaceStaticTextLabelChar(m_staticTextZeroResistance, L'\u2080');
155  ReplaceStaticTextLabelChar(m_staticTextZeroReactance, L'\u2080');
156  Layout();
157  m_syncMotor = syncMotor;
158  m_parent = parent;
159 
160  SyncMotorElectricalData data = syncMotor->GetElectricalData();
161 
162  m_textCtrlName->SetValue(data.name);
163 
164  m_textCtrlnominalPower->SetValue(SyncMotor::StringFromDouble(data.nominalPower));
165  switch(data.nominalPowerUnit) {
166  case UNIT_VA:
167  m_choiceNominalPower->SetSelection(0);
168  break;
169  case UNIT_kVA:
170  m_choiceNominalPower->SetSelection(1);
171  break;
172  case UNIT_MVA:
173  m_choiceNominalPower->SetSelection(2);
174  break;
175  default:
176  break;
177  }
178 
179  m_textCtrlActivePower->SetValue(SyncMotor::StringFromDouble(data.activePower));
180  switch(data.activePowerUnit) {
181  case UNIT_PU:
182  m_choiceActivePower->SetSelection(0);
183  break;
184  case UNIT_W:
185  m_choiceActivePower->SetSelection(1);
186  break;
187  case UNIT_kW:
188  m_choiceActivePower->SetSelection(2);
189  break;
190  case UNIT_MW:
191  m_choiceActivePower->SetSelection(3);
192  break;
193  default:
194  break;
195  }
196 
197  m_textCtrlReactivePower->SetValue(SyncMotor::StringFromDouble(data.reactivePower));
198  switch(data.reactivePowerUnit) {
199  case UNIT_PU:
200  m_choiceReactivePower->SetSelection(0);
201  break;
202  case UNIT_VAr:
203  m_choiceReactivePower->SetSelection(1);
204  break;
205  case UNIT_kVAr:
206  m_choiceReactivePower->SetSelection(2);
207  break;
208  case UNIT_MVAr:
209  m_choiceReactivePower->SetSelection(3);
210  break;
211  default:
212  break;
213  }
214  m_checkBoxMaxReactive->SetValue(data.haveMaxReactive);
215 
216  m_textCtrlMaxRectivePower->SetValue(SyncMotor::StringFromDouble(data.maxReactive));
217  switch(data.maxReactiveUnit) {
218  case UNIT_PU:
219  m_choiceMaxRectivePower->SetSelection(0);
220  break;
221  case UNIT_VAr:
222  m_choiceMaxRectivePower->SetSelection(1);
223  break;
224  case UNIT_kVAr:
225  m_choiceMaxRectivePower->SetSelection(2);
226  break;
227  case UNIT_MVAr:
228  m_choiceMaxRectivePower->SetSelection(3);
229  break;
230  default:
231  break;
232  }
233  m_textCtrlMaxRectivePower->Enable(data.haveMaxReactive);
234  m_choiceMaxRectivePower->Enable(data.haveMaxReactive);
235 
236  m_checkBoxMinReactive->SetValue(data.haveMinReactive);
237  m_textCtrlMinRectivePower->SetValue(SyncMotor::StringFromDouble(data.minReactive));
238  switch(data.minReactiveUnit) {
239  case UNIT_PU:
240  m_choiceMinRectivePower->SetSelection(0);
241  break;
242  case UNIT_VAr:
243  m_choiceMinRectivePower->SetSelection(1);
244  break;
245  case UNIT_kVAr:
246  m_choiceMinRectivePower->SetSelection(2);
247  break;
248  case UNIT_MVAr:
249  m_choiceMinRectivePower->SetSelection(3);
250  break;
251  default:
252  break;
253  }
254  m_textCtrlMinRectivePower->Enable(data.haveMinReactive);
255  m_choiceMinRectivePower->Enable(data.haveMinReactive);
256 
257  m_checkBoxUseMachinePower->SetValue(data.useMachineBase);
258 
259  m_textCtrlPosResistance->SetValue(SyncMotor::StringFromDouble(data.positiveResistance));
260  m_textCtrlPosReactance->SetValue(SyncMotor::StringFromDouble(data.positiveReactance));
261  m_textCtrlNegResistance->SetValue(SyncMotor::StringFromDouble(data.negativeResistance));
262  m_textCtrlNegReactance->SetValue(SyncMotor::StringFromDouble(data.negativeReactance));
263  m_textCtrlZeroResistance->SetValue(SyncMotor::StringFromDouble(data.zeroResistance));
264  m_textCtrlZeroReactance->SetValue(SyncMotor::StringFromDouble(data.zeroReactance));
265  m_textCtrlGrdResistance->SetValue(SyncMotor::StringFromDouble(data.groundResistance));
266  m_textCtrlGrdReactance->SetValue(SyncMotor::StringFromDouble(data.groundReactance));
267  m_checkBoxGroundNeutral->SetValue(data.groundNeutral);
268 }
269 
270 SyncMachineForm::~SyncMachineForm() {}
271 void SyncMachineForm::OnCheckMaxReactive(wxCommandEvent& event)
272 {
273  m_textCtrlMaxRectivePower->Enable(m_checkBoxMaxReactive->GetValue());
274  m_choiceMaxRectivePower->Enable(m_checkBoxMaxReactive->GetValue());
275 }
276 void SyncMachineForm::OnCheckMinReactive(wxCommandEvent& event)
277 {
278  m_textCtrlMinRectivePower->Enable(m_checkBoxMinReactive->GetValue());
279  m_choiceMinRectivePower->Enable(m_checkBoxMinReactive->GetValue());
280 }
281 void SyncMachineForm::OnOKButtonClick(wxCommandEvent& event)
282 {
283  if(ValidateData()) EndModal(wxID_OK);
284 }
285 void SyncMachineForm::OnStabilityButtonClick(wxCommandEvent& event)
286 {
287  if(ValidateData()) {
288  if(m_syncGenerator) {
289  GeneratorStabForm* stabForm = new GeneratorStabForm(m_parent, m_syncGenerator);
290  if(stabForm->ShowModal() == wxID_OK) {
291  stabForm->Destroy();
292  EndModal(wxID_OK);
293  }
294 
295  stabForm->Destroy();
296  EndModal(wxID_CANCEL);
297  }
298  }
299 }
300 
301 bool SyncMachineForm::ValidateData()
302 {
303  if(m_syncGenerator) {
304  SyncGeneratorElectricalData data = m_syncGenerator->GetElectricalData();
305  data.name = m_textCtrlName->GetValue();
306 
307  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlnominalPower->GetValue(), data.nominalPower,
308  _("Value entered incorrectly in the field \"Nominal power\".")))
309  return false;
310  switch(m_choiceNominalPower->GetSelection()) {
311  case 0:
312  data.nominalPowerUnit = UNIT_VA;
313  break;
314  case 1:
315  data.nominalPowerUnit = UNIT_kVA;
316  break;
317  case 2:
318  data.nominalPowerUnit = UNIT_MVA;
319  break;
320  }
321 
322  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
323  _("Value entered incorrectly in the field \"Active power\".")))
324  return false;
325  switch(m_choiceActivePower->GetSelection()) {
326  case 0:
327  data.activePowerUnit = UNIT_PU;
328  break;
329  case 1:
330  data.activePowerUnit = UNIT_W;
331  break;
332  case 2:
333  data.activePowerUnit = UNIT_kW;
334  break;
335  case 3:
336  data.activePowerUnit = UNIT_MW;
337  break;
338  }
339 
340  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
341  _("Value entered incorrectly in the field \"Reactive power\".")))
342  return false;
343  switch(m_choiceReactivePower->GetSelection()) {
344  case 0:
345  data.reactivePowerUnit = UNIT_PU;
346  break;
347  case 1:
348  data.reactivePowerUnit = UNIT_VAr;
349  break;
350  case 2:
351  data.reactivePowerUnit = UNIT_kVAr;
352  break;
353  case 3:
354  data.reactivePowerUnit = UNIT_MVAr;
355  break;
356  }
357 
358  data.haveMaxReactive = m_checkBoxMaxReactive->GetValue();
359  if(data.haveMaxReactive) {
360  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlMaxRectivePower->GetValue(), data.maxReactive,
361  _("Value entered incorrectly in the field \"Max reactive power\".")))
362  return false;
363  switch(m_choiceMaxRectivePower->GetSelection()) {
364  case 0:
365  data.maxReactiveUnit = UNIT_PU;
366  break;
367  case 1:
368  data.maxReactiveUnit = UNIT_VAr;
369  break;
370  case 2:
371  data.maxReactiveUnit = UNIT_kVAr;
372  break;
373  case 3:
374  data.maxReactiveUnit = UNIT_MVAr;
375  break;
376  }
377  }
378 
379  data.haveMinReactive = m_checkBoxMinReactive->GetValue();
380  if(data.haveMinReactive) {
381  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlMinRectivePower->GetValue(), data.minReactive,
382  _("Value entered incorrectly in the field \"Min reactive power\".")))
383  return false;
384  switch(m_choiceMinRectivePower->GetSelection()) {
385  case 0:
386  data.minReactiveUnit = UNIT_PU;
387  break;
388  case 1:
389  data.minReactiveUnit = UNIT_VAr;
390  break;
391  case 2:
392  data.minReactiveUnit = UNIT_kVAr;
393  break;
394  case 3:
395  data.minReactiveUnit = UNIT_MVAr;
396  break;
397  }
398  }
399 
400  data.useMachineBase = m_checkBoxUseMachinePower->GetValue();
401 
402  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlPosResistance->GetValue(), data.positiveResistance,
403  _("Value entered incorrectly in the field \"Positive resistance\".")))
404  return false;
405 
406  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlPosReactance->GetValue(), data.positiveReactance,
407  _("Value entered incorrectly in the field \"Positive reactance\".")))
408  return false;
409 
410  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlNegResistance->GetValue(), data.negativeResistance,
411  _("Value entered incorrectly in the field \"Negative resistance\".")))
412  return false;
413 
414  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlNegReactance->GetValue(), data.negativeReactance,
415  _("Value entered incorrectly in the field \"Negative reactance\".")))
416  return false;
417 
418  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
419  _("Value entered incorrectly in the field \"Zero resistance\".")))
420  return false;
421 
422  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroReactance,
423  _("Value entered incorrectly in the field \"Zero reactance\".")))
424  return false;
425 
426  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlGrdResistance->GetValue(), data.groundResistance,
427  _("Value entered incorrectly in the field \"Ground resistance\".")))
428  return false;
429 
430  if(!m_syncGenerator->DoubleFromString(m_parent, m_textCtrlGrdReactance->GetValue(), data.groundReactance,
431  _("Value entered incorrectly in the field \"Ground reactance\".")))
432  return false;
433 
434  data.groundNeutral = m_checkBoxGroundNeutral->GetValue();
435 
436  m_syncGenerator->SetElectricalData(data);
437  } else if(m_syncMotor) {
438  SyncMotorElectricalData data = m_syncMotor->GetElectricalData();
439  data.name = m_textCtrlName->GetValue();
440 
441  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlnominalPower->GetValue(), data.nominalPower,
442  _("Value entered incorrectly in the field \"Nominal power\".")))
443  return false;
444  switch(m_choiceNominalPower->GetSelection()) {
445  case 0:
446  data.nominalPowerUnit = UNIT_VA;
447  break;
448  case 1:
449  data.nominalPowerUnit = UNIT_kVA;
450  break;
451  case 2:
452  data.nominalPowerUnit = UNIT_MVA;
453  break;
454  }
455 
456  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlActivePower->GetValue(), data.activePower,
457  _("Value entered incorrectly in the field \"Active power\".")))
458  return false;
459  switch(m_choiceActivePower->GetSelection()) {
460  case 0:
461  data.activePowerUnit = UNIT_PU;
462  break;
463  case 1:
464  data.activePowerUnit = UNIT_W;
465  break;
466  case 2:
467  data.activePowerUnit = UNIT_kW;
468  break;
469  case 3:
470  data.activePowerUnit = UNIT_MW;
471  break;
472  }
473 
474  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlReactivePower->GetValue(), data.reactivePower,
475  _("Value entered incorrectly in the field \"Reactive power\".")))
476  return false;
477  switch(m_choiceReactivePower->GetSelection()) {
478  case 0:
479  data.reactivePowerUnit = UNIT_PU;
480  break;
481  case 1:
482  data.reactivePowerUnit = UNIT_VAr;
483  break;
484  case 2:
485  data.reactivePowerUnit = UNIT_kVAr;
486  break;
487  case 3:
488  data.reactivePowerUnit = UNIT_MVAr;
489  break;
490  }
491 
492  data.haveMaxReactive = m_checkBoxMaxReactive->GetValue();
493  if(data.haveMaxReactive) {
494  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlMaxRectivePower->GetValue(), data.maxReactive,
495  _("Value entered incorrectly in the field \"Max reactive power\".")))
496  return false;
497  switch(m_choiceMaxRectivePower->GetSelection()) {
498  case 0:
499  data.maxReactiveUnit = UNIT_PU;
500  break;
501  case 1:
502  data.maxReactiveUnit = UNIT_VAr;
503  break;
504  case 2:
505  data.maxReactiveUnit = UNIT_kVAr;
506  break;
507  case 3:
508  data.maxReactiveUnit = UNIT_MVAr;
509  break;
510  }
511  }
512 
513  data.haveMinReactive = m_checkBoxMinReactive->GetValue();
514  if(data.haveMinReactive) {
515  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlMinRectivePower->GetValue(), data.minReactive,
516  _("Value entered incorrectly in the field \"Min reactive power\".")))
517  return false;
518  switch(m_choiceMinRectivePower->GetSelection()) {
519  case 0:
520  data.minReactiveUnit = UNIT_PU;
521  break;
522  case 1:
523  data.minReactiveUnit = UNIT_VAr;
524  break;
525  case 2:
526  data.minReactiveUnit = UNIT_kVAr;
527  break;
528  case 3:
529  data.minReactiveUnit = UNIT_MVAr;
530  break;
531  }
532  }
533 
534  data.useMachineBase = m_checkBoxUseMachinePower->GetValue();
535 
536  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlPosResistance->GetValue(), data.positiveResistance,
537  _("Value entered incorrectly in the field \"Positive resistance\".")))
538  return false;
539 
540  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlPosReactance->GetValue(), data.positiveReactance,
541  _("Value entered incorrectly in the field \"Positive reactance\".")))
542  return false;
543 
544  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlNegResistance->GetValue(), data.negativeResistance,
545  _("Value entered incorrectly in the field \"Negative resistance\".")))
546  return false;
547 
548  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlNegReactance->GetValue(), data.negativeReactance,
549  _("Value entered incorrectly in the field \"Negative reactance\".")))
550  return false;
551 
552  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
553  _("Value entered incorrectly in the field \"Zero resistance\".")))
554  return false;
555 
556  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroReactance,
557  _("Value entered incorrectly in the field \"Zero reactance\".")))
558  return false;
559 
560  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlGrdResistance->GetValue(), data.groundResistance,
561  _("Value entered incorrectly in the field \"Ground resistance\".")))
562  return false;
563 
564  if(!m_syncMotor->DoubleFromString(m_parent, m_textCtrlGrdReactance->GetValue(), data.groundReactance,
565  _("Value entered incorrectly in the field \"Ground reactance\".")))
566  return false;
567 
568  data.groundNeutral = m_checkBoxGroundNeutral->GetValue();
569 
570  m_syncMotor->SetElectricalData(data);
571  }
572  return true;
573 }
574 
575 void SyncMachineForm::ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar)
576 {
577  wxString label = staticText->GetLabel();
578  label[label.length() - 2] = newChar;
579  staticText->SetLabel(label);
580 }
+ - +
Synchronous generator power element.
+
Form to edit the synchronous generator data for electromechanical studies.
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
static wxString StringFromDouble(double value, int minDecimal=1)
Convert a double value to string.
Definition: Element.cpp:320
diff --git a/docs/doxygen/html/_sync_machine_form_8h_source.html b/docs/doxygen/html/_sync_machine_form_8h_source.html index bd189b2..15aa6ca 100644 --- a/docs/doxygen/html/_sync_machine_form_8h_source.html +++ b/docs/doxygen/html/_sync_machine_form_8h_source.html @@ -88,11 +88,11 @@ $(document).ready(function(){initNavTree('_sync_machine_form_8h_source.html','')
SyncMachineForm.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCMACHINEFORM_H
19 #define SYNCMACHINEFORM_H
20 
21 #include "ElementForm.h"
22 
23 class GeneratorStabForm;
24 class SyncGenerator;
25 class SyncMotor;
26 
35 {
36  public:
37  SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator);
38  SyncMachineForm(wxWindow* parent, SyncMotor* syncMotor);
39  virtual ~SyncMachineForm();
40 
41  protected:
42  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); };
43  virtual void OnCheckMaxReactive(wxCommandEvent& event);
44  virtual void OnCheckMinReactive(wxCommandEvent& event);
45  virtual void OnOKButtonClick(wxCommandEvent& event);
46  virtual void OnStabilityButtonClick(wxCommandEvent& event);
47 
48  virtual bool ValidateData();
49  virtual void ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar);
50 
51  SyncGenerator* m_syncGenerator = NULL;
52  SyncMotor* m_syncMotor = NULL;
53  wxWindow* m_parent = NULL;
54 };
55 #endif // SYNCMACHINEFORM_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCMACHINEFORM_H
19 #define SYNCMACHINEFORM_H
20 
21 #include "ElementForm.h"
22 
23 class GeneratorStabForm;
24 class SyncGenerator;
25 class SyncMotor;
26 
35 {
36  public:
37  SyncMachineForm(wxWindow* parent, SyncGenerator* syncGenerator);
38  SyncMachineForm(wxWindow* parent, SyncMotor* syncMotor);
39  virtual ~SyncMachineForm();
40 
41  protected:
42  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); };
43  virtual void OnCheckMaxReactive(wxCommandEvent& event);
44  virtual void OnCheckMinReactive(wxCommandEvent& event);
45  virtual void OnOKButtonClick(wxCommandEvent& event);
46  virtual void OnStabilityButtonClick(wxCommandEvent& event);
47 
48  virtual bool ValidateData();
49  virtual void ReplaceStaticTextLabelChar(wxStaticText* staticText, wchar_t newChar);
50 
51  SyncGenerator* m_syncGenerator = NULL;
52  SyncMotor* m_syncMotor = NULL;
53  wxWindow* m_parent = NULL;
54 };
55 #endif // SYNCMACHINEFORM_H
Synchronous generator power element.
Form to edit the synchronous machine power data.
Form to edit the synchronous generator data for electromechanical studies.
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
diff --git a/docs/doxygen/html/_sync_motor_8cpp_source.html b/docs/doxygen/html/_sync_motor_8cpp_source.html index 54f9987..7c4589b 100644 --- a/docs/doxygen/html/_sync_motor_8cpp_source.html +++ b/docs/doxygen/html/_sync_motor_8cpp_source.html @@ -88,7 +88,7 @@ $(document).ready(function(){initNavTree('_sync_motor_8cpp_source.html','');});
SyncMotor.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SyncMachineForm.h"
19 #include "SyncMotor.h"
20 
21 SyncMotor::SyncMotor() : Machines() {}
22 SyncMotor::SyncMotor(wxString name) : Machines() { m_electricalData.name = name; }
23 SyncMotor::~SyncMotor() {}
24 void SyncMotor::DrawSymbol() const { DrawArc(m_position, 12, 30, 330, 10, GL_LINE_STRIP); }
25 bool SyncMotor::GetContextMenu(wxMenu& menu)
26 {
27  menu.Append(ID_EDIT_ELEMENT, _("Edit Synchronous Condenser"));
28  GeneralMenuItens(menu);
29 
30  return true;
31 }
32 
33 bool SyncMotor::ShowForm(wxWindow* parent, Element* element)
34 {
35  SyncMachineForm* syncMotorForm = new SyncMachineForm(parent, this);
36  syncMotorForm->SetTitle(_("Synchronous Condenser"));
37  if(syncMotorForm->ShowModal() == wxID_OK) {
38  syncMotorForm->Destroy();
39  return true;
40  }
41 
42  syncMotorForm->Destroy();
43  return false;
44 }
45 
46 SyncMotorElectricalData SyncMotor::GetPUElectricalData(double systemPowerBase)
47 {
48  SyncMotorElectricalData data = m_electricalData;
49  double machineBasePower = 1.0;
50  if(data.useMachineBase) {
51  machineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
52  }
53 
54  // Active power
55  double activePower = GetValueFromUnit(data.activePower, data.activePowerUnit);
56  if(!m_online) activePower = 0.0;
57  if(data.activePowerUnit == UNIT_PU) {
58  if(data.useMachineBase) data.activePower = (activePower * machineBasePower) / systemPowerBase;
59  } else {
60  data.activePower = activePower / systemPowerBase;
61  }
62  data.activePowerUnit = UNIT_PU;
63 
64  // Reactive power
65  double reactivePower = GetValueFromUnit(data.reactivePower, data.reactivePowerUnit);
66  if(!m_online) reactivePower = 0.0;
67  if(data.reactivePowerUnit == UNIT_PU) {
68  if(data.useMachineBase) data.reactivePower = (reactivePower * machineBasePower) / systemPowerBase;
69  } else {
70  data.reactivePower = reactivePower / systemPowerBase;
71  }
72  data.reactivePowerUnit = UNIT_PU;
73 
74  // Max reactive power
75  double maxReactive = GetValueFromUnit(data.maxReactive, data.maxReactiveUnit);
76  if(data.maxReactiveUnit == UNIT_PU) {
77  if(data.useMachineBase) data.maxReactive = (maxReactive * machineBasePower) / systemPowerBase;
78  } else {
79  data.maxReactive = maxReactive / systemPowerBase;
80  }
81  data.maxReactiveUnit = UNIT_PU;
82 
83  // Min reactive power
84  double minReactive = GetValueFromUnit(data.minReactive, data.minReactiveUnit);
85  if(data.minReactiveUnit == UNIT_PU) {
86  if(data.useMachineBase) data.minReactive = (minReactive * machineBasePower) / systemPowerBase;
87  } else {
88  data.minReactive = minReactive / systemPowerBase;
89  }
90  data.minReactiveUnit = UNIT_PU;
91 
92  double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
93  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemPowerBase;
94  double machineBaseImpedance = (baseVoltage * baseVoltage) / machineBasePower;
95 
96  // Fault data
97  if(data.useMachineBase) {
98  data.positiveResistance = (data.positiveResistance * machineBaseImpedance) / systemBaseImpedance;
99  data.positiveReactance = (data.positiveReactance * machineBaseImpedance) / systemBaseImpedance;
100  data.negativeResistance = (data.negativeResistance * machineBaseImpedance) / systemBaseImpedance;
101  data.negativeReactance = (data.negativeReactance * machineBaseImpedance) / systemBaseImpedance;
102  data.zeroResistance = (data.zeroResistance * machineBaseImpedance) / systemBaseImpedance;
103  data.zeroReactance = (data.zeroReactance * machineBaseImpedance) / systemBaseImpedance;
104  data.groundResistance = (data.groundResistance * machineBaseImpedance) / systemBaseImpedance;
105  data.groundReactance = (data.groundReactance * machineBaseImpedance) / systemBaseImpedance;
106  }
107 
108  if(!m_online) {
109  data.faultCurrent[0] = std::complex<double>(0, 0);
110  data.faultCurrent[1] = std::complex<double>(0, 0);
111  data.faultCurrent[2] = std::complex<double>(0, 0);
112  }
113 
114  return data;
115 }
116 
117 void SyncMotor::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
118 {
119  if(nominalVoltage.size() > 0) {
120  m_electricalData.nominalVoltage = nominalVoltage[0];
121  m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
122  }
123 }
124 
126 {
127  SyncMotor* copy = new SyncMotor();
128  *copy = *this;
129  return copy;
130 }
131 
132 wxString SyncMotor::GetTipText() const
133 {
134  wxString tipText = m_electricalData.name;
135  tipText += "\n";
136  double activePower = m_electricalData.activePower;
137  if(!m_online) activePower = 0.0;
138  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
139  switch(m_electricalData.activePowerUnit) {
140  case UNIT_PU: {
141  tipText += _(" p.u.");
142  } break;
143  case UNIT_W: {
144  tipText += _(" W");
145  } break;
146  case UNIT_kW: {
147  tipText += _(" kW");
148  } break;
149  case UNIT_MW: {
150  tipText += _(" MW");
151  } break;
152  default:
153  break;
154  }
155  double reactivePower = m_electricalData.reactivePower;
156  if(!m_online) reactivePower = 0.0;
157  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
158  switch(m_electricalData.reactivePowerUnit) {
159  case UNIT_PU: {
160  tipText += _(" p.u.");
161  } break;
162  case UNIT_VAr: {
163  tipText += _(" VAr");
164  } break;
165  case UNIT_kVAr: {
166  tipText += _(" kVAr");
167  } break;
168  case UNIT_MVAr: {
169  tipText += _(" MVAr");
170  } break;
171  default:
172  break;
173  }
174 
175  return tipText;
176 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "SyncMachineForm.h"
19 #include "SyncMotor.h"
20 
21 SyncMotor::SyncMotor() : Machines() {}
22 SyncMotor::SyncMotor(wxString name) : Machines() { m_electricalData.name = name; }
23 SyncMotor::~SyncMotor() {}
24 void SyncMotor::DrawSymbol() const { DrawArc(m_position, 12, 30, 330, 10, GL_LINE_STRIP); }
25 bool SyncMotor::GetContextMenu(wxMenu& menu)
26 {
27  menu.Append(ID_EDIT_ELEMENT, _("Edit Synchronous Condenser"));
28  GeneralMenuItens(menu);
29 
30  return true;
31 }
32 
33 bool SyncMotor::ShowForm(wxWindow* parent, Element* element)
34 {
35  SyncMachineForm* syncMotorForm = new SyncMachineForm(parent, this);
36  syncMotorForm->SetTitle(_("Synchronous Condenser"));
37  if(syncMotorForm->ShowModal() == wxID_OK) {
38  syncMotorForm->Destroy();
39  return true;
40  }
41 
42  syncMotorForm->Destroy();
43  return false;
44 }
45 
46 SyncMotorElectricalData SyncMotor::GetPUElectricalData(double systemPowerBase)
47 {
48  SyncMotorElectricalData data = m_electricalData;
49  double machineBasePower = 1.0;
50  if(data.useMachineBase) {
51  machineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
52  }
53 
54  // Active power
55  double activePower = GetValueFromUnit(data.activePower, data.activePowerUnit);
56  if(!m_online) activePower = 0.0;
57  if(data.activePowerUnit == UNIT_PU) {
58  if(data.useMachineBase) data.activePower = (activePower * machineBasePower) / systemPowerBase;
59  } else {
60  data.activePower = activePower / systemPowerBase;
61  }
62  data.activePowerUnit = UNIT_PU;
63 
64  // Reactive power
65  double reactivePower = GetValueFromUnit(data.reactivePower, data.reactivePowerUnit);
66  if(!m_online) reactivePower = 0.0;
67  if(data.reactivePowerUnit == UNIT_PU) {
68  if(data.useMachineBase) data.reactivePower = (reactivePower * machineBasePower) / systemPowerBase;
69  } else {
70  data.reactivePower = reactivePower / systemPowerBase;
71  }
72  data.reactivePowerUnit = UNIT_PU;
73 
74  // Max reactive power
75  double maxReactive = GetValueFromUnit(data.maxReactive, data.maxReactiveUnit);
76  if(data.maxReactiveUnit == UNIT_PU) {
77  if(data.useMachineBase) data.maxReactive = (maxReactive * machineBasePower) / systemPowerBase;
78  } else {
79  data.maxReactive = maxReactive / systemPowerBase;
80  }
81  data.maxReactiveUnit = UNIT_PU;
82 
83  // Min reactive power
84  double minReactive = GetValueFromUnit(data.minReactive, data.minReactiveUnit);
85  if(data.minReactiveUnit == UNIT_PU) {
86  if(data.useMachineBase) data.minReactive = (minReactive * machineBasePower) / systemPowerBase;
87  } else {
88  data.minReactive = minReactive / systemPowerBase;
89  }
90  data.minReactiveUnit = UNIT_PU;
91 
92  double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
93  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemPowerBase;
94  double machineBaseImpedance = (baseVoltage * baseVoltage) / machineBasePower;
95 
96  // Fault data
97  if(data.useMachineBase) {
98  data.positiveResistance = (data.positiveResistance * machineBaseImpedance) / systemBaseImpedance;
99  data.positiveReactance = (data.positiveReactance * machineBaseImpedance) / systemBaseImpedance;
100  data.negativeResistance = (data.negativeResistance * machineBaseImpedance) / systemBaseImpedance;
101  data.negativeReactance = (data.negativeReactance * machineBaseImpedance) / systemBaseImpedance;
102  data.zeroResistance = (data.zeroResistance * machineBaseImpedance) / systemBaseImpedance;
103  data.zeroReactance = (data.zeroReactance * machineBaseImpedance) / systemBaseImpedance;
104  data.groundResistance = (data.groundResistance * machineBaseImpedance) / systemBaseImpedance;
105  data.groundReactance = (data.groundReactance * machineBaseImpedance) / systemBaseImpedance;
106  }
107 
108  if(!m_online) {
109  data.faultCurrent[0] = std::complex<double>(0, 0);
110  data.faultCurrent[1] = std::complex<double>(0, 0);
111  data.faultCurrent[2] = std::complex<double>(0, 0);
112  }
113 
114  return data;
115 }
116 
117 void SyncMotor::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
118 {
119  if(nominalVoltage.size() > 0) {
120  m_electricalData.nominalVoltage = nominalVoltage[0];
121  m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
122  }
123 }
124 
126 {
127  SyncMotor* copy = new SyncMotor();
128  *copy = *this;
129  return copy;
130 }
131 
132 wxString SyncMotor::GetTipText() const
133 {
134  wxString tipText = m_electricalData.name;
135  tipText += "\n";
136  double activePower = m_electricalData.activePower;
137  if(!m_online) activePower = 0.0;
138  tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
139  switch(m_electricalData.activePowerUnit) {
140  case UNIT_PU: {
141  tipText += _(" p.u.");
142  } break;
143  case UNIT_W: {
144  tipText += _(" W");
145  } break;
146  case UNIT_kW: {
147  tipText += _(" kW");
148  } break;
149  case UNIT_MW: {
150  tipText += _(" MW");
151  } break;
152  default:
153  break;
154  }
155  double reactivePower = m_electricalData.reactivePower;
156  if(!m_online) reactivePower = 0.0;
157  tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
158  switch(m_electricalData.reactivePowerUnit) {
159  case UNIT_PU: {
160  tipText += _(" p.u.");
161  } break;
162  case UNIT_VAr: {
163  tipText += _(" VAr");
164  } break;
165  case UNIT_kVAr: {
166  tipText += _(" kVAr");
167  } break;
168  case UNIT_MVAr: {
169  tipText += _(" MVAr");
170  } break;
171  default:
172  break;
173  }
174 
175  return tipText;
176 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual Element * GetCopy()
Get a the element copy.
Definition: SyncMotor.cpp:125
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: SyncMotor.cpp:25
virtual wxString GetTipText() const
Get the tip text.
Definition: SyncMotor.cpp:132
@@ -96,14 +96,15 @@ $(document).ready(function(){initNavTree('_sync_motor_8cpp_source.html','');}); +
Form to edit the synchronous machine power data.
- +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
Definition: SyncMotor.cpp:117
- +
Abstract class for rotary machines power elements.
Definition: Machines.h:33
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: SyncMotor.cpp:33
diff --git a/docs/doxygen/html/_sync_motor_8h.html b/docs/doxygen/html/_sync_motor_8h.html new file mode 100644 index 0000000..4de597b --- /dev/null +++ b/docs/doxygen/html/_sync_motor_8h.html @@ -0,0 +1,117 @@ + + + + + + + + + +Project/SyncMotor.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
SyncMotor.h File Reference
+
+
+
#include "Machines.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  SyncMotorElectricalData
 
class  SyncMotor
 Synchronous motor (synchronous compensator) power element. More...
 
+
+
+ + + + diff --git a/docs/doxygen/html/_sync_motor_8h_source.html b/docs/doxygen/html/_sync_motor_8h_source.html index d443e20..c14907d 100644 --- a/docs/doxygen/html/_sync_motor_8h_source.html +++ b/docs/doxygen/html/_sync_motor_8h_source.html @@ -88,25 +88,26 @@ $(document).ready(function(){initNavTree('_sync_motor_8h_source.html','');});
SyncMotor.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCMOTOR_H
19 #define SYNCMOTOR_H
20 
21 #include "Machines.h"
22 
23 class SyncMachineForm;
24 
26  // General
27  wxString name = "";
28  double nominalPower = 100.0;
29  ElectricalUnit nominalPowerUnit = UNIT_MVA;
30  double nominalVoltage = 13.8;
31  ElectricalUnit nominalVoltageUnit = UNIT_kV;
32  double activePower = 100.0;
33  ElectricalUnit activePowerUnit = UNIT_MW;
34  double reactivePower = 0.0;
35  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
36  bool haveMaxReactive = false;
37  double maxReactive = 9999.0;
38  ElectricalUnit maxReactiveUnit = UNIT_MVAr;
39  bool haveMinReactive = false;
40  double minReactive = -9999.0;
41  ElectricalUnit minReactiveUnit = UNIT_MVAr;
42  bool useMachineBase = true;
43 
44  // Fault
45  double positiveResistance = 0.0;
46  double positiveReactance = 1.0;
47  double negativeResistance = 0.0;
48  double negativeReactance = 1.0;
49  double zeroResistance = 0.0;
50  double zeroReactance = 1.0;
51  double groundResistance = 0.0;
52  double groundReactance = 0.0;
53  bool groundNeutral = true;
54  // p.u. fault data
55  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
56  std::complex<double>(0.0, 0.0)};
57 
58  // Stability
59  bool plotSyncMachine = false;
60  double inertia = 1.0;
61  double damping = 0.0;
62  bool useAVR = false;
63  bool useSpeedGovernor = false;
64 
65  double armResistance = 0.0;
66  double potierReactance = 0.0;
67  double satFactor = 0.0;
68 
69  double syncXd = 0.0;
70  double syncXq = 0.0;
71  double transXd = 1.0;
72  double transXq = 0.0;
73  double transTd0 = 0.0;
74  double transTq0 = 0.0;
75  double subXd = 0.0;
76  double subXq = 0.0;
77  double subTd0 = 0.0;
78  double subTq0 = 0.0;
79 
80  // Machine state variables
81  std::complex<double> terminalVoltage;
82  std::vector<std::complex<double> > terminalVoltageVector;
83  std::complex<double> electricalPower;
84  std::vector<std::complex<double> > electricalPowerVector;
85  double pm;
86  std::vector<double> mechanicalPowerVector;
87  double speed;
88  std::vector<double> freqVector;
89  double fieldVoltage;
90  std::vector<double> fieldVoltageVector;
91  double delta;
92  std::vector<double> deltaVector;
93 
94  double initialFieldVoltage;
95 
96  // Internal machine variables
97  double tranEq;
98  double tranEd;
99  double subEq;
100  double subEd;
101  double pe;
102 
103  // Variables to extrapolate
104  double oldId;
105  double oldIq;
106  double oldPe;
107 
108  // Integration constants
109  IntegrationConstant icSpeed;
110  IntegrationConstant icDelta;
111  IntegrationConstant icTranEq;
112  IntegrationConstant icTranEd;
113  IntegrationConstant icSubEq;
114  IntegrationConstant icSubEd;
115 
116  // Control
117  ControlElementContainer* avr = NULL;
118  ControlElementContainer* speedGov = NULL;
119 
120  // Control solvers
121  ControlElementSolver* avrSolver = NULL;
122  ControlElementSolver* speedGovSolver = NULL;
123 
124  Machines::SyncMachineModel model = Machines::SM_MODEL_1;
125 };
126 
127 class SyncMotor : public Machines
128 {
129  public:
130  SyncMotor();
131  SyncMotor(wxString name);
132  ~SyncMotor();
133 
134  virtual Element* GetCopy();
135  virtual void DrawSymbol() const;
136  virtual bool GetContextMenu(wxMenu& menu);
137  virtual wxString GetTipText() const;
138  virtual SyncMotorElectricalData GetElectricalData() { return m_electricalData; }
139  virtual SyncMotorElectricalData GetPUElectricalData(double systemPowerBase);
140  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
141  virtual void SetElectricalData(SyncMotorElectricalData electricalData) { m_electricalData = electricalData; }
142  virtual bool ShowForm(wxWindow* parent, Element* element);
143 
144  protected:
145  SyncMotorElectricalData m_electricalData;
146 };
147 
148 #endif // SYNCMOTOR_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef SYNCMOTOR_H
19 #define SYNCMOTOR_H
20 
21 #include "Machines.h"
22 
23 class SyncMachineForm;
24 
26  // General
27  wxString name = "";
28  double nominalPower = 100.0;
29  ElectricalUnit nominalPowerUnit = UNIT_MVA;
30  double nominalVoltage = 13.8;
31  ElectricalUnit nominalVoltageUnit = UNIT_kV;
32  double activePower = 100.0;
33  ElectricalUnit activePowerUnit = UNIT_MW;
34  double reactivePower = 0.0;
35  ElectricalUnit reactivePowerUnit = UNIT_MVAr;
36  bool haveMaxReactive = false;
37  double maxReactive = 9999.0;
38  ElectricalUnit maxReactiveUnit = UNIT_MVAr;
39  bool haveMinReactive = false;
40  double minReactive = -9999.0;
41  ElectricalUnit minReactiveUnit = UNIT_MVAr;
42  bool useMachineBase = true;
43 
44  // Fault
45  double positiveResistance = 0.0;
46  double positiveReactance = 1.0;
47  double negativeResistance = 0.0;
48  double negativeReactance = 1.0;
49  double zeroResistance = 0.0;
50  double zeroReactance = 1.0;
51  double groundResistance = 0.0;
52  double groundReactance = 0.0;
53  bool groundNeutral = true;
54  // p.u. fault data
55  std::complex<double> faultCurrent[3] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0),
56  std::complex<double>(0.0, 0.0)};
57 
58  // Stability
59  bool plotSyncMachine = false;
60  double inertia = 1.0;
61  double damping = 0.0;
62  bool useAVR = false;
63  bool useSpeedGovernor = false;
64 
65  double armResistance = 0.0;
66  double potierReactance = 0.0;
67  double satFactor = 0.0;
68 
69  double syncXd = 0.0;
70  double syncXq = 0.0;
71  double transXd = 1.0;
72  double transXq = 0.0;
73  double transTd0 = 0.0;
74  double transTq0 = 0.0;
75  double subXd = 0.0;
76  double subXq = 0.0;
77  double subTd0 = 0.0;
78  double subTq0 = 0.0;
79 
80  // Machine state variables
81  std::complex<double> terminalVoltage;
82  std::vector<std::complex<double> > terminalVoltageVector;
83  std::complex<double> electricalPower;
84  std::vector<std::complex<double> > electricalPowerVector;
85  double pm;
86  std::vector<double> mechanicalPowerVector;
87  double speed;
88  std::vector<double> freqVector;
89  double fieldVoltage;
90  std::vector<double> fieldVoltageVector;
91  double delta;
92  std::vector<double> deltaVector;
93 
94  double initialFieldVoltage;
95 
96  // Internal machine variables
97  double tranEq;
98  double tranEd;
99  double subEq;
100  double subEd;
101  double pe;
102 
103  // Variables to extrapolate
104  double oldId;
105  double oldIq;
106  double oldPe;
107 
108  // Integration constants
109  IntegrationConstant icSpeed;
110  IntegrationConstant icDelta;
111  IntegrationConstant icTranEq;
112  IntegrationConstant icTranEd;
113  IntegrationConstant icSubEq;
114  IntegrationConstant icSubEd;
115 
116  // Control
117  ControlElementContainer* avr = NULL;
118  ControlElementContainer* speedGov = NULL;
119 
120  // Control solvers
121  ControlElementSolver* avrSolver = NULL;
122  ControlElementSolver* speedGovSolver = NULL;
123 
124  Machines::SyncMachineModel model = Machines::SM_MODEL_1;
125 };
126 
134 class SyncMotor : public Machines
135 {
136  public:
137  SyncMotor();
138  SyncMotor(wxString name);
139  ~SyncMotor();
140 
141  virtual Element* GetCopy();
142  virtual void DrawSymbol() const;
143  virtual bool GetContextMenu(wxMenu& menu);
144  virtual wxString GetTipText() const;
145  virtual SyncMotorElectricalData GetElectricalData() { return m_electricalData; }
146  virtual SyncMotorElectricalData GetPUElectricalData(double systemPowerBase);
147  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
148  virtual void SetElectricalData(SyncMotorElectricalData electricalData) { m_electricalData = electricalData; }
149  virtual bool ShowForm(wxWindow* parent, Element* element);
150 
151  protected:
152  SyncMotorElectricalData m_electricalData;
153 };
154 
155 #endif // SYNCMOTOR_H
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
- +
Integration constants to calculate dynamic elements through trapezoidal integration method...
Definition: PowerElement.h:105
Form to edit the synchronous machine power data.
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
- - +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
Abstract class for rotary machines power elements.
Definition: Machines.h:33
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TextForm.h"
19 #include "Text.h"
20 
21 #ifdef USING_WX_3_0_X
22 #include "DegreesAndRadians.h"
23 #endif
24 #include "ElectricCalculation.h"
25 #include "Bus.h"
26 #include "Line.h"
27 #include "Transformer.h"
28 #include "SyncGenerator.h"
29 #include "IndMotor.h"
30 #include "SyncMotor.h"
31 #include "Load.h"
32 #include "Inductor.h"
33 #include "Capacitor.h"
34 
35 Text::Text() : GraphicalElement() { SetText(m_text); }
36 Text::Text(wxPoint2DDouble position) : GraphicalElement()
37 {
38  m_position = position;
39  SetText(m_text);
40 }
41 
42 Text::~Text()
43 {
44  if(m_glString) delete m_glString;
45  if(m_glStringArray) delete m_glStringArray;
46 }
47 bool Text::Contains(wxPoint2DDouble position) const
48 {
49  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
50  return m_rect.Contains(ptR);
51 }
52 
53 void Text::Draw(wxPoint2DDouble translation, double scale)
54 {
55  wxScreenDC dc;
56 
57  // Draw selection rectangle
58 
59  // Push the current matrix on stack.
60  glPushMatrix();
61  // Rotate the matrix around the object position.
62  glTranslated(m_position.m_x, m_position.m_y, 0.0);
63  glRotated(m_angle, 0.0, 0.0, 1.0);
64  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
65 
66  if(m_selected) {
67  glColor4d(0.0, 0.5, 1.0, 0.5);
68  DrawRectangle(m_position + wxPoint2DDouble(m_borderSize / 2.0, m_borderSize / 2.0), m_rect.m_width,
69  m_rect.m_height);
70  }
71 
72  // Draw text (layer 2)
73  glEnable(GL_TEXTURE_2D);
74  glColor4d(0.0, 0.0, 0.0, 1.0);
75  if(!m_isMultlineText) { // Only one line
76  m_glString->bind();
77  m_glString->render(m_position.m_x, m_position.m_y);
78  } else { // Multiples lines
79  m_glStringArray->bind();
80  // The text will be printed centralized.
81  double lineHeight = m_height / (double)m_numberOfLines;
82  for(int i = 0; i < m_numberOfLines; i++) {
83  m_glStringArray->get(i)
84  .render(m_position.m_x, m_position.m_y - m_height / 2.0 + lineHeight / 2.0 + lineHeight * double(i));
85  }
86  }
87  glDisable(GL_TEXTURE_2D);
88 
89  glPopMatrix();
90 }
91 
92 bool Text::Intersects(wxRect2DDouble rect) const
93 {
94  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
95  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
96 }
97 
98 void Text::SetText(wxString text)
99 {
100  glEnable(GL_TEXTURE_2D);
101  m_text = text;
102  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
103 
104  wxScreenDC dc;
105  GLuint* idString = NULL;
106  GLuint* idStringArray = NULL;
107 
108  if(m_glString) {
109  delete m_glString;
110  m_glString = NULL;
111 
112  idString = new GLuint;
113  glGenTextures(1, idString);
114  }
115  if(m_glStringArray) {
116  delete m_glStringArray;
117  m_glStringArray = NULL;
118 
119  idStringArray = new GLuint;
120  glGenTextures(1, idStringArray);
121  }
122 
123  m_numberOfLines = m_text.Freq('\n') + 1;
124  if(m_numberOfLines == 1) { // Only one line
125  m_isMultlineText = false;
126  m_glString = new wxGLString(m_text);
127  m_glString->setFont(font);
128  m_glString->consolidate(&dc);
129  m_width = m_glString->getWidth();
130  m_height = m_glString->getheight();
131  } else {
132  m_isMultlineText = true;
133  m_glStringArray = new wxGLStringArray();
134  dc.SetFont(font);
135 
136  m_width = 0.0;
137  m_height = 0.0;
138  wxString multText = m_text;
139  for(int i = 0; i < m_numberOfLines; ++i) {
140  wxString nextLine;
141  wxString currentLine = multText.BeforeFirst('\n', &nextLine);
142  multText = nextLine;
143  m_glStringArray->addString(currentLine);
144 
145  wxSize size = dc.GetTextExtent(currentLine);
146  if(size.GetWidth() > m_width) m_width = size.GetWidth();
147  m_height += size.GetHeight();
148  }
149 
150  m_glStringArray->setFont(font);
151  m_glStringArray->consolidate(&dc);
152  }
153 
154  if(idString) glDeleteTextures(1, idString);
155  if(idStringArray) glDeleteTextures(1, idStringArray);
156 
157  // Update text rectangle.
158  SetPosition(m_position);
159  glDisable(GL_TEXTURE_2D);
160 }
161 
162 void Text::Rotate(bool clockwise)
163 {
164  double rotAngle = m_rotationAngle;
165  if(!clockwise) rotAngle = -m_rotationAngle;
166 
167  m_angle += rotAngle;
168  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
169 }
170 
171 bool Text::ShowForm(wxWindow* parent, std::vector<Element*> elementList)
172 {
173  TextForm* textForm = new TextForm(parent, this, elementList);
174  if(textForm->ShowModal() == wxID_OK) {
175  textForm->Destroy();
176  return true;
177  }
178  textForm->Destroy();
179  return false;
180 }
181 
182 void Text::UpdateText(double systemPowerBase)
183 {
184  switch(m_elementType) {
185  case TYPE_NONE:
186  SetText(m_text);
187  break;
188  case TYPE_BUS: {
189  Bus* bus = static_cast<Bus*>(m_element);
190  if(bus) {
191  BusElectricalData data = bus->GetElectricalData();
192  double baseVoltage = data.nominalVoltage;
193  if(data.nominalVoltageUnit == UNIT_kV) baseVoltage *= 1e3;
194  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
195 
196  switch(m_dataType) {
197  case DATA_NAME: {
198  SetText(bus->GetElectricalData().name);
199  } break;
200  case DATA_VOLTAGE: {
201  double voltage = std::abs(data.voltage);
202  switch(m_unit) {
203  case UNIT_PU: {
204  SetText(wxString::FromDouble(voltage, m_decimalPlaces) + " p.u.");
205  } break;
206  case UNIT_V: {
207  SetText(wxString::FromDouble(voltage * baseVoltage, m_decimalPlaces) + " V");
208  } break;
209  case UNIT_kV: {
210  SetText(wxString::FromDouble(voltage * baseVoltage / 1e3, m_decimalPlaces) + " kV");
211  } break;
212  default:
213  break;
214  }
215  } break;
216  case DATA_ANGLE: {
217  double angle = std::arg(data.voltage);
218  switch(m_unit) {
219  case UNIT_RADIAN: {
220  SetText(wxString::FromDouble(angle, m_decimalPlaces) + " rad");
221  } break;
222  case UNIT_DEGREE: {
223  SetText(wxString::FromDouble(wxRadToDeg(angle), m_decimalPlaces) + (wxString)L'\u00B0');
224  } break;
225  default:
226  break;
227  }
228  } break;
229  case DATA_SC_CURRENT: {
230  double faultCurrent[3] = {std::abs(data.faultCurrent[0]), std::abs(data.faultCurrent[1]),
231  std::abs(data.faultCurrent[2])};
232  switch(m_unit) {
233  case UNIT_PU: {
234  wxString str =
235  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
236  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
237  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
238  SetText(str);
239  } break;
240  case UNIT_A: {
241  wxString str = "Ia = " +
242  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
243  " A";
244  str += "\nIb = " +
245  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
246  str += "\nIc = " +
247  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
248  SetText(str);
249  } break;
250  case UNIT_kA: {
251  wxString str =
252  "Ia = " +
253  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
254  str += "\nIb = " +
255  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
256  " kA";
257  str += "\nIc = " +
258  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
259  " kA";
260  SetText(str);
261  } break;
262  default:
263  break;
264  }
265  } break;
266  case DATA_SC_VOLTAGE: {
267  double faultVoltage[3] = {std::abs(data.faultVoltage[0]), std::abs(data.faultVoltage[1]),
268  std::abs(data.faultVoltage[2])};
269  switch(m_unit) {
270  case UNIT_PU: {
271  wxString str =
272  "Va = " + wxString::FromDouble(faultVoltage[0], m_decimalPlaces) + " p.u.";
273  str += "\nVb = " + wxString::FromDouble(faultVoltage[1], m_decimalPlaces) + " p.u.";
274  str += "\nVc = " + wxString::FromDouble(faultVoltage[2], m_decimalPlaces) + " p.u.";
275  SetText(str);
276  } break;
277  case UNIT_V: {
278  wxString str = "Va = " +
279  wxString::FromDouble(faultVoltage[0] * baseVoltage, m_decimalPlaces) +
280  " V";
281  str += "\nVb = " +
282  wxString::FromDouble(faultVoltage[1] * baseVoltage, m_decimalPlaces) + " V";
283  str += "\nVc = " +
284  wxString::FromDouble(faultVoltage[2] * baseVoltage, m_decimalPlaces) + " V";
285  SetText(str);
286  } break;
287  case UNIT_kV: {
288  wxString str =
289  "Va = " +
290  wxString::FromDouble(faultVoltage[0] * baseVoltage / 1e3, m_decimalPlaces) + " kV";
291  str += "\nVb = " +
292  wxString::FromDouble(faultVoltage[1] * baseVoltage / 1e3, m_decimalPlaces) +
293  " kV";
294  str += "\nVc = " +
295  wxString::FromDouble(faultVoltage[2] * baseVoltage / 1e3, m_decimalPlaces) +
296  " kV";
297  SetText(str);
298  } break;
299  default:
300  break;
301  }
302  } break;
303  case DATA_SC_POWER: {
304  switch(m_unit) {
305  case UNIT_PU: {
306  SetText(wxString::FromDouble(data.scPower, m_decimalPlaces) + " p.u.");
307  } break;
308  case UNIT_VA: {
309  SetText(wxString::FromDouble(data.scPower * systemPowerBase, m_decimalPlaces) + " VA");
310  } break;
311  case UNIT_kVA: {
312  SetText(wxString::FromDouble(data.scPower * systemPowerBase / 1e3, m_decimalPlaces) +
313  " kVA");
314  } break;
315  case UNIT_MVA: {
316  SetText(wxString::FromDouble(data.scPower * systemPowerBase / 1e6, m_decimalPlaces) +
317  " MVA");
318  } break;
319  default:
320  break;
321  }
322  } break;
323  default:
324  break;
325  }
326  }
327  } break;
328  case TYPE_SYNC_GENERATOR: {
329  SyncGenerator* syncGenerator = static_cast<SyncGenerator*>(m_element);
330  if(syncGenerator) {
331  SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
332  double baseVoltage = syncGenerator->GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
333  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
334  switch(m_dataType) {
335  case DATA_NAME: {
336  SetText(data.name);
337  } break;
338  case DATA_ACTIVE_POWER: {
339  double activePower = data.activePower;
340  if(!syncGenerator->IsOnline()) activePower = 0.0;
341  switch(m_unit) {
342  case UNIT_PU: {
343  SetText(wxString::FromDouble(activePower, m_decimalPlaces) + " p.u.");
344  } break;
345  case UNIT_W: {
346  SetText(wxString::FromDouble(activePower * systemPowerBase, m_decimalPlaces) + " W");
347  } break;
348  case UNIT_kW: {
349  SetText(wxString::FromDouble(activePower * systemPowerBase / 1e3, m_decimalPlaces) +
350  " kW");
351  } break;
352  case UNIT_MW: {
353  SetText(wxString::FromDouble(activePower * systemPowerBase / 1e6, m_decimalPlaces) +
354  " MW");
355  } break;
356  default:
357  break;
358  }
359  } break;
360  case DATA_REACTIVE_POWER: {
361  double reactivePower = data.reactivePower;
362  if(!syncGenerator->IsOnline()) reactivePower = 0.0;
363  switch(m_unit) {
364  case UNIT_PU: {
365  SetText(wxString::FromDouble(reactivePower, m_decimalPlaces) + " p.u.");
366  } break;
367  case UNIT_VAr: {
368  SetText(wxString::FromDouble(reactivePower * systemPowerBase, m_decimalPlaces) +
369  " VAr");
370  } break;
371  case UNIT_kVAr: {
372  SetText(wxString::FromDouble(reactivePower * systemPowerBase / 1e3, m_decimalPlaces) +
373  " kVAr");
374  } break;
375  case UNIT_MVAr: {
376  SetText(wxString::FromDouble(reactivePower * systemPowerBase / 1e6, m_decimalPlaces) +
377  " MVAr");
378  } break;
379  default:
380  break;
381  }
382  } break;
383  case DATA_SC_CURRENT: {
384  double faultCurrent[3] = {std::abs(data.faultCurrent[0]), std::abs(data.faultCurrent[1]),
385  std::abs(data.faultCurrent[2])};
386  switch(m_unit) {
387  case UNIT_PU: {
388  wxString str =
389  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
390  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
391  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
392  SetText(str);
393  } break;
394  case UNIT_A: {
395  wxString str = "Ia = " +
396  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
397  " A";
398  str += "\nIb = " +
399  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
400  str += "\nIc = " +
401  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
402  SetText(str);
403  } break;
404  case UNIT_kA: {
405  wxString str =
406  "Ia = " +
407  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
408  str += "\nIb = " +
409  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
410  " kA";
411  str += "\nIc = " +
412  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
413  " kA";
414  SetText(str);
415  } break;
416  default:
417  break;
418  }
419  } break;
420  default:
421  break;
422  }
423  }
424  } break;
425  case TYPE_LINE: {
426  Line* line = static_cast<Line*>(m_element);
427  if(line) {
428  LineElectricalData data = line->GetElectricalData();
429  double baseVoltage = data.nominalVoltage;
430  if(data.nominalVoltageUnit == UNIT_kV) baseVoltage *= 1e3;
431  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
432  switch(m_dataType) {
433  case DATA_NAME: {
434  SetText(data.name);
435  } break;
436  case DATA_PF_ACTIVE: {
437  double activePF = std::real(data.powerFlow[m_direction]);
438  if(!line->IsOnline()) activePF = 0.0;
439  switch(m_unit) {
440  case UNIT_PU: {
441  SetText(wxString::FromDouble(activePF, m_decimalPlaces) + " p.u.");
442  } break;
443  case UNIT_W: {
444  SetText(wxString::FromDouble(activePF * systemPowerBase, m_decimalPlaces) + " W");
445  } break;
446  case UNIT_kW: {
447  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e3, m_decimalPlaces) +
448  " kW");
449  } break;
450  case UNIT_MW: {
451  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e6, m_decimalPlaces) +
452  " MW");
453  } break;
454  default:
455  break;
456  }
457  } break;
458  case DATA_PF_REACTIVE: {
459  double reactivePF = std::imag(data.powerFlow[m_direction]);
460  if(!line->IsOnline()) reactivePF = 0.0;
461  switch(m_unit) {
462  case UNIT_PU: {
463  SetText(wxString::FromDouble(reactivePF, m_decimalPlaces) + " p.u.");
464  } break;
465  case UNIT_VAr: {
466  SetText(wxString::FromDouble(reactivePF * systemPowerBase, m_decimalPlaces) + " VAr");
467  } break;
468  case UNIT_kVAr: {
469  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e3, m_decimalPlaces) +
470  " kVAr");
471  } break;
472  case UNIT_MVAr: {
473  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e6, m_decimalPlaces) +
474  " MVAr");
475  } break;
476  default:
477  break;
478  }
479  } break;
480  case DATA_PF_LOSSES: {
481  double losses = std::abs(std::real(data.powerFlow[0]) + std::real(data.powerFlow[1]));
482  if(!line->IsOnline()) losses = 0.0;
483  switch(m_unit) {
484  case UNIT_PU: {
485  SetText(wxString::FromDouble(losses, m_decimalPlaces) + " p.u.");
486  } break;
487  case UNIT_W: {
488  SetText(wxString::FromDouble(losses * systemPowerBase, m_decimalPlaces) + " W");
489  } break;
490  case UNIT_kW: {
491  SetText(wxString::FromDouble(losses * systemPowerBase / 1e3, m_decimalPlaces) + " kW");
492  } break;
493  case UNIT_MW: {
494  SetText(wxString::FromDouble(losses * systemPowerBase / 1e6, m_decimalPlaces) + " MW");
495  } break;
496  default:
497  break;
498  }
499  } break;
500  case DATA_PF_CURRENT: {
501  double current = std::abs(data.current[m_direction]);
502  if(!line->IsOnline()) current = 0.0;
503  switch(m_unit) {
504  case UNIT_PU: {
505  SetText(wxString::FromDouble(current, m_decimalPlaces) + " p.u.");
506  } break;
507  case UNIT_A: {
508  SetText(wxString::FromDouble(current * baseCurrent, m_decimalPlaces) + " A");
509  } break;
510  case UNIT_kA: {
511  SetText(wxString::FromDouble(current * baseCurrent / 1e3, m_decimalPlaces) + " kA");
512  } break;
513  default:
514  break;
515  }
516  } break;
517  case DATA_SC_CURRENT: {
518  double faultCurrent[3] = {std::abs(data.faultCurrent[m_direction][0]),
519  std::abs(data.faultCurrent[m_direction][1]),
520  std::abs(data.faultCurrent[m_direction][2])};
521  if(!line->IsOnline()) faultCurrent[0] = faultCurrent[1] = faultCurrent[2] = 0.0;
522  switch(m_unit) {
523  case UNIT_PU: {
524  wxString str =
525  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
526  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
527  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
528  SetText(str);
529  } break;
530  case UNIT_A: {
531  wxString str = "Ia = " +
532  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
533  " A";
534  str += "\nIb = " +
535  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
536  str += "\nIc = " +
537  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
538  SetText(str);
539  } break;
540  case UNIT_kA: {
541  wxString str =
542  "Ia = " +
543  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
544  str += "\nIb = " +
545  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
546  " kA";
547  str += "\nIc = " +
548  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
549  " kA";
550  SetText(str);
551  } break;
552  default:
553  break;
554  }
555  } break;
556  default:
557  break;
558  }
559  }
560  } break;
561  case TYPE_TRANSFORMER: {
562  Transformer* transformer = static_cast<Transformer*>(m_element);
563  if(transformer) {
564  TransformerElectricalData data = transformer->GetElectricalData();
565  double baseVoltage[2] = {data.primaryNominalVoltage, data.secondaryNominalVoltage};
566 
567  if(data.primaryNominalVoltageUnit == UNIT_kV) baseVoltage[0] *= 1e3;
568  if(data.secondaryNominalVoltageUnit == UNIT_kV) baseVoltage[1] *= 1e3;
569 
570  double baseCurrent[2] = {systemPowerBase / (std::sqrt(3.0) * baseVoltage[0]),
571  systemPowerBase / (std::sqrt(3.0) * baseVoltage[1])};
572  switch(m_dataType) {
573  case DATA_NAME: {
574  SetText(data.name);
575  } break;
576  case DATA_PF_ACTIVE: {
577  double activePF = std::real(data.powerFlow[m_direction]);
578  if(!transformer->IsOnline()) activePF = 0.0;
579  switch(m_unit) {
580  case UNIT_PU: {
581  SetText(wxString::FromDouble(activePF, m_decimalPlaces) + " p.u.");
582  } break;
583  case UNIT_W: {
584  SetText(wxString::FromDouble(activePF * systemPowerBase, m_decimalPlaces) + " W");
585  } break;
586  case UNIT_kW: {
587  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e3, m_decimalPlaces) +
588  " kW");
589  } break;
590  case UNIT_MW: {
591  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e6, m_decimalPlaces) +
592  " MW");
593  } break;
594  default:
595  break;
596  }
597  } break;
598  case DATA_PF_REACTIVE: {
599  double reactivePF = std::imag(data.powerFlow[m_direction]);
600  if(!transformer->IsOnline()) reactivePF = 0.0;
601  switch(m_unit) {
602  case UNIT_PU: {
603  SetText(wxString::FromDouble(reactivePF, m_decimalPlaces) + " p.u.");
604  } break;
605  case UNIT_VAr: {
606  SetText(wxString::FromDouble(reactivePF * systemPowerBase, m_decimalPlaces) + " VAr");
607  } break;
608  case UNIT_kVAr: {
609  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e3, m_decimalPlaces) +
610  " kVAr");
611  } break;
612  case UNIT_MVAr: {
613  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e6, m_decimalPlaces) +
614  " MVAr");
615  } break;
616  default:
617  break;
618  }
619  } break;
620  case DATA_PF_LOSSES: {
621  double losses = std::abs(std::real(data.powerFlow[0]) + std::real(data.powerFlow[1]));
622  if(!transformer->IsOnline()) losses = 0.0;
623  switch(m_unit) {
624  case UNIT_PU: {
625  SetText(wxString::FromDouble(losses, m_decimalPlaces) + " p.u.");
626  } break;
627  case UNIT_W: {
628  SetText(wxString::FromDouble(losses * systemPowerBase, m_decimalPlaces) + " W");
629  } break;
630  case UNIT_kW: {
631  SetText(wxString::FromDouble(losses * systemPowerBase / 1e3, m_decimalPlaces) + " kW");
632  } break;
633  case UNIT_MW: {
634  SetText(wxString::FromDouble(losses * systemPowerBase / 1e6, m_decimalPlaces) + " MW");
635  } break;
636  default:
637  break;
638  }
639  } break;
640  case DATA_PF_CURRENT: {
641  double current = std::abs(data.current[m_direction]);
642  if(!transformer->IsOnline()) current = 0.0;
643  switch(m_unit) {
644  case UNIT_PU: {
645  SetText(wxString::FromDouble(current, m_decimalPlaces) + " p.u.");
646  } break;
647  case UNIT_A: {
648  SetText(wxString::FromDouble(current * baseCurrent[m_direction], m_decimalPlaces) +
649  " A");
650  } break;
651  case UNIT_kA: {
652  SetText(
653  wxString::FromDouble(current * baseCurrent[m_direction] / 1e3, m_decimalPlaces) +
654  " kA");
655  } break;
656  default:
657  break;
658  }
659  } break;
660  case DATA_SC_CURRENT: {
661  double faultCurrent[3] = {std::abs(data.faultCurrent[m_direction][0]),
662  std::abs(data.faultCurrent[m_direction][1]),
663  std::abs(data.faultCurrent[m_direction][2])};
664  if(!transformer->IsOnline()) faultCurrent[0] = faultCurrent[1] = faultCurrent[2] = 0.0;
665  switch(m_unit) {
666  case UNIT_PU: {
667  wxString str =
668  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
669  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
670  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
671  SetText(str);
672  } break;
673  case UNIT_A: {
674  wxString str =
675  "Ia = " +
676  wxString::FromDouble(faultCurrent[0] * baseCurrent[m_direction], m_decimalPlaces) +
677  " A";
678  str += "\nIb = " + wxString::FromDouble(faultCurrent[1] * baseCurrent[m_direction],
679  m_decimalPlaces) +
680  " A";
681  str += "\nIc = " + wxString::FromDouble(faultCurrent[2] * baseCurrent[m_direction],
682  m_decimalPlaces) +
683  " A";
684  SetText(str);
685  } break;
686  case UNIT_kA: {
687  wxString str = "Ia = " +
688  wxString::FromDouble(faultCurrent[0] * baseCurrent[m_direction] / 1e3,
689  m_decimalPlaces) +
690  " kA";
691  str += "\nIb = " +
692  wxString::FromDouble(faultCurrent[1] * baseCurrent[m_direction] / 1e3,
693  m_decimalPlaces) +
694  " kA";
695  str += "\nIc = " +
696  wxString::FromDouble(faultCurrent[2] * baseCurrent[m_direction] / 1e3,
697  m_decimalPlaces) +
698  " kA";
699  SetText(str);
700  } break;
701  default:
702  break;
703  }
704  } break;
705  default:
706  break;
707  }
708  }
709  } break;
710  case TYPE_LOAD: {
711  Load* load = static_cast<Load*>(m_element);
712  if(load) {
713  LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
714  std::complex<double> sPower(data.activePower, data.reactivePower);
715  if(data.loadType == CONST_IMPEDANCE && load->IsOnline()) {
716  std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
717  sPower = std::pow(std::abs(v), 2) * sPower;
718  }
719  if(!load->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
720  switch(m_dataType) {
721  case DATA_NAME: {
722  SetText(data.name);
723  } break;
724  case DATA_ACTIVE_POWER: {
725  switch(m_unit) {
726  case UNIT_PU: {
727  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
728  }
729  case UNIT_W: {
730  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
731  }
732  case UNIT_kW: {
733  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
734  " kW");
735  }
736  case UNIT_MW: {
737  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
738  " MW");
739  }
740  default:
741  break;
742  }
743  } break;
744  case DATA_REACTIVE_POWER: {
745  switch(m_unit) {
746  case UNIT_PU: {
747  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
748  }
749  case UNIT_VAr: {
750  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
751  " VAr");
752  }
753  case UNIT_kVAr: {
754  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
755  " kVAr");
756  }
757  case UNIT_MVAr: {
758  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
759  " MVAr");
760  }
761  default:
762  break;
763  }
764  } break;
765  default:
766  break;
767  }
768  }
769  } break;
770  case TYPE_SYNC_MOTOR: {
771  SyncMotor* syncMotor = static_cast<SyncMotor*>(m_element);
772  if(syncMotor) {
773  SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
774  std::complex<double> sPower(data.activePower, data.reactivePower);
775  if(!syncMotor->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
776  switch(m_dataType) {
777  case DATA_NAME: {
778  SetText(data.name);
779  } break;
780  case DATA_ACTIVE_POWER: {
781  switch(m_unit) {
782  case UNIT_PU: {
783  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
784  }
785  case UNIT_W: {
786  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
787  }
788  case UNIT_kW: {
789  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
790  " kW");
791  }
792  case UNIT_MW: {
793  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
794  " MW");
795  }
796  default:
797  break;
798  }
799  } break;
800  case DATA_REACTIVE_POWER: {
801  switch(m_unit) {
802  case UNIT_PU: {
803  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
804  }
805  case UNIT_VAr: {
806  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
807  " VAr");
808  }
809  case UNIT_kVAr: {
810  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
811  " kVAr");
812  }
813  case UNIT_MVAr: {
814  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
815  " MVAr");
816  }
817  default:
818  break;
819  }
820  } break;
821  default:
822  break;
823  }
824  }
825  } break;
826  case TYPE_IND_MOTOR: {
827  IndMotor* indMotor = static_cast<IndMotor*>(m_element);
828  if(indMotor) {
829  IndMotorElectricalData data = indMotor->GetPUElectricalData(systemPowerBase);
830  std::complex<double> sPower(data.activePower, data.reactivePower);
831  if(!indMotor->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
832  switch(m_dataType) {
833  case DATA_NAME: {
834  SetText(data.name);
835  } break;
836  case DATA_ACTIVE_POWER: {
837  switch(m_unit) {
838  case UNIT_PU: {
839  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
840  }
841  case UNIT_W: {
842  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
843  }
844  case UNIT_kW: {
845  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
846  " kW");
847  }
848  case UNIT_MW: {
849  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
850  " MW");
851  }
852  default:
853  break;
854  }
855  } break;
856  case DATA_REACTIVE_POWER: {
857  switch(m_unit) {
858  case UNIT_PU: {
859  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
860  }
861  case UNIT_VAr: {
862  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
863  " VAr");
864  }
865  case UNIT_kVAr: {
866  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
867  " kVAr");
868  }
869  case UNIT_MVAr: {
870  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
871  " MVAr");
872  }
873  default:
874  break;
875  }
876  } break;
877  default:
878  break;
879  }
880  }
881  } break;
882  case TYPE_CAPACITOR: {
883  Capacitor* capacitor = static_cast<Capacitor*>(m_element);
884  if(capacitor) {
885  CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
886  double reativePower = data.reactivePower;
887  if(!capacitor->IsOnline())
888  reativePower = 0.0;
889  else {
890  std::complex<double> v =
891  static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().voltage;
892  reativePower *= std::pow(std::abs(v), 2);
893  }
894  switch(m_dataType) {
895  case DATA_NAME: {
896  SetText(data.name);
897  } break;
898  case DATA_REACTIVE_POWER: {
899  switch(m_unit) {
900  case UNIT_PU: {
901  SetText(wxString::FromDouble(reativePower, m_decimalPlaces) + " p.u.");
902  }
903  case UNIT_VAr: {
904  SetText(wxString::FromDouble(reativePower * systemPowerBase, m_decimalPlaces) + " VAr");
905  }
906  case UNIT_kVAr: {
907  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e3, m_decimalPlaces) +
908  " kVAr");
909  }
910  case UNIT_MVAr: {
911  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e6, m_decimalPlaces) +
912  " MVAr");
913  }
914  default:
915  break;
916  }
917  } break;
918  default:
919  break;
920  }
921  }
922  } break;
923  case TYPE_INDUCTOR: {
924  Inductor* inductor = static_cast<Inductor*>(m_element);
925  if(inductor) {
926  InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
927  double reativePower = data.reactivePower;
928  if(!inductor->IsOnline())
929  reativePower = 0.0;
930  else {
931  std::complex<double> v =
932  static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().voltage;
933  reativePower *= std::pow(std::abs(v), 2);
934  }
935  switch(m_dataType) {
936  case DATA_NAME: {
937  SetText(data.name);
938  } break;
939  case DATA_REACTIVE_POWER: {
940  switch(m_unit) {
941  case UNIT_PU: {
942  SetText(wxString::FromDouble(reativePower, m_decimalPlaces) + " p.u.");
943  }
944  case UNIT_VAr: {
945  SetText(wxString::FromDouble(reativePower * systemPowerBase, m_decimalPlaces) + " VAr");
946  }
947  case UNIT_kVAr: {
948  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e3, m_decimalPlaces) +
949  " kVAr");
950  }
951  case UNIT_MVAr: {
952  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e6, m_decimalPlaces) +
953  " MVAr");
954  }
955  default:
956  break;
957  }
958  } break;
959  default:
960  break;
961  }
962  }
963  } break;
964  }
965 }
966 
968 {
969  Text* copy = new Text();
970  *copy = *this;
971  // The pointers to wxGLString must be different or can cause crashes.
972  copy->m_glString = NULL;
973  copy->m_glStringArray = NULL;
974  copy->SetText(copy->m_text);
975  return copy;
976 }
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
-
Definition: Text.h:65
- +
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TextForm.h"
19 #include "Text.h"
20 
21 #ifdef USING_WX_3_0_X
22 #include "DegreesAndRadians.h"
23 #endif
24 #include "ElectricCalculation.h"
25 #include "Bus.h"
26 #include "Line.h"
27 #include "Transformer.h"
28 #include "SyncGenerator.h"
29 #include "IndMotor.h"
30 #include "SyncMotor.h"
31 #include "Load.h"
32 #include "Inductor.h"
33 #include "Capacitor.h"
34 
35 Text::Text() : GraphicalElement() { SetText(m_text); }
36 Text::Text(wxPoint2DDouble position) : GraphicalElement()
37 {
38  m_position = position;
39  SetText(m_text);
40 }
41 
42 Text::~Text()
43 {
44  if(m_glString) delete m_glString;
45  if(m_glStringArray) delete m_glStringArray;
46 }
47 bool Text::Contains(wxPoint2DDouble position) const
48 {
49  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
50  return m_rect.Contains(ptR);
51 }
52 
53 void Text::Draw(wxPoint2DDouble translation, double scale)
54 {
55  wxScreenDC dc;
56 
57  // Draw selection rectangle
58 
59  // Push the current matrix on stack.
60  glPushMatrix();
61  // Rotate the matrix around the object position.
62  glTranslated(m_position.m_x, m_position.m_y, 0.0);
63  glRotated(m_angle, 0.0, 0.0, 1.0);
64  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
65 
66  if(m_selected) {
67  glColor4d(0.0, 0.5, 1.0, 0.5);
68  DrawRectangle(m_position + wxPoint2DDouble(m_borderSize / 2.0, m_borderSize / 2.0), m_rect.m_width,
69  m_rect.m_height);
70  }
71 
72  // Draw text (layer 2)
73  glEnable(GL_TEXTURE_2D);
74  glColor4d(0.0, 0.0, 0.0, 1.0);
75  if(!m_isMultlineText) { // Only one line
76  m_glString->bind();
77  m_glString->render(m_position.m_x, m_position.m_y);
78  } else { // Multiples lines
79  m_glStringArray->bind();
80  // The text will be printed centralized.
81  double lineHeight = m_height / (double)m_numberOfLines;
82  for(int i = 0; i < m_numberOfLines; i++) {
83  m_glStringArray->get(i)
84  .render(m_position.m_x, m_position.m_y - m_height / 2.0 + lineHeight / 2.0 + lineHeight * double(i));
85  }
86  }
87  glDisable(GL_TEXTURE_2D);
88 
89  glPopMatrix();
90 }
91 
92 bool Text::Intersects(wxRect2DDouble rect) const
93 {
94  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
95  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
96 }
97 
98 void Text::SetText(wxString text)
99 {
100  glEnable(GL_TEXTURE_2D);
101  m_text = text;
102  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
103 
104  wxScreenDC dc;
105  GLuint* idString = NULL;
106  GLuint* idStringArray = NULL;
107 
108  if(m_glString) {
109  delete m_glString;
110  m_glString = NULL;
111 
112  idString = new GLuint;
113  glGenTextures(1, idString);
114  }
115  if(m_glStringArray) {
116  delete m_glStringArray;
117  m_glStringArray = NULL;
118 
119  idStringArray = new GLuint;
120  glGenTextures(1, idStringArray);
121  }
122 
123  m_numberOfLines = m_text.Freq('\n') + 1;
124  if(m_numberOfLines == 1) { // Only one line
125  m_isMultlineText = false;
126  m_glString = new wxGLString(m_text);
127  m_glString->setFont(font);
128  m_glString->consolidate(&dc);
129  m_width = m_glString->getWidth();
130  m_height = m_glString->getheight();
131  } else {
132  m_isMultlineText = true;
133  m_glStringArray = new wxGLStringArray();
134  dc.SetFont(font);
135 
136  m_width = 0.0;
137  m_height = 0.0;
138  wxString multText = m_text;
139  for(int i = 0; i < m_numberOfLines; ++i) {
140  wxString nextLine;
141  wxString currentLine = multText.BeforeFirst('\n', &nextLine);
142  multText = nextLine;
143  m_glStringArray->addString(currentLine);
144 
145  wxSize size = dc.GetTextExtent(currentLine);
146  if(size.GetWidth() > m_width) m_width = size.GetWidth();
147  m_height += size.GetHeight();
148  }
149 
150  m_glStringArray->setFont(font);
151  m_glStringArray->consolidate(&dc);
152  }
153 
154  if(idString) glDeleteTextures(1, idString);
155  if(idStringArray) glDeleteTextures(1, idStringArray);
156 
157  // Update text rectangle.
158  SetPosition(m_position);
159  glDisable(GL_TEXTURE_2D);
160 }
161 
162 void Text::Rotate(bool clockwise)
163 {
164  double rotAngle = m_rotationAngle;
165  if(!clockwise) rotAngle = -m_rotationAngle;
166 
167  m_angle += rotAngle;
168  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
169 }
170 
171 bool Text::ShowForm(wxWindow* parent, std::vector<Element*> elementList)
172 {
173  TextForm* textForm = new TextForm(parent, this, elementList);
174  if(textForm->ShowModal() == wxID_OK) {
175  textForm->Destroy();
176  return true;
177  }
178  textForm->Destroy();
179  return false;
180 }
181 
182 void Text::UpdateText(double systemPowerBase)
183 {
184  switch(m_elementType) {
185  case TYPE_NONE:
186  SetText(m_text);
187  break;
188  case TYPE_BUS: {
189  Bus* bus = static_cast<Bus*>(m_element);
190  if(bus) {
191  BusElectricalData data = bus->GetElectricalData();
192  double baseVoltage = data.nominalVoltage;
193  if(data.nominalVoltageUnit == UNIT_kV) baseVoltage *= 1e3;
194  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
195 
196  switch(m_dataType) {
197  case DATA_NAME: {
198  SetText(bus->GetElectricalData().name);
199  } break;
200  case DATA_VOLTAGE: {
201  double voltage = std::abs(data.voltage);
202  switch(m_unit) {
203  case UNIT_PU: {
204  SetText(wxString::FromDouble(voltage, m_decimalPlaces) + " p.u.");
205  } break;
206  case UNIT_V: {
207  SetText(wxString::FromDouble(voltage * baseVoltage, m_decimalPlaces) + " V");
208  } break;
209  case UNIT_kV: {
210  SetText(wxString::FromDouble(voltage * baseVoltage / 1e3, m_decimalPlaces) + " kV");
211  } break;
212  default:
213  break;
214  }
215  } break;
216  case DATA_ANGLE: {
217  double angle = std::arg(data.voltage);
218  switch(m_unit) {
219  case UNIT_RADIAN: {
220  SetText(wxString::FromDouble(angle, m_decimalPlaces) + " rad");
221  } break;
222  case UNIT_DEGREE: {
223  SetText(wxString::FromDouble(wxRadToDeg(angle), m_decimalPlaces) + (wxString)L'\u00B0');
224  } break;
225  default:
226  break;
227  }
228  } break;
229  case DATA_SC_CURRENT: {
230  double faultCurrent[3] = {std::abs(data.faultCurrent[0]), std::abs(data.faultCurrent[1]),
231  std::abs(data.faultCurrent[2])};
232  switch(m_unit) {
233  case UNIT_PU: {
234  wxString str =
235  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
236  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
237  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
238  SetText(str);
239  } break;
240  case UNIT_A: {
241  wxString str = "Ia = " +
242  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
243  " A";
244  str += "\nIb = " +
245  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
246  str += "\nIc = " +
247  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
248  SetText(str);
249  } break;
250  case UNIT_kA: {
251  wxString str =
252  "Ia = " +
253  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
254  str += "\nIb = " +
255  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
256  " kA";
257  str += "\nIc = " +
258  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
259  " kA";
260  SetText(str);
261  } break;
262  default:
263  break;
264  }
265  } break;
266  case DATA_SC_VOLTAGE: {
267  double faultVoltage[3] = {std::abs(data.faultVoltage[0]), std::abs(data.faultVoltage[1]),
268  std::abs(data.faultVoltage[2])};
269  switch(m_unit) {
270  case UNIT_PU: {
271  wxString str =
272  "Va = " + wxString::FromDouble(faultVoltage[0], m_decimalPlaces) + " p.u.";
273  str += "\nVb = " + wxString::FromDouble(faultVoltage[1], m_decimalPlaces) + " p.u.";
274  str += "\nVc = " + wxString::FromDouble(faultVoltage[2], m_decimalPlaces) + " p.u.";
275  SetText(str);
276  } break;
277  case UNIT_V: {
278  wxString str = "Va = " +
279  wxString::FromDouble(faultVoltage[0] * baseVoltage, m_decimalPlaces) +
280  " V";
281  str += "\nVb = " +
282  wxString::FromDouble(faultVoltage[1] * baseVoltage, m_decimalPlaces) + " V";
283  str += "\nVc = " +
284  wxString::FromDouble(faultVoltage[2] * baseVoltage, m_decimalPlaces) + " V";
285  SetText(str);
286  } break;
287  case UNIT_kV: {
288  wxString str =
289  "Va = " +
290  wxString::FromDouble(faultVoltage[0] * baseVoltage / 1e3, m_decimalPlaces) + " kV";
291  str += "\nVb = " +
292  wxString::FromDouble(faultVoltage[1] * baseVoltage / 1e3, m_decimalPlaces) +
293  " kV";
294  str += "\nVc = " +
295  wxString::FromDouble(faultVoltage[2] * baseVoltage / 1e3, m_decimalPlaces) +
296  " kV";
297  SetText(str);
298  } break;
299  default:
300  break;
301  }
302  } break;
303  case DATA_SC_POWER: {
304  switch(m_unit) {
305  case UNIT_PU: {
306  SetText(wxString::FromDouble(data.scPower, m_decimalPlaces) + " p.u.");
307  } break;
308  case UNIT_VA: {
309  SetText(wxString::FromDouble(data.scPower * systemPowerBase, m_decimalPlaces) + " VA");
310  } break;
311  case UNIT_kVA: {
312  SetText(wxString::FromDouble(data.scPower * systemPowerBase / 1e3, m_decimalPlaces) +
313  " kVA");
314  } break;
315  case UNIT_MVA: {
316  SetText(wxString::FromDouble(data.scPower * systemPowerBase / 1e6, m_decimalPlaces) +
317  " MVA");
318  } break;
319  default:
320  break;
321  }
322  } break;
323  default:
324  break;
325  }
326  }
327  } break;
328  case TYPE_SYNC_GENERATOR: {
329  SyncGenerator* syncGenerator = static_cast<SyncGenerator*>(m_element);
330  if(syncGenerator) {
331  SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
332  double baseVoltage = syncGenerator->GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
333  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
334  switch(m_dataType) {
335  case DATA_NAME: {
336  SetText(data.name);
337  } break;
338  case DATA_ACTIVE_POWER: {
339  double activePower = data.activePower;
340  if(!syncGenerator->IsOnline()) activePower = 0.0;
341  switch(m_unit) {
342  case UNIT_PU: {
343  SetText(wxString::FromDouble(activePower, m_decimalPlaces) + " p.u.");
344  } break;
345  case UNIT_W: {
346  SetText(wxString::FromDouble(activePower * systemPowerBase, m_decimalPlaces) + " W");
347  } break;
348  case UNIT_kW: {
349  SetText(wxString::FromDouble(activePower * systemPowerBase / 1e3, m_decimalPlaces) +
350  " kW");
351  } break;
352  case UNIT_MW: {
353  SetText(wxString::FromDouble(activePower * systemPowerBase / 1e6, m_decimalPlaces) +
354  " MW");
355  } break;
356  default:
357  break;
358  }
359  } break;
360  case DATA_REACTIVE_POWER: {
361  double reactivePower = data.reactivePower;
362  if(!syncGenerator->IsOnline()) reactivePower = 0.0;
363  switch(m_unit) {
364  case UNIT_PU: {
365  SetText(wxString::FromDouble(reactivePower, m_decimalPlaces) + " p.u.");
366  } break;
367  case UNIT_VAr: {
368  SetText(wxString::FromDouble(reactivePower * systemPowerBase, m_decimalPlaces) +
369  " VAr");
370  } break;
371  case UNIT_kVAr: {
372  SetText(wxString::FromDouble(reactivePower * systemPowerBase / 1e3, m_decimalPlaces) +
373  " kVAr");
374  } break;
375  case UNIT_MVAr: {
376  SetText(wxString::FromDouble(reactivePower * systemPowerBase / 1e6, m_decimalPlaces) +
377  " MVAr");
378  } break;
379  default:
380  break;
381  }
382  } break;
383  case DATA_SC_CURRENT: {
384  double faultCurrent[3] = {std::abs(data.faultCurrent[0]), std::abs(data.faultCurrent[1]),
385  std::abs(data.faultCurrent[2])};
386  switch(m_unit) {
387  case UNIT_PU: {
388  wxString str =
389  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
390  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
391  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
392  SetText(str);
393  } break;
394  case UNIT_A: {
395  wxString str = "Ia = " +
396  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
397  " A";
398  str += "\nIb = " +
399  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
400  str += "\nIc = " +
401  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
402  SetText(str);
403  } break;
404  case UNIT_kA: {
405  wxString str =
406  "Ia = " +
407  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
408  str += "\nIb = " +
409  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
410  " kA";
411  str += "\nIc = " +
412  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
413  " kA";
414  SetText(str);
415  } break;
416  default:
417  break;
418  }
419  } break;
420  default:
421  break;
422  }
423  }
424  } break;
425  case TYPE_LINE: {
426  Line* line = static_cast<Line*>(m_element);
427  if(line) {
428  LineElectricalData data = line->GetElectricalData();
429  double baseVoltage = data.nominalVoltage;
430  if(data.nominalVoltageUnit == UNIT_kV) baseVoltage *= 1e3;
431  double baseCurrent = systemPowerBase / (std::sqrt(3.0) * baseVoltage);
432  switch(m_dataType) {
433  case DATA_NAME: {
434  SetText(data.name);
435  } break;
436  case DATA_PF_ACTIVE: {
437  double activePF = std::real(data.powerFlow[m_direction]);
438  if(!line->IsOnline()) activePF = 0.0;
439  switch(m_unit) {
440  case UNIT_PU: {
441  SetText(wxString::FromDouble(activePF, m_decimalPlaces) + " p.u.");
442  } break;
443  case UNIT_W: {
444  SetText(wxString::FromDouble(activePF * systemPowerBase, m_decimalPlaces) + " W");
445  } break;
446  case UNIT_kW: {
447  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e3, m_decimalPlaces) +
448  " kW");
449  } break;
450  case UNIT_MW: {
451  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e6, m_decimalPlaces) +
452  " MW");
453  } break;
454  default:
455  break;
456  }
457  } break;
458  case DATA_PF_REACTIVE: {
459  double reactivePF = std::imag(data.powerFlow[m_direction]);
460  if(!line->IsOnline()) reactivePF = 0.0;
461  switch(m_unit) {
462  case UNIT_PU: {
463  SetText(wxString::FromDouble(reactivePF, m_decimalPlaces) + " p.u.");
464  } break;
465  case UNIT_VAr: {
466  SetText(wxString::FromDouble(reactivePF * systemPowerBase, m_decimalPlaces) + " VAr");
467  } break;
468  case UNIT_kVAr: {
469  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e3, m_decimalPlaces) +
470  " kVAr");
471  } break;
472  case UNIT_MVAr: {
473  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e6, m_decimalPlaces) +
474  " MVAr");
475  } break;
476  default:
477  break;
478  }
479  } break;
480  case DATA_PF_LOSSES: {
481  double losses = std::abs(std::real(data.powerFlow[0]) + std::real(data.powerFlow[1]));
482  if(!line->IsOnline()) losses = 0.0;
483  switch(m_unit) {
484  case UNIT_PU: {
485  SetText(wxString::FromDouble(losses, m_decimalPlaces) + " p.u.");
486  } break;
487  case UNIT_W: {
488  SetText(wxString::FromDouble(losses * systemPowerBase, m_decimalPlaces) + " W");
489  } break;
490  case UNIT_kW: {
491  SetText(wxString::FromDouble(losses * systemPowerBase / 1e3, m_decimalPlaces) + " kW");
492  } break;
493  case UNIT_MW: {
494  SetText(wxString::FromDouble(losses * systemPowerBase / 1e6, m_decimalPlaces) + " MW");
495  } break;
496  default:
497  break;
498  }
499  } break;
500  case DATA_PF_CURRENT: {
501  double current = std::abs(data.current[m_direction]);
502  if(!line->IsOnline()) current = 0.0;
503  switch(m_unit) {
504  case UNIT_PU: {
505  SetText(wxString::FromDouble(current, m_decimalPlaces) + " p.u.");
506  } break;
507  case UNIT_A: {
508  SetText(wxString::FromDouble(current * baseCurrent, m_decimalPlaces) + " A");
509  } break;
510  case UNIT_kA: {
511  SetText(wxString::FromDouble(current * baseCurrent / 1e3, m_decimalPlaces) + " kA");
512  } break;
513  default:
514  break;
515  }
516  } break;
517  case DATA_SC_CURRENT: {
518  double faultCurrent[3] = {std::abs(data.faultCurrent[m_direction][0]),
519  std::abs(data.faultCurrent[m_direction][1]),
520  std::abs(data.faultCurrent[m_direction][2])};
521  if(!line->IsOnline()) faultCurrent[0] = faultCurrent[1] = faultCurrent[2] = 0.0;
522  switch(m_unit) {
523  case UNIT_PU: {
524  wxString str =
525  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
526  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
527  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
528  SetText(str);
529  } break;
530  case UNIT_A: {
531  wxString str = "Ia = " +
532  wxString::FromDouble(faultCurrent[0] * baseCurrent, m_decimalPlaces) +
533  " A";
534  str += "\nIb = " +
535  wxString::FromDouble(faultCurrent[1] * baseCurrent, m_decimalPlaces) + " A";
536  str += "\nIc = " +
537  wxString::FromDouble(faultCurrent[2] * baseCurrent, m_decimalPlaces) + " A";
538  SetText(str);
539  } break;
540  case UNIT_kA: {
541  wxString str =
542  "Ia = " +
543  wxString::FromDouble(faultCurrent[0] * baseCurrent / 1e3, m_decimalPlaces) + " kA";
544  str += "\nIb = " +
545  wxString::FromDouble(faultCurrent[1] * baseCurrent / 1e3, m_decimalPlaces) +
546  " kA";
547  str += "\nIc = " +
548  wxString::FromDouble(faultCurrent[2] * baseCurrent / 1e3, m_decimalPlaces) +
549  " kA";
550  SetText(str);
551  } break;
552  default:
553  break;
554  }
555  } break;
556  default:
557  break;
558  }
559  }
560  } break;
561  case TYPE_TRANSFORMER: {
562  Transformer* transformer = static_cast<Transformer*>(m_element);
563  if(transformer) {
564  TransformerElectricalData data = transformer->GetElectricalData();
565  double baseVoltage[2] = {data.primaryNominalVoltage, data.secondaryNominalVoltage};
566 
567  if(data.primaryNominalVoltageUnit == UNIT_kV) baseVoltage[0] *= 1e3;
568  if(data.secondaryNominalVoltageUnit == UNIT_kV) baseVoltage[1] *= 1e3;
569 
570  double baseCurrent[2] = {systemPowerBase / (std::sqrt(3.0) * baseVoltage[0]),
571  systemPowerBase / (std::sqrt(3.0) * baseVoltage[1])};
572  switch(m_dataType) {
573  case DATA_NAME: {
574  SetText(data.name);
575  } break;
576  case DATA_PF_ACTIVE: {
577  double activePF = std::real(data.powerFlow[m_direction]);
578  if(!transformer->IsOnline()) activePF = 0.0;
579  switch(m_unit) {
580  case UNIT_PU: {
581  SetText(wxString::FromDouble(activePF, m_decimalPlaces) + " p.u.");
582  } break;
583  case UNIT_W: {
584  SetText(wxString::FromDouble(activePF * systemPowerBase, m_decimalPlaces) + " W");
585  } break;
586  case UNIT_kW: {
587  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e3, m_decimalPlaces) +
588  " kW");
589  } break;
590  case UNIT_MW: {
591  SetText(wxString::FromDouble(activePF * systemPowerBase / 1e6, m_decimalPlaces) +
592  " MW");
593  } break;
594  default:
595  break;
596  }
597  } break;
598  case DATA_PF_REACTIVE: {
599  double reactivePF = std::imag(data.powerFlow[m_direction]);
600  if(!transformer->IsOnline()) reactivePF = 0.0;
601  switch(m_unit) {
602  case UNIT_PU: {
603  SetText(wxString::FromDouble(reactivePF, m_decimalPlaces) + " p.u.");
604  } break;
605  case UNIT_VAr: {
606  SetText(wxString::FromDouble(reactivePF * systemPowerBase, m_decimalPlaces) + " VAr");
607  } break;
608  case UNIT_kVAr: {
609  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e3, m_decimalPlaces) +
610  " kVAr");
611  } break;
612  case UNIT_MVAr: {
613  SetText(wxString::FromDouble(reactivePF * systemPowerBase / 1e6, m_decimalPlaces) +
614  " MVAr");
615  } break;
616  default:
617  break;
618  }
619  } break;
620  case DATA_PF_LOSSES: {
621  double losses = std::abs(std::real(data.powerFlow[0]) + std::real(data.powerFlow[1]));
622  if(!transformer->IsOnline()) losses = 0.0;
623  switch(m_unit) {
624  case UNIT_PU: {
625  SetText(wxString::FromDouble(losses, m_decimalPlaces) + " p.u.");
626  } break;
627  case UNIT_W: {
628  SetText(wxString::FromDouble(losses * systemPowerBase, m_decimalPlaces) + " W");
629  } break;
630  case UNIT_kW: {
631  SetText(wxString::FromDouble(losses * systemPowerBase / 1e3, m_decimalPlaces) + " kW");
632  } break;
633  case UNIT_MW: {
634  SetText(wxString::FromDouble(losses * systemPowerBase / 1e6, m_decimalPlaces) + " MW");
635  } break;
636  default:
637  break;
638  }
639  } break;
640  case DATA_PF_CURRENT: {
641  double current = std::abs(data.current[m_direction]);
642  if(!transformer->IsOnline()) current = 0.0;
643  switch(m_unit) {
644  case UNIT_PU: {
645  SetText(wxString::FromDouble(current, m_decimalPlaces) + " p.u.");
646  } break;
647  case UNIT_A: {
648  SetText(wxString::FromDouble(current * baseCurrent[m_direction], m_decimalPlaces) +
649  " A");
650  } break;
651  case UNIT_kA: {
652  SetText(
653  wxString::FromDouble(current * baseCurrent[m_direction] / 1e3, m_decimalPlaces) +
654  " kA");
655  } break;
656  default:
657  break;
658  }
659  } break;
660  case DATA_SC_CURRENT: {
661  double faultCurrent[3] = {std::abs(data.faultCurrent[m_direction][0]),
662  std::abs(data.faultCurrent[m_direction][1]),
663  std::abs(data.faultCurrent[m_direction][2])};
664  if(!transformer->IsOnline()) faultCurrent[0] = faultCurrent[1] = faultCurrent[2] = 0.0;
665  switch(m_unit) {
666  case UNIT_PU: {
667  wxString str =
668  "Ia = " + wxString::FromDouble(faultCurrent[0], m_decimalPlaces) + " p.u.";
669  str += "\nIb = " + wxString::FromDouble(faultCurrent[1], m_decimalPlaces) + " p.u.";
670  str += "\nIc = " + wxString::FromDouble(faultCurrent[2], m_decimalPlaces) + " p.u.";
671  SetText(str);
672  } break;
673  case UNIT_A: {
674  wxString str =
675  "Ia = " +
676  wxString::FromDouble(faultCurrent[0] * baseCurrent[m_direction], m_decimalPlaces) +
677  " A";
678  str += "\nIb = " + wxString::FromDouble(faultCurrent[1] * baseCurrent[m_direction],
679  m_decimalPlaces) +
680  " A";
681  str += "\nIc = " + wxString::FromDouble(faultCurrent[2] * baseCurrent[m_direction],
682  m_decimalPlaces) +
683  " A";
684  SetText(str);
685  } break;
686  case UNIT_kA: {
687  wxString str = "Ia = " +
688  wxString::FromDouble(faultCurrent[0] * baseCurrent[m_direction] / 1e3,
689  m_decimalPlaces) +
690  " kA";
691  str += "\nIb = " +
692  wxString::FromDouble(faultCurrent[1] * baseCurrent[m_direction] / 1e3,
693  m_decimalPlaces) +
694  " kA";
695  str += "\nIc = " +
696  wxString::FromDouble(faultCurrent[2] * baseCurrent[m_direction] / 1e3,
697  m_decimalPlaces) +
698  " kA";
699  SetText(str);
700  } break;
701  default:
702  break;
703  }
704  } break;
705  default:
706  break;
707  }
708  }
709  } break;
710  case TYPE_LOAD: {
711  Load* load = static_cast<Load*>(m_element);
712  if(load) {
713  LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
714  std::complex<double> sPower(data.activePower, data.reactivePower);
715  if(data.loadType == CONST_IMPEDANCE && load->IsOnline()) {
716  std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
717  sPower = std::pow(std::abs(v), 2) * sPower;
718  }
719  if(!load->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
720  switch(m_dataType) {
721  case DATA_NAME: {
722  SetText(data.name);
723  } break;
724  case DATA_ACTIVE_POWER: {
725  switch(m_unit) {
726  case UNIT_PU: {
727  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
728  }
729  case UNIT_W: {
730  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
731  }
732  case UNIT_kW: {
733  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
734  " kW");
735  }
736  case UNIT_MW: {
737  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
738  " MW");
739  }
740  default:
741  break;
742  }
743  } break;
744  case DATA_REACTIVE_POWER: {
745  switch(m_unit) {
746  case UNIT_PU: {
747  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
748  }
749  case UNIT_VAr: {
750  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
751  " VAr");
752  }
753  case UNIT_kVAr: {
754  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
755  " kVAr");
756  }
757  case UNIT_MVAr: {
758  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
759  " MVAr");
760  }
761  default:
762  break;
763  }
764  } break;
765  default:
766  break;
767  }
768  }
769  } break;
770  case TYPE_SYNC_MOTOR: {
771  SyncMotor* syncMotor = static_cast<SyncMotor*>(m_element);
772  if(syncMotor) {
773  SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
774  std::complex<double> sPower(data.activePower, data.reactivePower);
775  if(!syncMotor->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
776  switch(m_dataType) {
777  case DATA_NAME: {
778  SetText(data.name);
779  } break;
780  case DATA_ACTIVE_POWER: {
781  switch(m_unit) {
782  case UNIT_PU: {
783  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
784  }
785  case UNIT_W: {
786  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
787  }
788  case UNIT_kW: {
789  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
790  " kW");
791  }
792  case UNIT_MW: {
793  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
794  " MW");
795  }
796  default:
797  break;
798  }
799  } break;
800  case DATA_REACTIVE_POWER: {
801  switch(m_unit) {
802  case UNIT_PU: {
803  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
804  }
805  case UNIT_VAr: {
806  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
807  " VAr");
808  }
809  case UNIT_kVAr: {
810  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
811  " kVAr");
812  }
813  case UNIT_MVAr: {
814  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
815  " MVAr");
816  }
817  default:
818  break;
819  }
820  } break;
821  default:
822  break;
823  }
824  }
825  } break;
826  case TYPE_IND_MOTOR: {
827  IndMotor* indMotor = static_cast<IndMotor*>(m_element);
828  if(indMotor) {
829  IndMotorElectricalData data = indMotor->GetPUElectricalData(systemPowerBase);
830  std::complex<double> sPower(data.activePower, data.reactivePower);
831  if(!indMotor->IsOnline()) sPower = std::complex<double>(0.0, 0.0);
832  switch(m_dataType) {
833  case DATA_NAME: {
834  SetText(data.name);
835  } break;
836  case DATA_ACTIVE_POWER: {
837  switch(m_unit) {
838  case UNIT_PU: {
839  SetText(wxString::FromDouble(sPower.real(), m_decimalPlaces) + " p.u.");
840  }
841  case UNIT_W: {
842  SetText(wxString::FromDouble(sPower.real() * systemPowerBase, m_decimalPlaces) + " W");
843  }
844  case UNIT_kW: {
845  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e3, m_decimalPlaces) +
846  " kW");
847  }
848  case UNIT_MW: {
849  SetText(wxString::FromDouble(sPower.real() * systemPowerBase / 1e6, m_decimalPlaces) +
850  " MW");
851  }
852  default:
853  break;
854  }
855  } break;
856  case DATA_REACTIVE_POWER: {
857  switch(m_unit) {
858  case UNIT_PU: {
859  SetText(wxString::FromDouble(sPower.imag(), m_decimalPlaces) + " p.u.");
860  }
861  case UNIT_VAr: {
862  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase, m_decimalPlaces) +
863  " VAr");
864  }
865  case UNIT_kVAr: {
866  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e3, m_decimalPlaces) +
867  " kVAr");
868  }
869  case UNIT_MVAr: {
870  SetText(wxString::FromDouble(sPower.imag() * systemPowerBase / 1e6, m_decimalPlaces) +
871  " MVAr");
872  }
873  default:
874  break;
875  }
876  } break;
877  default:
878  break;
879  }
880  }
881  } break;
882  case TYPE_CAPACITOR: {
883  Capacitor* capacitor = static_cast<Capacitor*>(m_element);
884  if(capacitor) {
885  CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
886  double reativePower = data.reactivePower;
887  if(!capacitor->IsOnline())
888  reativePower = 0.0;
889  else {
890  std::complex<double> v =
891  static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().voltage;
892  reativePower *= std::pow(std::abs(v), 2);
893  }
894  switch(m_dataType) {
895  case DATA_NAME: {
896  SetText(data.name);
897  } break;
898  case DATA_REACTIVE_POWER: {
899  switch(m_unit) {
900  case UNIT_PU: {
901  SetText(wxString::FromDouble(reativePower, m_decimalPlaces) + " p.u.");
902  }
903  case UNIT_VAr: {
904  SetText(wxString::FromDouble(reativePower * systemPowerBase, m_decimalPlaces) + " VAr");
905  }
906  case UNIT_kVAr: {
907  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e3, m_decimalPlaces) +
908  " kVAr");
909  }
910  case UNIT_MVAr: {
911  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e6, m_decimalPlaces) +
912  " MVAr");
913  }
914  default:
915  break;
916  }
917  } break;
918  default:
919  break;
920  }
921  }
922  } break;
923  case TYPE_INDUCTOR: {
924  Inductor* inductor = static_cast<Inductor*>(m_element);
925  if(inductor) {
926  InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
927  double reativePower = data.reactivePower;
928  if(!inductor->IsOnline())
929  reativePower = 0.0;
930  else {
931  std::complex<double> v =
932  static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().voltage;
933  reativePower *= std::pow(std::abs(v), 2);
934  }
935  switch(m_dataType) {
936  case DATA_NAME: {
937  SetText(data.name);
938  } break;
939  case DATA_REACTIVE_POWER: {
940  switch(m_unit) {
941  case UNIT_PU: {
942  SetText(wxString::FromDouble(reativePower, m_decimalPlaces) + " p.u.");
943  }
944  case UNIT_VAr: {
945  SetText(wxString::FromDouble(reativePower * systemPowerBase, m_decimalPlaces) + " VAr");
946  }
947  case UNIT_kVAr: {
948  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e3, m_decimalPlaces) +
949  " kVAr");
950  }
951  case UNIT_MVAr: {
952  SetText(wxString::FromDouble(reativePower * systemPowerBase / 1e6, m_decimalPlaces) +
953  " MVAr");
954  }
955  default:
956  break;
957  }
958  } break;
959  default:
960  break;
961  }
962  }
963  } break;
964  }
965 }
966 
968 {
969  Text* copy = new Text();
970  *copy = *this;
971  // The pointers to wxGLString must be different or can cause crashes.
972  copy->m_glString = NULL;
973  copy->m_glStringArray = NULL;
974  copy->SetText(copy->m_text);
975  return copy;
976 }
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
+
Element that shows power element informations in workspace.
Definition: Text.h:72
+
Abstract class for graphical elements shown with power elements in workspace.
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Text.cpp:162
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
+ -
Base class of electric calculations, with general methods.
+ + - +
Synchronous generator power element.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Text.cpp:92
virtual wxPoint2DDouble RotateAtPosition(wxPoint2DDouble pointToRotate, double angle, bool degrees=true) const
Rotate a point as element position being the origin.
Definition: Element.cpp:107
+
virtual void DrawRectangle(wxPoint2DDouble position, double width, double height, GLenum mode=GL_QUADS) const
Draw rectangle.
Definition: Element.cpp:69
+
virtual Element * GetCopy()
Get a the element copy.
Definition: Text.cpp:967
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
+ +
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition: Element.cpp:25
+
Form to edit the text graphical data.
Definition: TextForm.h:32
-
Definition: Line.h:52
-
Definition: Load.h:35
+
Power line element.
Definition: Line.h:59
+
Loas shunt power element.
Definition: Load.h:42
- - + +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
Induction motor power element.
Definition: IndMotor.h:40
+ - - +
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
virtual bool RotatedRectanglesIntersects(wxRect2DDouble rect1, wxRect2DDouble rect2, double angle1, double angle2) const
Check if two roteted rectangles intersect.
Definition: Element.cpp:147
+ - +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_text_8h.html b/docs/doxygen/html/_text_8h.html new file mode 100644 index 0000000..3c05a89 --- /dev/null +++ b/docs/doxygen/html/_text_8h.html @@ -0,0 +1,155 @@ + + + + + + + + + +Project/Text.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Text.h File Reference
+
+
+
#include "GraphicalElement.h"
+#include "PowerElement.h"
+#include "wxGLString.h"
+
+

Go to the source code of this file.

+ + + + + +

+Classes

class  Text
 Element that shows power element informations in workspace. More...
 
+ + + + + +

+Enumerations

enum  ElementType {
+  TYPE_NONE = 0, +TYPE_BUS, +TYPE_CAPACITOR, +TYPE_IND_MOTOR, +
+  TYPE_INDUCTOR, +TYPE_LINE, +TYPE_LOAD, +TYPE_SYNC_GENERATOR, +
+  TYPE_SYNC_MOTOR, +TYPE_TRANSFORMER +
+ }
 
enum  DataType {
+  DATA_NAME, +DATA_VOLTAGE, +DATA_ANGLE, +DATA_SC_CURRENT, +
+  DATA_SC_VOLTAGE, +DATA_SC_POWER, +DATA_ACTIVE_POWER, +DATA_REACTIVE_POWER, +
+  DATA_PF_ACTIVE, +DATA_PF_REACTIVE, +DATA_PF_LOSSES, +DATA_PF_CURRENT +
+ }
 
+
+
+ + + + diff --git a/docs/doxygen/html/_text_8h.js b/docs/doxygen/html/_text_8h.js new file mode 100644 index 0000000..6db81f3 --- /dev/null +++ b/docs/doxygen/html/_text_8h.js @@ -0,0 +1,30 @@ +var _text_8h = +[ + [ "Text", "class_text.html", "class_text" ], + [ "DataType", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6", [ + [ "DATA_NAME", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6ab7040a50973a299b4bb7a583c96daadd", null ], + [ "DATA_VOLTAGE", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6a2ca371d2e0d1ad3ac5b2b50adfafd9e1", null ], + [ "DATA_ANGLE", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6a4e82b326f9c3de98460df5362aa44e92", null ], + [ "DATA_SC_CURRENT", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6aabd0755439b58817f974429b6fc24b75", null ], + [ "DATA_SC_VOLTAGE", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6a4c60231ccdc66a26e8496abe76576f24", null ], + [ "DATA_SC_POWER", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6af3c8353176bb407fb6b1b40efd5476d1", null ], + [ "DATA_ACTIVE_POWER", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6af39976a2a2423b1817236bef5d2213e7", null ], + [ "DATA_REACTIVE_POWER", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6a77de5416cbae97c24743d0b479d3e942", null ], + [ "DATA_PF_ACTIVE", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6aa62cac0375f8d12dad808a2714811d1d", null ], + [ "DATA_PF_REACTIVE", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6ae1b2bf8507145590a0e4152cc9630d82", null ], + [ "DATA_PF_LOSSES", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6ad7558996cb619db166f38c76c75bb232", null ], + [ "DATA_PF_CURRENT", "_text_8h.html#ad8ed01ff3ff33333d8e19db4d2818bb6ad45f89e02b92507cadf1f1116e9474fb", null ] + ] ], + [ "ElementType", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01ae", [ + [ "TYPE_NONE", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea01a66f4d8d66e4614c1c900c5a1c37ff", null ], + [ "TYPE_BUS", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aeaf00e74cf5eee391e33017bded0e16441", null ], + [ "TYPE_CAPACITOR", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea998ba698d626c693ac0221506d9b25f4", null ], + [ "TYPE_IND_MOTOR", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aead674b87cc573664b0ed19aea4dad9b28", null ], + [ "TYPE_INDUCTOR", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea96ea624f93518535cfa4cdbf874fc5a5", null ], + [ "TYPE_LINE", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea6a7fcf36ea744349687acad656884ee6", null ], + [ "TYPE_LOAD", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea4924f28256f67f848f35fd2c52316425", null ], + [ "TYPE_SYNC_GENERATOR", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea04e67f46cc2905135b5d376518542b12", null ], + [ "TYPE_SYNC_MOTOR", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aeac13da57b6eda9c8ec23ed0a371600320", null ], + [ "TYPE_TRANSFORMER", "_text_8h.html#a16b11be27a8e9362dd122c4d879e01aea111c77888a1c99bf6aae9e70c460cf5c", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/doxygen/html/_text_8h_source.html b/docs/doxygen/html/_text_8h_source.html index 7d6d796..5b4f986 100644 --- a/docs/doxygen/html/_text_8h_source.html +++ b/docs/doxygen/html/_text_8h_source.html @@ -88,34 +88,35 @@ $(document).ready(function(){initNavTree('_text_8h_source.html','');});
Text.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TEXT_H
19 #define TEXT_H
20 
21 #include "GraphicalElement.h"
22 #include "PowerElement.h"
23 #include "wxGLString.h"
24 
25 class TextForm;
26 
27 class Bus;
28 class Line;
29 class Transformer;
30 class SyncGenerator;
31 class IndMotor;
32 class SyncMotor;
33 class Load;
34 class Inductor;
35 class Capacitor;
36 
37 enum ElementType {
38  TYPE_NONE = 0,
39  TYPE_BUS,
40  TYPE_CAPACITOR,
41  TYPE_IND_MOTOR,
42  TYPE_INDUCTOR,
43  TYPE_LINE,
44  TYPE_LOAD,
45  TYPE_SYNC_GENERATOR,
46  TYPE_SYNC_MOTOR,
47  TYPE_TRANSFORMER
48 };
49 
50 enum DataType {
51  DATA_NAME,
52  DATA_VOLTAGE,
53  DATA_ANGLE,
54  DATA_SC_CURRENT,
55  DATA_SC_VOLTAGE,
56  DATA_SC_POWER,
57  DATA_ACTIVE_POWER,
58  DATA_REACTIVE_POWER,
59  DATA_PF_ACTIVE,
60  DATA_PF_REACTIVE,
61  DATA_PF_LOSSES,
62  DATA_PF_CURRENT
63 };
64 
65 class Text : public GraphicalElement
66 {
67  public:
68  Text();
69  Text(wxPoint2DDouble position);
70  ~Text();
71 
72  virtual Element* GetCopy();
73  virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return true; };
74  virtual bool Contains(wxPoint2DDouble position) const;
75  virtual void Draw(wxPoint2DDouble translation, double scale);
76  virtual bool Intersects(wxRect2DDouble rect) const;
77  virtual void Rotate(bool clockwise = true);
78  virtual bool ShowForm(wxWindow* parent, std::vector<Element*> elementList);
79  virtual void UpdateText(double systemPowerBase);
80  virtual wxString GetText() const { return m_text; }
81  virtual void SetText(wxString text);
82 
83  void SetDataType(const DataType& dataType) { m_dataType = dataType; }
84  void SetDirection(int direction) { m_direction = direction; }
85  void SetElement(Element* element) { m_element = element; }
86  void SetElementNumber(int elementNumber) { m_elementNumber = elementNumber; }
87  void SetElementType(const ElementType elementType) { m_elementType = elementType; }
88  void SetFontSize(int fontSize) { m_fontSize = fontSize; }
89  void SetUnit(const ElectricalUnit unit) { m_unit = unit; }
90  void SetDecimalPlaces(int decimalPlaces) { m_decimalPlaces = decimalPlaces; }
91  const DataType GetDataType() const { return m_dataType; }
92  int GetDirection() const { return m_direction; }
93  Element* GetElement() { return m_element; }
94  int GetElementNumber() const { return m_elementNumber; }
95  const ElementType GetElementType() const { return m_elementType; }
96  int GetFontSize() const { return m_fontSize; }
97  const ElectricalUnit GetUnit() const { return m_unit; }
98  int GetDecimalPlaces() const { return m_decimalPlaces; }
99  protected:
100  wxGLString* m_glString = NULL;
101  wxGLStringArray* m_glStringArray = NULL;
102 
103  wxString m_text = _("Text");
104  int m_numberOfLines;
105  bool m_isMultlineText = false;
106  int m_fontSize = 10;
107 
108  Element* m_element = NULL;
109  ElementType m_elementType = TYPE_NONE;
110  int m_elementNumber;
111  DataType m_dataType;
112  ElectricalUnit m_unit;
113  int m_direction = 0;
114  int m_decimalPlaces = 2;
115 };
116 
117 #endif // TEXT_H
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
-
Definition: Text.h:65
- - +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TEXT_H
19 #define TEXT_H
20 
21 #include "GraphicalElement.h"
22 #include "PowerElement.h"
23 #include "wxGLString.h"
24 
25 class TextForm;
26 
27 class Bus;
28 class Line;
29 class Transformer;
30 class SyncGenerator;
31 class IndMotor;
32 class SyncMotor;
33 class Load;
34 class Inductor;
35 class Capacitor;
36 
37 enum ElementType {
38  TYPE_NONE = 0,
39  TYPE_BUS,
40  TYPE_CAPACITOR,
41  TYPE_IND_MOTOR,
42  TYPE_INDUCTOR,
43  TYPE_LINE,
44  TYPE_LOAD,
45  TYPE_SYNC_GENERATOR,
46  TYPE_SYNC_MOTOR,
47  TYPE_TRANSFORMER
48 };
49 
50 enum DataType {
51  DATA_NAME,
52  DATA_VOLTAGE,
53  DATA_ANGLE,
54  DATA_SC_CURRENT,
55  DATA_SC_VOLTAGE,
56  DATA_SC_POWER,
57  DATA_ACTIVE_POWER,
58  DATA_REACTIVE_POWER,
59  DATA_PF_ACTIVE,
60  DATA_PF_REACTIVE,
61  DATA_PF_LOSSES,
62  DATA_PF_CURRENT
63 };
64 
72 class Text : public GraphicalElement
73 {
74  public:
75  Text();
76  Text(wxPoint2DDouble position);
77  ~Text();
78 
79  virtual Element* GetCopy();
80  virtual bool AddParent(Element* parent, wxPoint2DDouble position) { return true; };
81  virtual bool Contains(wxPoint2DDouble position) const;
82  virtual void Draw(wxPoint2DDouble translation, double scale);
83  virtual bool Intersects(wxRect2DDouble rect) const;
84  virtual void Rotate(bool clockwise = true);
85  virtual bool ShowForm(wxWindow* parent, std::vector<Element*> elementList);
86  virtual void UpdateText(double systemPowerBase);
87  virtual wxString GetText() const { return m_text; }
88  virtual void SetText(wxString text);
89 
90  void SetDataType(const DataType& dataType) { m_dataType = dataType; }
91  void SetDirection(int direction) { m_direction = direction; }
92  void SetElement(Element* element) { m_element = element; }
93  void SetElementNumber(int elementNumber) { m_elementNumber = elementNumber; }
94  void SetElementType(const ElementType elementType) { m_elementType = elementType; }
95  void SetFontSize(int fontSize) { m_fontSize = fontSize; }
96  void SetUnit(const ElectricalUnit unit) { m_unit = unit; }
97  void SetDecimalPlaces(int decimalPlaces) { m_decimalPlaces = decimalPlaces; }
98  const DataType GetDataType() const { return m_dataType; }
99  int GetDirection() const { return m_direction; }
100  Element* GetElement() { return m_element; }
101  int GetElementNumber() const { return m_elementNumber; }
102  const ElementType GetElementType() const { return m_elementType; }
103  int GetFontSize() const { return m_fontSize; }
104  const ElectricalUnit GetUnit() const { return m_unit; }
105  int GetDecimalPlaces() const { return m_decimalPlaces; }
106  protected:
107  wxGLString* m_glString = NULL;
108  wxGLStringArray* m_glStringArray = NULL;
109 
110  wxString m_text = _("Text");
111  int m_numberOfLines;
112  bool m_isMultlineText = false;
113  int m_fontSize = 10;
114 
115  Element* m_element = NULL;
116  ElementType m_elementType = TYPE_NONE;
117  int m_elementNumber;
118  DataType m_dataType;
119  ElectricalUnit m_unit;
120  int m_direction = 0;
121  int m_decimalPlaces = 2;
122 };
123 
124 #endif // TEXT_H
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
+
Element that shows power element informations in workspace.
Definition: Text.h:72
+
Abstract class for graphical elements shown with power elements in workspace.
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Text.cpp:162
- +
Synchronous generator power element.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Text.cpp:92
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
virtual Element * GetCopy()
Get a the element copy.
Definition: Text.cpp:967
-
Definition: Bus.h:62
-
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Text.h:73
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
+
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Text.h:80
Form to edit the text graphical data.
Definition: TextForm.h:32
-
Definition: Line.h:52
-
Definition: Load.h:35
-
Switching data of power elements.
- - - - +
Power line element.
Definition: Line.h:59
+
Loas shunt power element.
Definition: Load.h:42
+ +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
Induction motor power element.
Definition: IndMotor.h:40
+
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
+ - +
Two-winding transformer power element.
Definition: Transformer.h:78
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TextForm.h"
19 
20 TextForm::TextForm(wxWindow* parent, Text* text, std::vector<Element*> elementList, double systemPowerBase)
21  : TextFormBase(parent)
22 {
23  SetSize(GetBestSize());
24  m_parent = parent;
25  m_textToEdit = text;
26  m_allElements.GetElementsFromList(elementList);
27  m_systemPowerBase = systemPowerBase;
28 
29  m_text = new Text();
30  m_text->SetElementType(text->GetElementType());
31  m_text->SetElementNumber(text->GetElementNumber());
32  m_text->SetElement(text->GetElement());
33  m_text->SetDataType(text->GetDataType());
34  m_text->SetDirection(text->GetDirection());
35  m_text->SetUnit(text->GetUnit());
36  m_text->SetDecimalPlaces(text->GetDecimalPlaces());
37 
38  if(!LoadChoices()) {
39  m_choiceName->Enable(false);
40  m_choiceTextType->Enable(false);
41  m_choiceTextFromBus->Enable(false);
42  m_choiceTextToBus->Enable(false);
43  m_choiceTextUnit->Enable(false);
44  }
45 }
46 
47 TextForm::~TextForm() {}
48 void TextForm::OnElementChoiceSelected(wxCommandEvent& event)
49 {
50  switch(m_choiceElement->GetSelection()) {
51  case 0: {
52  m_text->SetElementType(TYPE_BUS);
53  } break;
54  case 1: {
55  m_text->SetElementType(TYPE_SYNC_GENERATOR);
56  } break;
57  case 2: {
58  m_text->SetElementType(TYPE_LINE);
59  } break;
60  case 3: {
61  m_text->SetElementType(TYPE_TRANSFORMER);
62  } break;
63  case 4: {
64  m_text->SetElementType(TYPE_LOAD);
65  } break;
66  case 5: {
67  m_text->SetElementType(TYPE_CAPACITOR);
68  } break;
69  case 6: {
70  m_text->SetElementType(TYPE_INDUCTOR);
71  } break;
72  case 7: {
73  m_text->SetElementType(TYPE_SYNC_MOTOR);
74  } break;
75  case 8: {
76  m_text->SetElementType(TYPE_IND_MOTOR);
77  } break;
78 
79  default:
80  break;
81  }
82 
83  ElementTypeChoice();
84 }
85 
86 void TextForm::OnFromBusChoiceSelected(wxCommandEvent& event)
87 {
88  m_text->SetDirection(m_choiceTextFromBus->GetSelection());
89  m_choiceTextToBus->SetSelection(m_choiceTextFromBus->GetSelection());
90 }
91 
92 void TextForm::OnNameChoiceSelected(wxCommandEvent& event)
93 {
94  m_text->SetElementNumber(m_choiceName->GetSelection());
95  ElementNumberChoice();
96 }
97 
98 void TextForm::OnTextEnter(wxCommandEvent& event) { Preview(); }
99 void TextForm::OnToBusChoiceSelected(wxCommandEvent& event)
100 {
101  m_text->SetDirection(m_choiceTextToBus->GetSelection());
102  m_choiceTextFromBus->SetSelection(m_choiceTextToBus->GetSelection());
103 }
104 
105 void TextForm::OnUnitChoiceSelected(wxCommandEvent& event)
106 {
107  UnitChoice();
108  Preview();
109 }
110 
111 void TextForm::OnTypeChoiceSelected(wxCommandEvent& event)
112 {
113  switch(m_text->GetElementType()) {
114  case TYPE_BUS: {
115  switch(m_choiceTextType->GetSelection()) {
116  case 0: {
117  m_text->SetDataType(DATA_NAME);
118  } break;
119  case 1: {
120  m_text->SetDataType(DATA_VOLTAGE);
121  } break;
122  case 2: {
123  m_text->SetDataType(DATA_ANGLE);
124  } break;
125  case 3: {
126  m_text->SetDataType(DATA_SC_CURRENT);
127  } break;
128  case 4: {
129  m_text->SetDataType(DATA_SC_VOLTAGE);
130  } break;
131  case 5: {
132  m_text->SetDataType(DATA_SC_POWER);
133  } break;
134  }
135  } break;
136  case TYPE_SYNC_GENERATOR: {
137  switch(m_choiceTextType->GetSelection()) {
138  case 0: {
139  m_text->SetDataType(DATA_NAME);
140  } break;
141  case 1: {
142  m_text->SetDataType(DATA_ACTIVE_POWER);
143  } break;
144  case 2: {
145  m_text->SetDataType(DATA_REACTIVE_POWER);
146  } break;
147  case 3: {
148  m_text->SetDataType(DATA_SC_CURRENT);
149  } break;
150  }
151  } break;
152  case TYPE_LINE:
153  case TYPE_TRANSFORMER: {
154  switch(m_choiceTextType->GetSelection()) {
155  case 0: {
156  m_text->SetDataType(DATA_NAME);
157  } break;
158  case 1: {
159  m_text->SetDataType(DATA_PF_ACTIVE);
160  } break;
161  case 2: {
162  m_text->SetDataType(DATA_PF_REACTIVE);
163  } break;
164  case 3: {
165  m_text->SetDataType(DATA_PF_LOSSES);
166  } break;
167  case 4: {
168  m_text->SetDataType(DATA_PF_CURRENT);
169  } break;
170  case 5: {
171  m_text->SetDataType(DATA_SC_CURRENT);
172  } break;
173  }
174  } break;
175  case TYPE_LOAD:
176  case TYPE_SYNC_MOTOR:
177  case TYPE_IND_MOTOR: {
178  switch(m_choiceTextType->GetSelection()) {
179  case 0: {
180  m_text->SetDataType(DATA_NAME);
181  } break;
182  case 1: {
183  m_text->SetDataType(DATA_ACTIVE_POWER);
184  } break;
185  case 2: {
186  m_text->SetDataType(DATA_REACTIVE_POWER);
187  } break;
188  }
189  } break;
190  case TYPE_CAPACITOR:
191  case TYPE_INDUCTOR: {
192  switch(m_choiceTextType->GetSelection()) {
193  case 0: {
194  m_text->SetDataType(DATA_NAME);
195  } break;
196  case 1: {
197  m_text->SetDataType(DATA_REACTIVE_POWER);
198  } break;
199  }
200  } break;
201  default:
202  break;
203  }
204  DataTypeChoice();
205 
206  if(m_text->GetDataType() == DATA_NAME) Preview();
207 }
208 
209 bool TextForm::LoadChoices()
210 {
211  if(m_text->GetElementType() == TYPE_NONE) return false;
212 
213  // Fill the element possible choices.
214  ElementTypeChoice();
215  m_choiceName->SetSelection(m_text->GetElementNumber());
216  ElementNumberChoice();
217  DataTypeChoice();
218 
219  // Select the saved choices.
220  switch(m_text->GetElementType()) {
221  case TYPE_BUS: {
222  m_choiceElement->SetSelection(0);
223  switch(m_text->GetDataType()) {
224  case DATA_NAME: {
225  m_choiceTextType->SetSelection(0);
226  } break;
227  case DATA_VOLTAGE: {
228  m_choiceTextType->SetSelection(1);
229  switch(m_text->GetUnit()) {
230  case UNIT_PU: {
231  m_choiceTextUnit->SetSelection(0);
232  } break;
233  case UNIT_V: {
234  m_choiceTextUnit->SetSelection(1);
235  } break;
236  case UNIT_kV: {
237  m_choiceTextUnit->SetSelection(2);
238  } break;
239  default:
240  break;
241  }
242 
243  } break;
244  case DATA_ANGLE: {
245  m_choiceTextType->SetSelection(2);
246  switch(m_text->GetUnit()) {
247  case UNIT_DEGREE: {
248  m_choiceTextUnit->SetSelection(0);
249  } break;
250  case UNIT_RADIAN: {
251  m_choiceTextUnit->SetSelection(1);
252  } break;
253  default:
254  break;
255  }
256  } break;
257  case DATA_SC_CURRENT: {
258  m_choiceTextType->SetSelection(3);
259  switch(m_text->GetUnit()) {
260  case UNIT_PU: {
261  m_choiceTextUnit->SetSelection(0);
262  } break;
263  case UNIT_A: {
264  m_choiceTextUnit->SetSelection(1);
265  } break;
266  case UNIT_kA: {
267  m_choiceTextUnit->SetSelection(2);
268  } break;
269  default:
270  break;
271  }
272  } break;
273  case DATA_SC_VOLTAGE: {
274  m_choiceTextType->SetSelection(4);
275  switch(m_text->GetUnit()) {
276  case UNIT_PU: {
277  m_choiceTextUnit->SetSelection(0);
278  } break;
279  case UNIT_V: {
280  m_choiceTextUnit->SetSelection(1);
281  } break;
282  case UNIT_kV: {
283  m_choiceTextUnit->SetSelection(2);
284  } break;
285  default:
286  break;
287  }
288  } break;
289  case DATA_SC_POWER: {
290  m_choiceTextType->SetSelection(5);
291  switch(m_text->GetUnit()) {
292  case UNIT_PU: {
293  m_choiceTextUnit->SetSelection(0);
294  } break;
295  case UNIT_VA: {
296  m_choiceTextUnit->SetSelection(1);
297  } break;
298  case UNIT_kVA: {
299  m_choiceTextUnit->SetSelection(2);
300  } break;
301  case UNIT_MVA: {
302  m_choiceTextUnit->SetSelection(3);
303  } break;
304  default:
305  break;
306  }
307  } break;
308  default:
309  break;
310  }
311  } break;
312  case TYPE_SYNC_GENERATOR: {
313  m_choiceElement->SetSelection(1);
314  switch(m_text->GetDataType()) {
315  case DATA_NAME: {
316  m_choiceTextType->SetSelection(0);
317  } break;
318  case DATA_ACTIVE_POWER: {
319  m_choiceTextType->SetSelection(1);
320  switch(m_text->GetUnit()) {
321  case UNIT_PU: {
322  m_choiceTextUnit->SetSelection(0);
323  } break;
324  case UNIT_W: {
325  m_choiceTextUnit->SetSelection(1);
326  } break;
327  case UNIT_kW: {
328  m_choiceTextUnit->SetSelection(2);
329  } break;
330  case UNIT_MW: {
331  m_choiceTextUnit->SetSelection(3);
332  } break;
333  default:
334  break;
335  }
336  } break;
337  case DATA_REACTIVE_POWER: {
338  m_choiceTextType->SetSelection(2);
339  switch(m_text->GetUnit()) {
340  case UNIT_PU: {
341  m_choiceTextUnit->SetSelection(0);
342  } break;
343  case UNIT_VAr: {
344  m_choiceTextUnit->SetSelection(1);
345  } break;
346  case UNIT_kVAr: {
347  m_choiceTextUnit->SetSelection(2);
348  } break;
349  case UNIT_MVAr: {
350  m_choiceTextUnit->SetSelection(3);
351  } break;
352  default:
353  break;
354  }
355  } break;
356  case DATA_SC_CURRENT: {
357  m_choiceTextType->SetSelection(3);
358  switch(m_text->GetUnit()) {
359  case UNIT_PU: {
360  m_choiceTextUnit->SetSelection(0);
361  } break;
362  case UNIT_A: {
363  m_choiceTextUnit->SetSelection(1);
364  } break;
365  case UNIT_kA: {
366  m_choiceTextUnit->SetSelection(2);
367  } break;
368  default:
369  break;
370  }
371  } break;
372  default:
373  break;
374  }
375  } break;
376  case TYPE_LINE: {
377  m_choiceElement->SetSelection(2);
378  switch(m_text->GetDataType()) {
379  case DATA_NAME: {
380  m_choiceTextType->SetSelection(0);
381  } break;
382  case DATA_PF_ACTIVE: {
383  m_choiceTextType->SetSelection(1);
384  switch(m_text->GetUnit()) {
385  case UNIT_PU: {
386  m_choiceTextUnit->SetSelection(0);
387  } break;
388  case UNIT_W: {
389  m_choiceTextUnit->SetSelection(1);
390  } break;
391  case UNIT_kW: {
392  m_choiceTextUnit->SetSelection(2);
393  } break;
394  case UNIT_MW: {
395  m_choiceTextUnit->SetSelection(3);
396  } break;
397  default:
398  break;
399  }
400  } break;
401  case DATA_PF_REACTIVE: {
402  m_choiceTextType->SetSelection(2);
403  switch(m_text->GetUnit()) {
404  case UNIT_PU: {
405  m_choiceTextUnit->SetSelection(0);
406  } break;
407  case UNIT_VAr: {
408  m_choiceTextUnit->SetSelection(1);
409  } break;
410  case UNIT_kVAr: {
411  m_choiceTextUnit->SetSelection(2);
412  } break;
413  case UNIT_MVAr: {
414  m_choiceTextUnit->SetSelection(3);
415  } break;
416  default:
417  break;
418  }
419  } break;
420  case DATA_PF_LOSSES: {
421  m_choiceTextType->SetSelection(3);
422  switch(m_text->GetUnit()) {
423  case UNIT_PU: {
424  m_choiceTextUnit->SetSelection(0);
425  } break;
426  case UNIT_W: {
427  m_choiceTextUnit->SetSelection(1);
428  } break;
429  case UNIT_kW: {
430  m_choiceTextUnit->SetSelection(2);
431  } break;
432  case UNIT_MW: {
433  m_choiceTextUnit->SetSelection(3);
434  } break;
435  default:
436  break;
437  }
438  } break;
439  case DATA_PF_CURRENT: {
440  m_choiceTextType->SetSelection(4);
441  switch(m_text->GetUnit()) {
442  case UNIT_PU: {
443  m_choiceTextUnit->SetSelection(0);
444  } break;
445  case UNIT_A: {
446  m_choiceTextUnit->SetSelection(1);
447  } break;
448  case UNIT_kA: {
449  m_choiceTextUnit->SetSelection(2);
450  } break;
451  default:
452  break;
453  }
454  } break;
455  case DATA_SC_CURRENT: {
456  m_choiceTextType->SetSelection(5);
457  switch(m_text->GetUnit()) {
458  case UNIT_PU: {
459  m_choiceTextUnit->SetSelection(0);
460  } break;
461  case UNIT_A: {
462  m_choiceTextUnit->SetSelection(1);
463  } break;
464  case UNIT_kA: {
465  m_choiceTextUnit->SetSelection(2);
466  } break;
467  case UNIT_MW: {
468  m_choiceTextUnit->SetSelection(3);
469  } break;
470  default:
471  break;
472  }
473  } break;
474  default:
475  break;
476  }
477  } break;
478  case TYPE_TRANSFORMER: {
479  m_choiceElement->SetSelection(3);
480  switch(m_text->GetDataType()) {
481  case DATA_NAME: {
482  m_choiceTextType->SetSelection(0);
483  } break;
484  case DATA_PF_ACTIVE: {
485  m_choiceTextType->SetSelection(1);
486  switch(m_text->GetUnit()) {
487  case UNIT_PU: {
488  m_choiceTextUnit->SetSelection(0);
489  } break;
490  case UNIT_W: {
491  m_choiceTextUnit->SetSelection(1);
492  } break;
493  case UNIT_kW: {
494  m_choiceTextUnit->SetSelection(2);
495  } break;
496  case UNIT_MW: {
497  m_choiceTextUnit->SetSelection(3);
498  } break;
499  default:
500  break;
501  }
502  } break;
503  case DATA_PF_REACTIVE: {
504  m_choiceTextType->SetSelection(2);
505  switch(m_text->GetUnit()) {
506  case UNIT_PU: {
507  m_choiceTextUnit->SetSelection(0);
508  } break;
509  case UNIT_VAr: {
510  m_choiceTextUnit->SetSelection(1);
511  } break;
512  case UNIT_kVAr: {
513  m_choiceTextUnit->SetSelection(2);
514  } break;
515  case UNIT_MVAr: {
516  m_choiceTextUnit->SetSelection(3);
517  } break;
518  default:
519  break;
520  }
521  } break;
522  case DATA_PF_LOSSES: {
523  m_choiceTextType->SetSelection(3);
524  switch(m_text->GetUnit()) {
525  case UNIT_PU: {
526  m_choiceTextUnit->SetSelection(0);
527  } break;
528  case UNIT_W: {
529  m_choiceTextUnit->SetSelection(1);
530  } break;
531  case UNIT_kW: {
532  m_choiceTextUnit->SetSelection(2);
533  } break;
534  case UNIT_MW: {
535  m_choiceTextUnit->SetSelection(3);
536  } break;
537  default:
538  break;
539  }
540  } break;
541  case DATA_PF_CURRENT: {
542  m_choiceTextType->SetSelection(4);
543  switch(m_text->GetUnit()) {
544  case UNIT_PU: {
545  m_choiceTextUnit->SetSelection(0);
546  } break;
547  case UNIT_A: {
548  m_choiceTextUnit->SetSelection(1);
549  } break;
550  case UNIT_kA: {
551  m_choiceTextUnit->SetSelection(2);
552  } break;
553  default:
554  break;
555  }
556  } break;
557  case DATA_SC_CURRENT: {
558  m_choiceTextType->SetSelection(5);
559  switch(m_text->GetUnit()) {
560  case UNIT_PU: {
561  m_choiceTextUnit->SetSelection(0);
562  } break;
563  case UNIT_A: {
564  m_choiceTextUnit->SetSelection(1);
565  } break;
566  case UNIT_kA: {
567  m_choiceTextUnit->SetSelection(2);
568  } break;
569  default:
570  break;
571  }
572  } break;
573  default:
574  break;
575  }
576  } break;
577  case TYPE_LOAD: {
578  m_choiceElement->SetSelection(4);
579  switch(m_text->GetDataType()) {
580  case DATA_NAME: {
581  m_choiceTextType->SetSelection(0);
582  } break;
583  case DATA_ACTIVE_POWER: {
584  m_choiceTextType->SetSelection(1);
585  switch(m_text->GetUnit()) {
586  case UNIT_PU: {
587  m_choiceTextUnit->SetSelection(0);
588  } break;
589  case UNIT_W: {
590  m_choiceTextUnit->SetSelection(1);
591  } break;
592  case UNIT_kW: {
593  m_choiceTextUnit->SetSelection(2);
594  } break;
595  case UNIT_MW: {
596  m_choiceTextUnit->SetSelection(3);
597  } break;
598  default:
599  break;
600  }
601  } break;
602  case DATA_REACTIVE_POWER: {
603  m_choiceTextType->SetSelection(2);
604  switch(m_text->GetUnit()) {
605  case UNIT_PU: {
606  m_choiceTextUnit->SetSelection(0);
607  } break;
608  case UNIT_VAr: {
609  m_choiceTextUnit->SetSelection(1);
610  } break;
611  case UNIT_kVAr: {
612  m_choiceTextUnit->SetSelection(2);
613  } break;
614  case UNIT_MVAr: {
615  m_choiceTextUnit->SetSelection(3);
616  } break;
617  default:
618  break;
619  }
620  } break;
621  default:
622  break;
623  }
624  } break;
625  case TYPE_CAPACITOR: {
626  m_choiceElement->SetSelection(5);
627  switch(m_text->GetDataType()) {
628  case DATA_NAME: {
629  m_choiceTextType->SetSelection(0);
630  } break;
631  case DATA_REACTIVE_POWER: {
632  m_choiceTextType->SetSelection(1);
633 
634  } break;
635  default:
636  break;
637  }
638  } break;
639  case TYPE_INDUCTOR: {
640  m_choiceElement->SetSelection(6);
641  switch(m_text->GetDataType()) {
642  case DATA_NAME: {
643  m_choiceTextType->SetSelection(0);
644  } break;
645  case DATA_REACTIVE_POWER: {
646  m_choiceTextType->SetSelection(1);
647  switch(m_text->GetUnit()) {
648  case UNIT_PU: {
649  m_choiceTextUnit->SetSelection(0);
650  } break;
651  case UNIT_VAr: {
652  m_choiceTextUnit->SetSelection(1);
653  } break;
654  case UNIT_kVAr: {
655  m_choiceTextUnit->SetSelection(2);
656  } break;
657  case UNIT_MVAr: {
658  m_choiceTextUnit->SetSelection(3);
659  } break;
660  default:
661  break;
662  }
663  } break;
664  default:
665  break;
666  }
667  } break;
668  case TYPE_SYNC_MOTOR: {
669  m_choiceElement->SetSelection(7);
670  switch(m_text->GetDataType()) {
671  case DATA_NAME: {
672  m_choiceTextType->SetSelection(0);
673  } break;
674  case DATA_ACTIVE_POWER: {
675  m_choiceTextType->SetSelection(1);
676  switch(m_text->GetUnit()) {
677  case UNIT_PU: {
678  m_choiceTextUnit->SetSelection(0);
679  } break;
680  case UNIT_W: {
681  m_choiceTextUnit->SetSelection(1);
682  } break;
683  case UNIT_kW: {
684  m_choiceTextUnit->SetSelection(2);
685  } break;
686  case UNIT_MW: {
687  m_choiceTextUnit->SetSelection(3);
688  } break;
689  default:
690  break;
691  }
692  } break;
693  case DATA_REACTIVE_POWER: {
694  m_choiceTextType->SetSelection(2);
695  switch(m_text->GetUnit()) {
696  case UNIT_PU: {
697  m_choiceTextUnit->SetSelection(0);
698  } break;
699  case UNIT_VAr: {
700  m_choiceTextUnit->SetSelection(1);
701  } break;
702  case UNIT_kVAr: {
703  m_choiceTextUnit->SetSelection(2);
704  } break;
705  case UNIT_MVAr: {
706  m_choiceTextUnit->SetSelection(3);
707  } break;
708  default:
709  break;
710  }
711  } break;
712  default:
713  break;
714  }
715  } break;
716  case TYPE_IND_MOTOR: {
717  m_choiceElement->SetSelection(8);
718  switch(m_text->GetDataType()) {
719  case DATA_NAME: {
720  m_choiceTextType->SetSelection(0);
721  } break;
722  case DATA_ACTIVE_POWER: {
723  m_choiceTextType->SetSelection(1);
724  switch(m_text->GetUnit()) {
725  case UNIT_PU: {
726  m_choiceTextUnit->SetSelection(0);
727  } break;
728  case UNIT_W: {
729  m_choiceTextUnit->SetSelection(1);
730  } break;
731  case UNIT_kW: {
732  m_choiceTextUnit->SetSelection(2);
733  } break;
734  case UNIT_MW: {
735  m_choiceTextUnit->SetSelection(3);
736  } break;
737  default:
738  break;
739  }
740  } break;
741  case DATA_REACTIVE_POWER: {
742  m_choiceTextType->SetSelection(2);
743  switch(m_text->GetUnit()) {
744  case UNIT_PU: {
745  m_choiceTextUnit->SetSelection(0);
746  } break;
747  case UNIT_VAr: {
748  m_choiceTextUnit->SetSelection(1);
749  } break;
750  case UNIT_kVAr: {
751  m_choiceTextUnit->SetSelection(2);
752  } break;
753  case UNIT_MVAr: {
754  m_choiceTextUnit->SetSelection(3);
755  } break;
756  default:
757  break;
758  }
759  } break;
760  default:
761  break;
762  }
763  } break;
764  default:
765  break;
766  }
767 
768  if(m_choiceTextFromBus->IsEnabled()) m_choiceTextFromBus->SetSelection(m_text->GetDirection());
769  if(m_choiceTextToBus->IsEnabled()) m_choiceTextToBus->SetSelection(m_text->GetDirection());
770 
771  m_textCtrlDecimal->SetValue(wxString::Format("%d", m_text->GetDecimalPlaces()));
772  Preview();
773 
774  return true;
775 }
776 
777 void TextForm::ElementTypeChoice()
778 {
779  m_choiceTextType->Enable(false);
780  m_choiceTextFromBus->Enable(false);
781  m_choiceTextToBus->Enable(false);
782  m_choiceTextUnit->Enable(false);
783  m_choiceTextType->Clear();
784  m_choiceTextFromBus->Clear();
785  m_choiceTextToBus->Clear();
786  m_choiceTextUnit->Clear();
787 
788  m_choiceName->Clear();
789  wxArrayString arrayString;
790  switch(m_text->GetElementType()) {
791  case TYPE_BUS: {
792  for(int i = 0; i < (int)m_allElements.GetBusList().size(); i++) {
793  Bus* bus = m_allElements.GetBusList()[i];
794  arrayString.Add(bus->GetElectricalData().name);
795  }
796  } break;
797  case TYPE_SYNC_GENERATOR: {
798  for(int i = 0; i < (int)m_allElements.GetSyncGeneratorList().size(); i++) {
799  SyncGenerator* syncGenerator = m_allElements.GetSyncGeneratorList()[i];
800  arrayString.Add(syncGenerator->GetElectricalData().name);
801  }
802  } break;
803  case TYPE_LINE: {
804  for(int i = 0; i < (int)m_allElements.GetLineList().size(); i++) {
805  Line* line = m_allElements.GetLineList()[i];
806  arrayString.Add(line->GetElectricalData().name);
807  }
808  } break;
809  case TYPE_TRANSFORMER: {
810  for(int i = 0; i < (int)m_allElements.GetTransformerList().size(); i++) {
811  Transformer* transformer = m_allElements.GetTransformerList()[i];
812  arrayString.Add(transformer->GetElectricalData().name);
813  }
814  } break;
815  case TYPE_LOAD: {
816  for(int i = 0; i < (int)m_allElements.GetLoadList().size(); i++) {
817  Load* load = m_allElements.GetLoadList()[i];
818  arrayString.Add(load->GetElectricalData().name);
819  }
820  } break;
821  case TYPE_CAPACITOR: {
822  for(int i = 0; i < (int)m_allElements.GetCapacitorList().size(); i++) {
823  Capacitor* capacitor = m_allElements.GetCapacitorList()[i];
824  arrayString.Add(capacitor->GetElectricalData().name);
825  }
826  } break;
827  case TYPE_INDUCTOR: {
828  for(int i = 0; i < (int)m_allElements.GetInductorList().size(); i++) {
829  Inductor* inductor = m_allElements.GetInductorList()[i];
830  arrayString.Add(inductor->GetElectricalData().name);
831  }
832  } break;
833  case TYPE_SYNC_MOTOR: {
834  for(int i = 0; i < (int)m_allElements.GetSyncMotorList().size(); i++) {
835  SyncMotor* syncMotor = m_allElements.GetSyncMotorList()[i];
836  arrayString.Add(syncMotor->GetElectricalData().name);
837  }
838  } break;
839  case TYPE_IND_MOTOR: {
840  for(int i = 0; i < (int)m_allElements.GetIndMotorList().size(); i++) {
841  IndMotor* indMotor = m_allElements.GetIndMotorList()[i];
842  arrayString.Add(indMotor->GetElectricalData().name);
843  }
844  } break;
845 
846  default:
847  break;
848  }
849  m_choiceName->Append(arrayString);
850  m_choiceName->Enable();
851 }
852 
853 void TextForm::ElementNumberChoice()
854 {
855  m_choiceTextFromBus->Enable(false);
856  m_choiceTextToBus->Enable(false);
857  m_choiceTextUnit->Enable(false);
858  m_choiceTextFromBus->Clear();
859  m_choiceTextToBus->Clear();
860  m_choiceTextUnit->Clear();
861 
862  int index = m_choiceName->GetSelection();
863  m_text->SetElementNumber(index);
864 
865  m_choiceTextType->Clear();
866  wxArrayString arrayString;
867  switch(m_text->GetElementType()) {
868  case TYPE_BUS: {
869  Bus* bus = m_allElements.GetBusList()[index];
870  m_text->SetElement(bus);
871 
872  arrayString.Add(_("Name"));
873  arrayString.Add(_("Voltage"));
874  arrayString.Add(_("Angle"));
875  arrayString.Add(_("Fault current"));
876  arrayString.Add(_("Fault voltage"));
877  arrayString.Add(_("Short-circuit power"));
878  } break;
879  case TYPE_SYNC_GENERATOR: {
880  SyncGenerator* syncGenerator = m_allElements.GetSyncGeneratorList()[index];
881  m_text->SetElement(syncGenerator);
882 
883  arrayString.Add(_("Name"));
884  arrayString.Add(_("Active power"));
885  arrayString.Add(_("Reactive power"));
886  arrayString.Add(_("Fault current"));
887  } break;
888  case TYPE_LINE: {
889  Line* line = m_allElements.GetLineList()[index];
890  m_text->SetElement(line);
891 
892  arrayString.Add(_("Name"));
893  arrayString.Add(_("Active power flow"));
894  arrayString.Add(_("Reactive power flow"));
895  arrayString.Add(_("Losses"));
896  arrayString.Add(_("Current"));
897  arrayString.Add(_("Fault current"));
898  } break;
899  case TYPE_TRANSFORMER: {
900  Transformer* transformer = m_allElements.GetTransformerList()[index];
901  m_text->SetElement(transformer);
902 
903  arrayString.Add(_("Name"));
904  arrayString.Add(_("Active power flow"));
905  arrayString.Add(_("Reactive power flow"));
906  arrayString.Add(_("Losses"));
907  arrayString.Add(_("Current"));
908  arrayString.Add(_("Fault current"));
909  } break;
910  case TYPE_LOAD: {
911  Load* load = m_allElements.GetLoadList()[index];
912  m_text->SetElement(load);
913 
914  arrayString.Add(_("Name"));
915  arrayString.Add(_("Active power"));
916  arrayString.Add(_("Reactive power"));
917  } break;
918  case TYPE_CAPACITOR: {
919  Capacitor* capacitor = m_allElements.GetCapacitorList()[index];
920  m_text->SetElement(capacitor);
921 
922  arrayString.Add(_("Name"));
923  arrayString.Add(_("Reactive power"));
924  } break;
925  case TYPE_INDUCTOR: {
926  Inductor* inductor = m_allElements.GetInductorList()[index];
927  m_text->SetElement(inductor);
928 
929  arrayString.Add(_("Name"));
930  arrayString.Add(_("Reactive power"));
931  } break;
932  case TYPE_SYNC_MOTOR: {
933  SyncMotor* syncMotor = m_allElements.GetSyncMotorList()[index];
934  m_text->SetElement(syncMotor);
935 
936  arrayString.Add(_("Name"));
937  arrayString.Add(_("Active power"));
938  arrayString.Add(_("Reactive power"));
939  } break;
940  case TYPE_IND_MOTOR: {
941  IndMotor* indMotor = m_allElements.GetIndMotorList()[index];
942  m_text->SetElement(indMotor);
943 
944  arrayString.Add(_("Name"));
945  arrayString.Add(_("Active power"));
946  arrayString.Add(_("Reactive power"));
947  } break;
948 
949  default:
950  break;
951  }
952  m_choiceTextType->Append(arrayString);
953  m_choiceTextType->Enable();
954 }
955 
956 void TextForm::DataTypeChoice()
957 {
958  m_choiceTextFromBus->Enable(false);
959  m_choiceTextToBus->Enable(false);
960 
961  m_choiceTextToBus->Clear();
962  m_choiceTextFromBus->Clear();
963  m_choiceTextUnit->Clear();
964 
965  m_choiceTextUnit->Enable();
966 
967  wxArrayString arrayString;
968  switch(m_text->GetDataType()) {
969  case DATA_NAME: {
970  m_choiceTextUnit->Enable(false);
971  return;
972  } break;
973  case DATA_VOLTAGE:
974  case DATA_SC_VOLTAGE: {
975  arrayString.Add(_("p.u."));
976  arrayString.Add(_("V"));
977  arrayString.Add(_("kV"));
978  } break;
979  case DATA_ANGLE: {
980  arrayString.Add(_("Degrees"));
981  arrayString.Add(_("Radians"));
982  } break;
983  case DATA_SC_CURRENT:
984  case DATA_PF_CURRENT: {
985  arrayString.Add(_("p.u."));
986  arrayString.Add(_("A"));
987  arrayString.Add(_("kA"));
988  } break;
989  case DATA_SC_POWER: {
990  arrayString.Add(_("p.u."));
991  arrayString.Add(_("VA"));
992  arrayString.Add(_("kVA"));
993  arrayString.Add(_("MVA"));
994  } break;
995  case DATA_ACTIVE_POWER:
996  case DATA_PF_ACTIVE:
997  case DATA_PF_LOSSES: {
998  arrayString.Add(_("p.u."));
999  arrayString.Add(_("W"));
1000  arrayString.Add(_("kW"));
1001  arrayString.Add(_("MW"));
1002  m_choiceTextUnit->Enable();
1003  } break;
1004  case DATA_REACTIVE_POWER:
1005  case DATA_PF_REACTIVE: {
1006  arrayString.Add(_("p.u."));
1007  arrayString.Add(_("VAr"));
1008  arrayString.Add(_("kVAr"));
1009  arrayString.Add(_("MVAr"));
1010  } break;
1011  default:
1012  break;
1013  }
1014  m_choiceTextUnit->Append(arrayString);
1015 
1016  switch(m_text->GetElementType()) {
1017  case TYPE_LINE: {
1018  if(m_text->GetDataType() != DATA_PF_LOSSES) {
1019  auto it = m_allElements.GetLineList().begin();
1020  std::advance(it, m_text->GetElementNumber());
1021  Line* line = *it;
1022 
1023  Bus* bus1 = static_cast<Bus*>(line->GetParentList()[0]);
1024  Bus* bus2 = static_cast<Bus*>(line->GetParentList()[1]);
1025  wxString bus1Name = bus1->GetElectricalData().name;
1026  wxString bus2Name = bus2->GetElectricalData().name;
1027 
1028  m_choiceTextFromBus->Append(bus1Name);
1029  m_choiceTextFromBus->Append(bus2Name);
1030  m_choiceTextToBus->Append(bus2Name);
1031  m_choiceTextToBus->Append(bus1Name);
1032  m_choiceTextFromBus->SetSelection(0);
1033  m_choiceTextToBus->SetSelection(0);
1034 
1035  m_choiceTextFromBus->Enable();
1036  m_choiceTextToBus->Enable();
1037  }
1038  } break;
1039  case TYPE_TRANSFORMER: {
1040  if(m_text->GetDataType() != DATA_PF_LOSSES) {
1041  auto it = m_allElements.GetTransformerList().begin();
1042  std::advance(it, m_text->GetElementNumber());
1043  Transformer* transformer = *it;
1044 
1045  Bus* bus1 = static_cast<Bus*>(transformer->GetParentList()[0]);
1046  Bus* bus2 = static_cast<Bus*>(transformer->GetParentList()[1]);
1047  wxString bus1Name = bus1->GetElectricalData().name;
1048  wxString bus2Name = bus2->GetElectricalData().name;
1049 
1050  m_choiceTextFromBus->Append(bus1Name);
1051  m_choiceTextFromBus->Append(bus2Name);
1052  m_choiceTextToBus->Append(bus2Name);
1053  m_choiceTextToBus->Append(bus1Name);
1054  m_choiceTextFromBus->SetSelection(0);
1055  m_choiceTextToBus->SetSelection(0);
1056 
1057  m_choiceTextFromBus->Enable();
1058  m_choiceTextToBus->Enable();
1059  }
1060  } break;
1061  default:
1062  break;
1063  }
1064 }
1065 
1066 void TextForm::UnitChoice()
1067 {
1068  switch(m_text->GetDataType()) {
1069  case DATA_NAME: {
1070  m_choiceTextUnit->Enable(false);
1071  return;
1072  } break;
1073  case DATA_VOLTAGE:
1074  case DATA_SC_VOLTAGE: {
1075  switch(m_choiceTextUnit->GetSelection()) {
1076  case 0: {
1077  m_text->SetUnit(UNIT_PU);
1078  } break;
1079  case 1: {
1080  m_text->SetUnit(UNIT_V);
1081  } break;
1082  case 2: {
1083  m_text->SetUnit(UNIT_kV);
1084  } break;
1085  default:
1086  break;
1087  }
1088  } break;
1089  case DATA_ANGLE: {
1090  switch(m_choiceTextUnit->GetSelection()) {
1091  case 0: {
1092  m_text->SetUnit(UNIT_DEGREE);
1093  } break;
1094  case 1: {
1095  m_text->SetUnit(UNIT_RADIAN);
1096  } break;
1097  default:
1098  break;
1099  }
1100  } break;
1101  case DATA_SC_CURRENT:
1102  case DATA_PF_CURRENT: {
1103  switch(m_choiceTextUnit->GetSelection()) {
1104  case 0: {
1105  m_text->SetUnit(UNIT_PU);
1106  } break;
1107  case 1: {
1108  m_text->SetUnit(UNIT_A);
1109  } break;
1110  case 2: {
1111  m_text->SetUnit(UNIT_kA);
1112  } break;
1113  default:
1114  break;
1115  }
1116  } break;
1117  case DATA_SC_POWER: {
1118  switch(m_choiceTextUnit->GetSelection()) {
1119  case 0: {
1120  m_text->SetUnit(UNIT_PU);
1121  } break;
1122  case 1: {
1123  m_text->SetUnit(UNIT_VA);
1124  } break;
1125  case 2: {
1126  m_text->SetUnit(UNIT_kVA);
1127  } break;
1128  case 3: {
1129  m_text->SetUnit(UNIT_MVA);
1130  } break;
1131  default:
1132  break;
1133  }
1134  } break;
1135  case DATA_ACTIVE_POWER:
1136  case DATA_PF_ACTIVE:
1137  case DATA_PF_LOSSES: {
1138  switch(m_choiceTextUnit->GetSelection()) {
1139  case 0: {
1140  m_text->SetUnit(UNIT_PU);
1141  } break;
1142  case 1: {
1143  m_text->SetUnit(UNIT_W);
1144  } break;
1145  case 2: {
1146  m_text->SetUnit(UNIT_kW);
1147  } break;
1148  case 3: {
1149  m_text->SetUnit(UNIT_MW);
1150  } break;
1151  default:
1152  break;
1153  }
1154  } break;
1155  case DATA_REACTIVE_POWER:
1156  case DATA_PF_REACTIVE: {
1157  switch(m_choiceTextUnit->GetSelection()) {
1158  case 0: {
1159  m_text->SetUnit(UNIT_PU);
1160  } break;
1161  case 1: {
1162  m_text->SetUnit(UNIT_VAr);
1163  } break;
1164  case 2: {
1165  m_text->SetUnit(UNIT_kVAr);
1166  } break;
1167  case 3: {
1168  m_text->SetUnit(UNIT_MVAr);
1169  } break;
1170  default:
1171  break;
1172  }
1173  } break;
1174  default:
1175  break;
1176  }
1177 }
1178 
1179 void TextForm::Preview()
1180 {
1181  double decimalPlaces = m_text->GetDecimalPlaces();
1182  if(m_textCtrlDecimal->GetValue().ToDouble(&decimalPlaces)) m_text->SetDecimalPlaces(decimalPlaces);
1183 
1184  m_text->UpdateText(m_systemPowerBase);
1185 
1186  m_textCtrlPreview->SetValue(m_text->GetText());
1187 }
1188 
1189 bool TextForm::ValidateData()
1190 {
1191  if(m_choiceElement->GetSelection() == -1) return false;
1192  if(m_choiceName->GetSelection() == -1) return false;
1193  if(m_choiceTextType->GetSelection() == -1) return false;
1194  if(m_text->GetDataType() != DATA_NAME && m_choiceTextUnit->GetSelection() == -1) return false;
1195  if(m_text->GetElementType() == TYPE_LINE || m_text->GetElementType() == TYPE_TRANSFORMER) {
1196  if(m_text->GetDataType() != DATA_PF_LOSSES && m_text->GetDataType() != DATA_NAME) {
1197  if(m_choiceTextFromBus->GetSelection() == -1) return false;
1198  if(m_choiceTextToBus->GetSelection() == -1) return false;
1199  }
1200  }
1201 
1202  if(m_choiceTextFromBus->IsEnabled() && m_choiceTextToBus->IsEnabled())
1203  m_text->SetDirection(m_choiceTextFromBus->GetSelection());
1204  double decimalPlaces = m_text->GetDecimalPlaces();
1205  if(m_textCtrlDecimal->GetValue().ToDouble(&decimalPlaces)) m_text->SetDecimalPlaces(decimalPlaces);
1206 
1207  m_textToEdit->SetElementType(m_text->GetElementType());
1208  m_textToEdit->SetElementNumber(m_text->GetElementNumber());
1209  m_textToEdit->SetElement(m_text->GetElement());
1210  m_textToEdit->SetDataType(m_text->GetDataType());
1211  m_textToEdit->SetDirection(m_text->GetDirection());
1212  m_textToEdit->SetUnit(m_text->GetUnit());
1213  m_textToEdit->SetDecimalPlaces(decimalPlaces);
1214  m_textToEdit->UpdateText(m_systemPowerBase);
1215 
1216  return true;
1217 }
1218 
1219 void TextForm::OnOKButtonClick(wxCommandEvent& event)
1220 {
1221  if(ValidateData()) {
1222  EndModal(wxID_OK);
1223  } else {
1224  wxString errorMsg = _("There are blank fields.");
1225  wxMessageDialog msgDialog(this, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1226  msgDialog.ShowModal();
1227  }
1228 }
Definition: Text.h:65
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TextForm.h"
19 
20 TextForm::TextForm(wxWindow* parent, Text* text, std::vector<Element*> elementList, double systemPowerBase)
21  : TextFormBase(parent)
22 {
23  SetSize(GetBestSize());
24  m_parent = parent;
25  m_textToEdit = text;
26  m_allElements.GetElementsFromList(elementList);
27  m_systemPowerBase = systemPowerBase;
28 
29  m_text = new Text();
30  m_text->SetElementType(text->GetElementType());
31  m_text->SetElementNumber(text->GetElementNumber());
32  m_text->SetElement(text->GetElement());
33  m_text->SetDataType(text->GetDataType());
34  m_text->SetDirection(text->GetDirection());
35  m_text->SetUnit(text->GetUnit());
36  m_text->SetDecimalPlaces(text->GetDecimalPlaces());
37 
38  if(!LoadChoices()) {
39  m_choiceName->Enable(false);
40  m_choiceTextType->Enable(false);
41  m_choiceTextFromBus->Enable(false);
42  m_choiceTextToBus->Enable(false);
43  m_choiceTextUnit->Enable(false);
44  }
45 }
46 
47 TextForm::~TextForm() {}
48 void TextForm::OnElementChoiceSelected(wxCommandEvent& event)
49 {
50  switch(m_choiceElement->GetSelection()) {
51  case 0: {
52  m_text->SetElementType(TYPE_BUS);
53  } break;
54  case 1: {
55  m_text->SetElementType(TYPE_SYNC_GENERATOR);
56  } break;
57  case 2: {
58  m_text->SetElementType(TYPE_LINE);
59  } break;
60  case 3: {
61  m_text->SetElementType(TYPE_TRANSFORMER);
62  } break;
63  case 4: {
64  m_text->SetElementType(TYPE_LOAD);
65  } break;
66  case 5: {
67  m_text->SetElementType(TYPE_CAPACITOR);
68  } break;
69  case 6: {
70  m_text->SetElementType(TYPE_INDUCTOR);
71  } break;
72  case 7: {
73  m_text->SetElementType(TYPE_SYNC_MOTOR);
74  } break;
75  case 8: {
76  m_text->SetElementType(TYPE_IND_MOTOR);
77  } break;
78 
79  default:
80  break;
81  }
82 
83  ElementTypeChoice();
84 }
85 
86 void TextForm::OnFromBusChoiceSelected(wxCommandEvent& event)
87 {
88  m_text->SetDirection(m_choiceTextFromBus->GetSelection());
89  m_choiceTextToBus->SetSelection(m_choiceTextFromBus->GetSelection());
90 }
91 
92 void TextForm::OnNameChoiceSelected(wxCommandEvent& event)
93 {
94  m_text->SetElementNumber(m_choiceName->GetSelection());
95  ElementNumberChoice();
96 }
97 
98 void TextForm::OnTextEnter(wxCommandEvent& event) { Preview(); }
99 void TextForm::OnToBusChoiceSelected(wxCommandEvent& event)
100 {
101  m_text->SetDirection(m_choiceTextToBus->GetSelection());
102  m_choiceTextFromBus->SetSelection(m_choiceTextToBus->GetSelection());
103 }
104 
105 void TextForm::OnUnitChoiceSelected(wxCommandEvent& event)
106 {
107  UnitChoice();
108  Preview();
109 }
110 
111 void TextForm::OnTypeChoiceSelected(wxCommandEvent& event)
112 {
113  switch(m_text->GetElementType()) {
114  case TYPE_BUS: {
115  switch(m_choiceTextType->GetSelection()) {
116  case 0: {
117  m_text->SetDataType(DATA_NAME);
118  } break;
119  case 1: {
120  m_text->SetDataType(DATA_VOLTAGE);
121  } break;
122  case 2: {
123  m_text->SetDataType(DATA_ANGLE);
124  } break;
125  case 3: {
126  m_text->SetDataType(DATA_SC_CURRENT);
127  } break;
128  case 4: {
129  m_text->SetDataType(DATA_SC_VOLTAGE);
130  } break;
131  case 5: {
132  m_text->SetDataType(DATA_SC_POWER);
133  } break;
134  }
135  } break;
136  case TYPE_SYNC_GENERATOR: {
137  switch(m_choiceTextType->GetSelection()) {
138  case 0: {
139  m_text->SetDataType(DATA_NAME);
140  } break;
141  case 1: {
142  m_text->SetDataType(DATA_ACTIVE_POWER);
143  } break;
144  case 2: {
145  m_text->SetDataType(DATA_REACTIVE_POWER);
146  } break;
147  case 3: {
148  m_text->SetDataType(DATA_SC_CURRENT);
149  } break;
150  }
151  } break;
152  case TYPE_LINE:
153  case TYPE_TRANSFORMER: {
154  switch(m_choiceTextType->GetSelection()) {
155  case 0: {
156  m_text->SetDataType(DATA_NAME);
157  } break;
158  case 1: {
159  m_text->SetDataType(DATA_PF_ACTIVE);
160  } break;
161  case 2: {
162  m_text->SetDataType(DATA_PF_REACTIVE);
163  } break;
164  case 3: {
165  m_text->SetDataType(DATA_PF_LOSSES);
166  } break;
167  case 4: {
168  m_text->SetDataType(DATA_PF_CURRENT);
169  } break;
170  case 5: {
171  m_text->SetDataType(DATA_SC_CURRENT);
172  } break;
173  }
174  } break;
175  case TYPE_LOAD:
176  case TYPE_SYNC_MOTOR:
177  case TYPE_IND_MOTOR: {
178  switch(m_choiceTextType->GetSelection()) {
179  case 0: {
180  m_text->SetDataType(DATA_NAME);
181  } break;
182  case 1: {
183  m_text->SetDataType(DATA_ACTIVE_POWER);
184  } break;
185  case 2: {
186  m_text->SetDataType(DATA_REACTIVE_POWER);
187  } break;
188  }
189  } break;
190  case TYPE_CAPACITOR:
191  case TYPE_INDUCTOR: {
192  switch(m_choiceTextType->GetSelection()) {
193  case 0: {
194  m_text->SetDataType(DATA_NAME);
195  } break;
196  case 1: {
197  m_text->SetDataType(DATA_REACTIVE_POWER);
198  } break;
199  }
200  } break;
201  default:
202  break;
203  }
204  DataTypeChoice();
205 
206  if(m_text->GetDataType() == DATA_NAME) Preview();
207 }
208 
209 bool TextForm::LoadChoices()
210 {
211  if(m_text->GetElementType() == TYPE_NONE) return false;
212 
213  // Fill the element possible choices.
214  ElementTypeChoice();
215  m_choiceName->SetSelection(m_text->GetElementNumber());
216  ElementNumberChoice();
217  DataTypeChoice();
218 
219  // Select the saved choices.
220  switch(m_text->GetElementType()) {
221  case TYPE_BUS: {
222  m_choiceElement->SetSelection(0);
223  switch(m_text->GetDataType()) {
224  case DATA_NAME: {
225  m_choiceTextType->SetSelection(0);
226  } break;
227  case DATA_VOLTAGE: {
228  m_choiceTextType->SetSelection(1);
229  switch(m_text->GetUnit()) {
230  case UNIT_PU: {
231  m_choiceTextUnit->SetSelection(0);
232  } break;
233  case UNIT_V: {
234  m_choiceTextUnit->SetSelection(1);
235  } break;
236  case UNIT_kV: {
237  m_choiceTextUnit->SetSelection(2);
238  } break;
239  default:
240  break;
241  }
242 
243  } break;
244  case DATA_ANGLE: {
245  m_choiceTextType->SetSelection(2);
246  switch(m_text->GetUnit()) {
247  case UNIT_DEGREE: {
248  m_choiceTextUnit->SetSelection(0);
249  } break;
250  case UNIT_RADIAN: {
251  m_choiceTextUnit->SetSelection(1);
252  } break;
253  default:
254  break;
255  }
256  } break;
257  case DATA_SC_CURRENT: {
258  m_choiceTextType->SetSelection(3);
259  switch(m_text->GetUnit()) {
260  case UNIT_PU: {
261  m_choiceTextUnit->SetSelection(0);
262  } break;
263  case UNIT_A: {
264  m_choiceTextUnit->SetSelection(1);
265  } break;
266  case UNIT_kA: {
267  m_choiceTextUnit->SetSelection(2);
268  } break;
269  default:
270  break;
271  }
272  } break;
273  case DATA_SC_VOLTAGE: {
274  m_choiceTextType->SetSelection(4);
275  switch(m_text->GetUnit()) {
276  case UNIT_PU: {
277  m_choiceTextUnit->SetSelection(0);
278  } break;
279  case UNIT_V: {
280  m_choiceTextUnit->SetSelection(1);
281  } break;
282  case UNIT_kV: {
283  m_choiceTextUnit->SetSelection(2);
284  } break;
285  default:
286  break;
287  }
288  } break;
289  case DATA_SC_POWER: {
290  m_choiceTextType->SetSelection(5);
291  switch(m_text->GetUnit()) {
292  case UNIT_PU: {
293  m_choiceTextUnit->SetSelection(0);
294  } break;
295  case UNIT_VA: {
296  m_choiceTextUnit->SetSelection(1);
297  } break;
298  case UNIT_kVA: {
299  m_choiceTextUnit->SetSelection(2);
300  } break;
301  case UNIT_MVA: {
302  m_choiceTextUnit->SetSelection(3);
303  } break;
304  default:
305  break;
306  }
307  } break;
308  default:
309  break;
310  }
311  } break;
312  case TYPE_SYNC_GENERATOR: {
313  m_choiceElement->SetSelection(1);
314  switch(m_text->GetDataType()) {
315  case DATA_NAME: {
316  m_choiceTextType->SetSelection(0);
317  } break;
318  case DATA_ACTIVE_POWER: {
319  m_choiceTextType->SetSelection(1);
320  switch(m_text->GetUnit()) {
321  case UNIT_PU: {
322  m_choiceTextUnit->SetSelection(0);
323  } break;
324  case UNIT_W: {
325  m_choiceTextUnit->SetSelection(1);
326  } break;
327  case UNIT_kW: {
328  m_choiceTextUnit->SetSelection(2);
329  } break;
330  case UNIT_MW: {
331  m_choiceTextUnit->SetSelection(3);
332  } break;
333  default:
334  break;
335  }
336  } break;
337  case DATA_REACTIVE_POWER: {
338  m_choiceTextType->SetSelection(2);
339  switch(m_text->GetUnit()) {
340  case UNIT_PU: {
341  m_choiceTextUnit->SetSelection(0);
342  } break;
343  case UNIT_VAr: {
344  m_choiceTextUnit->SetSelection(1);
345  } break;
346  case UNIT_kVAr: {
347  m_choiceTextUnit->SetSelection(2);
348  } break;
349  case UNIT_MVAr: {
350  m_choiceTextUnit->SetSelection(3);
351  } break;
352  default:
353  break;
354  }
355  } break;
356  case DATA_SC_CURRENT: {
357  m_choiceTextType->SetSelection(3);
358  switch(m_text->GetUnit()) {
359  case UNIT_PU: {
360  m_choiceTextUnit->SetSelection(0);
361  } break;
362  case UNIT_A: {
363  m_choiceTextUnit->SetSelection(1);
364  } break;
365  case UNIT_kA: {
366  m_choiceTextUnit->SetSelection(2);
367  } break;
368  default:
369  break;
370  }
371  } break;
372  default:
373  break;
374  }
375  } break;
376  case TYPE_LINE: {
377  m_choiceElement->SetSelection(2);
378  switch(m_text->GetDataType()) {
379  case DATA_NAME: {
380  m_choiceTextType->SetSelection(0);
381  } break;
382  case DATA_PF_ACTIVE: {
383  m_choiceTextType->SetSelection(1);
384  switch(m_text->GetUnit()) {
385  case UNIT_PU: {
386  m_choiceTextUnit->SetSelection(0);
387  } break;
388  case UNIT_W: {
389  m_choiceTextUnit->SetSelection(1);
390  } break;
391  case UNIT_kW: {
392  m_choiceTextUnit->SetSelection(2);
393  } break;
394  case UNIT_MW: {
395  m_choiceTextUnit->SetSelection(3);
396  } break;
397  default:
398  break;
399  }
400  } break;
401  case DATA_PF_REACTIVE: {
402  m_choiceTextType->SetSelection(2);
403  switch(m_text->GetUnit()) {
404  case UNIT_PU: {
405  m_choiceTextUnit->SetSelection(0);
406  } break;
407  case UNIT_VAr: {
408  m_choiceTextUnit->SetSelection(1);
409  } break;
410  case UNIT_kVAr: {
411  m_choiceTextUnit->SetSelection(2);
412  } break;
413  case UNIT_MVAr: {
414  m_choiceTextUnit->SetSelection(3);
415  } break;
416  default:
417  break;
418  }
419  } break;
420  case DATA_PF_LOSSES: {
421  m_choiceTextType->SetSelection(3);
422  switch(m_text->GetUnit()) {
423  case UNIT_PU: {
424  m_choiceTextUnit->SetSelection(0);
425  } break;
426  case UNIT_W: {
427  m_choiceTextUnit->SetSelection(1);
428  } break;
429  case UNIT_kW: {
430  m_choiceTextUnit->SetSelection(2);
431  } break;
432  case UNIT_MW: {
433  m_choiceTextUnit->SetSelection(3);
434  } break;
435  default:
436  break;
437  }
438  } break;
439  case DATA_PF_CURRENT: {
440  m_choiceTextType->SetSelection(4);
441  switch(m_text->GetUnit()) {
442  case UNIT_PU: {
443  m_choiceTextUnit->SetSelection(0);
444  } break;
445  case UNIT_A: {
446  m_choiceTextUnit->SetSelection(1);
447  } break;
448  case UNIT_kA: {
449  m_choiceTextUnit->SetSelection(2);
450  } break;
451  default:
452  break;
453  }
454  } break;
455  case DATA_SC_CURRENT: {
456  m_choiceTextType->SetSelection(5);
457  switch(m_text->GetUnit()) {
458  case UNIT_PU: {
459  m_choiceTextUnit->SetSelection(0);
460  } break;
461  case UNIT_A: {
462  m_choiceTextUnit->SetSelection(1);
463  } break;
464  case UNIT_kA: {
465  m_choiceTextUnit->SetSelection(2);
466  } break;
467  case UNIT_MW: {
468  m_choiceTextUnit->SetSelection(3);
469  } break;
470  default:
471  break;
472  }
473  } break;
474  default:
475  break;
476  }
477  } break;
478  case TYPE_TRANSFORMER: {
479  m_choiceElement->SetSelection(3);
480  switch(m_text->GetDataType()) {
481  case DATA_NAME: {
482  m_choiceTextType->SetSelection(0);
483  } break;
484  case DATA_PF_ACTIVE: {
485  m_choiceTextType->SetSelection(1);
486  switch(m_text->GetUnit()) {
487  case UNIT_PU: {
488  m_choiceTextUnit->SetSelection(0);
489  } break;
490  case UNIT_W: {
491  m_choiceTextUnit->SetSelection(1);
492  } break;
493  case UNIT_kW: {
494  m_choiceTextUnit->SetSelection(2);
495  } break;
496  case UNIT_MW: {
497  m_choiceTextUnit->SetSelection(3);
498  } break;
499  default:
500  break;
501  }
502  } break;
503  case DATA_PF_REACTIVE: {
504  m_choiceTextType->SetSelection(2);
505  switch(m_text->GetUnit()) {
506  case UNIT_PU: {
507  m_choiceTextUnit->SetSelection(0);
508  } break;
509  case UNIT_VAr: {
510  m_choiceTextUnit->SetSelection(1);
511  } break;
512  case UNIT_kVAr: {
513  m_choiceTextUnit->SetSelection(2);
514  } break;
515  case UNIT_MVAr: {
516  m_choiceTextUnit->SetSelection(3);
517  } break;
518  default:
519  break;
520  }
521  } break;
522  case DATA_PF_LOSSES: {
523  m_choiceTextType->SetSelection(3);
524  switch(m_text->GetUnit()) {
525  case UNIT_PU: {
526  m_choiceTextUnit->SetSelection(0);
527  } break;
528  case UNIT_W: {
529  m_choiceTextUnit->SetSelection(1);
530  } break;
531  case UNIT_kW: {
532  m_choiceTextUnit->SetSelection(2);
533  } break;
534  case UNIT_MW: {
535  m_choiceTextUnit->SetSelection(3);
536  } break;
537  default:
538  break;
539  }
540  } break;
541  case DATA_PF_CURRENT: {
542  m_choiceTextType->SetSelection(4);
543  switch(m_text->GetUnit()) {
544  case UNIT_PU: {
545  m_choiceTextUnit->SetSelection(0);
546  } break;
547  case UNIT_A: {
548  m_choiceTextUnit->SetSelection(1);
549  } break;
550  case UNIT_kA: {
551  m_choiceTextUnit->SetSelection(2);
552  } break;
553  default:
554  break;
555  }
556  } break;
557  case DATA_SC_CURRENT: {
558  m_choiceTextType->SetSelection(5);
559  switch(m_text->GetUnit()) {
560  case UNIT_PU: {
561  m_choiceTextUnit->SetSelection(0);
562  } break;
563  case UNIT_A: {
564  m_choiceTextUnit->SetSelection(1);
565  } break;
566  case UNIT_kA: {
567  m_choiceTextUnit->SetSelection(2);
568  } break;
569  default:
570  break;
571  }
572  } break;
573  default:
574  break;
575  }
576  } break;
577  case TYPE_LOAD: {
578  m_choiceElement->SetSelection(4);
579  switch(m_text->GetDataType()) {
580  case DATA_NAME: {
581  m_choiceTextType->SetSelection(0);
582  } break;
583  case DATA_ACTIVE_POWER: {
584  m_choiceTextType->SetSelection(1);
585  switch(m_text->GetUnit()) {
586  case UNIT_PU: {
587  m_choiceTextUnit->SetSelection(0);
588  } break;
589  case UNIT_W: {
590  m_choiceTextUnit->SetSelection(1);
591  } break;
592  case UNIT_kW: {
593  m_choiceTextUnit->SetSelection(2);
594  } break;
595  case UNIT_MW: {
596  m_choiceTextUnit->SetSelection(3);
597  } break;
598  default:
599  break;
600  }
601  } break;
602  case DATA_REACTIVE_POWER: {
603  m_choiceTextType->SetSelection(2);
604  switch(m_text->GetUnit()) {
605  case UNIT_PU: {
606  m_choiceTextUnit->SetSelection(0);
607  } break;
608  case UNIT_VAr: {
609  m_choiceTextUnit->SetSelection(1);
610  } break;
611  case UNIT_kVAr: {
612  m_choiceTextUnit->SetSelection(2);
613  } break;
614  case UNIT_MVAr: {
615  m_choiceTextUnit->SetSelection(3);
616  } break;
617  default:
618  break;
619  }
620  } break;
621  default:
622  break;
623  }
624  } break;
625  case TYPE_CAPACITOR: {
626  m_choiceElement->SetSelection(5);
627  switch(m_text->GetDataType()) {
628  case DATA_NAME: {
629  m_choiceTextType->SetSelection(0);
630  } break;
631  case DATA_REACTIVE_POWER: {
632  m_choiceTextType->SetSelection(1);
633 
634  } break;
635  default:
636  break;
637  }
638  } break;
639  case TYPE_INDUCTOR: {
640  m_choiceElement->SetSelection(6);
641  switch(m_text->GetDataType()) {
642  case DATA_NAME: {
643  m_choiceTextType->SetSelection(0);
644  } break;
645  case DATA_REACTIVE_POWER: {
646  m_choiceTextType->SetSelection(1);
647  switch(m_text->GetUnit()) {
648  case UNIT_PU: {
649  m_choiceTextUnit->SetSelection(0);
650  } break;
651  case UNIT_VAr: {
652  m_choiceTextUnit->SetSelection(1);
653  } break;
654  case UNIT_kVAr: {
655  m_choiceTextUnit->SetSelection(2);
656  } break;
657  case UNIT_MVAr: {
658  m_choiceTextUnit->SetSelection(3);
659  } break;
660  default:
661  break;
662  }
663  } break;
664  default:
665  break;
666  }
667  } break;
668  case TYPE_SYNC_MOTOR: {
669  m_choiceElement->SetSelection(7);
670  switch(m_text->GetDataType()) {
671  case DATA_NAME: {
672  m_choiceTextType->SetSelection(0);
673  } break;
674  case DATA_ACTIVE_POWER: {
675  m_choiceTextType->SetSelection(1);
676  switch(m_text->GetUnit()) {
677  case UNIT_PU: {
678  m_choiceTextUnit->SetSelection(0);
679  } break;
680  case UNIT_W: {
681  m_choiceTextUnit->SetSelection(1);
682  } break;
683  case UNIT_kW: {
684  m_choiceTextUnit->SetSelection(2);
685  } break;
686  case UNIT_MW: {
687  m_choiceTextUnit->SetSelection(3);
688  } break;
689  default:
690  break;
691  }
692  } break;
693  case DATA_REACTIVE_POWER: {
694  m_choiceTextType->SetSelection(2);
695  switch(m_text->GetUnit()) {
696  case UNIT_PU: {
697  m_choiceTextUnit->SetSelection(0);
698  } break;
699  case UNIT_VAr: {
700  m_choiceTextUnit->SetSelection(1);
701  } break;
702  case UNIT_kVAr: {
703  m_choiceTextUnit->SetSelection(2);
704  } break;
705  case UNIT_MVAr: {
706  m_choiceTextUnit->SetSelection(3);
707  } break;
708  default:
709  break;
710  }
711  } break;
712  default:
713  break;
714  }
715  } break;
716  case TYPE_IND_MOTOR: {
717  m_choiceElement->SetSelection(8);
718  switch(m_text->GetDataType()) {
719  case DATA_NAME: {
720  m_choiceTextType->SetSelection(0);
721  } break;
722  case DATA_ACTIVE_POWER: {
723  m_choiceTextType->SetSelection(1);
724  switch(m_text->GetUnit()) {
725  case UNIT_PU: {
726  m_choiceTextUnit->SetSelection(0);
727  } break;
728  case UNIT_W: {
729  m_choiceTextUnit->SetSelection(1);
730  } break;
731  case UNIT_kW: {
732  m_choiceTextUnit->SetSelection(2);
733  } break;
734  case UNIT_MW: {
735  m_choiceTextUnit->SetSelection(3);
736  } break;
737  default:
738  break;
739  }
740  } break;
741  case DATA_REACTIVE_POWER: {
742  m_choiceTextType->SetSelection(2);
743  switch(m_text->GetUnit()) {
744  case UNIT_PU: {
745  m_choiceTextUnit->SetSelection(0);
746  } break;
747  case UNIT_VAr: {
748  m_choiceTextUnit->SetSelection(1);
749  } break;
750  case UNIT_kVAr: {
751  m_choiceTextUnit->SetSelection(2);
752  } break;
753  case UNIT_MVAr: {
754  m_choiceTextUnit->SetSelection(3);
755  } break;
756  default:
757  break;
758  }
759  } break;
760  default:
761  break;
762  }
763  } break;
764  default:
765  break;
766  }
767 
768  if(m_choiceTextFromBus->IsEnabled()) m_choiceTextFromBus->SetSelection(m_text->GetDirection());
769  if(m_choiceTextToBus->IsEnabled()) m_choiceTextToBus->SetSelection(m_text->GetDirection());
770 
771  m_textCtrlDecimal->SetValue(wxString::Format("%d", m_text->GetDecimalPlaces()));
772  Preview();
773 
774  return true;
775 }
776 
777 void TextForm::ElementTypeChoice()
778 {
779  m_choiceTextType->Enable(false);
780  m_choiceTextFromBus->Enable(false);
781  m_choiceTextToBus->Enable(false);
782  m_choiceTextUnit->Enable(false);
783  m_choiceTextType->Clear();
784  m_choiceTextFromBus->Clear();
785  m_choiceTextToBus->Clear();
786  m_choiceTextUnit->Clear();
787 
788  m_choiceName->Clear();
789  wxArrayString arrayString;
790  switch(m_text->GetElementType()) {
791  case TYPE_BUS: {
792  for(int i = 0; i < (int)m_allElements.GetBusList().size(); i++) {
793  Bus* bus = m_allElements.GetBusList()[i];
794  arrayString.Add(bus->GetElectricalData().name);
795  }
796  } break;
797  case TYPE_SYNC_GENERATOR: {
798  for(int i = 0; i < (int)m_allElements.GetSyncGeneratorList().size(); i++) {
799  SyncGenerator* syncGenerator = m_allElements.GetSyncGeneratorList()[i];
800  arrayString.Add(syncGenerator->GetElectricalData().name);
801  }
802  } break;
803  case TYPE_LINE: {
804  for(int i = 0; i < (int)m_allElements.GetLineList().size(); i++) {
805  Line* line = m_allElements.GetLineList()[i];
806  arrayString.Add(line->GetElectricalData().name);
807  }
808  } break;
809  case TYPE_TRANSFORMER: {
810  for(int i = 0; i < (int)m_allElements.GetTransformerList().size(); i++) {
811  Transformer* transformer = m_allElements.GetTransformerList()[i];
812  arrayString.Add(transformer->GetElectricalData().name);
813  }
814  } break;
815  case TYPE_LOAD: {
816  for(int i = 0; i < (int)m_allElements.GetLoadList().size(); i++) {
817  Load* load = m_allElements.GetLoadList()[i];
818  arrayString.Add(load->GetElectricalData().name);
819  }
820  } break;
821  case TYPE_CAPACITOR: {
822  for(int i = 0; i < (int)m_allElements.GetCapacitorList().size(); i++) {
823  Capacitor* capacitor = m_allElements.GetCapacitorList()[i];
824  arrayString.Add(capacitor->GetElectricalData().name);
825  }
826  } break;
827  case TYPE_INDUCTOR: {
828  for(int i = 0; i < (int)m_allElements.GetInductorList().size(); i++) {
829  Inductor* inductor = m_allElements.GetInductorList()[i];
830  arrayString.Add(inductor->GetElectricalData().name);
831  }
832  } break;
833  case TYPE_SYNC_MOTOR: {
834  for(int i = 0; i < (int)m_allElements.GetSyncMotorList().size(); i++) {
835  SyncMotor* syncMotor = m_allElements.GetSyncMotorList()[i];
836  arrayString.Add(syncMotor->GetElectricalData().name);
837  }
838  } break;
839  case TYPE_IND_MOTOR: {
840  for(int i = 0; i < (int)m_allElements.GetIndMotorList().size(); i++) {
841  IndMotor* indMotor = m_allElements.GetIndMotorList()[i];
842  arrayString.Add(indMotor->GetElectricalData().name);
843  }
844  } break;
845 
846  default:
847  break;
848  }
849  m_choiceName->Append(arrayString);
850  m_choiceName->Enable();
851 }
852 
853 void TextForm::ElementNumberChoice()
854 {
855  m_choiceTextFromBus->Enable(false);
856  m_choiceTextToBus->Enable(false);
857  m_choiceTextUnit->Enable(false);
858  m_choiceTextFromBus->Clear();
859  m_choiceTextToBus->Clear();
860  m_choiceTextUnit->Clear();
861 
862  int index = m_choiceName->GetSelection();
863  m_text->SetElementNumber(index);
864 
865  m_choiceTextType->Clear();
866  wxArrayString arrayString;
867  switch(m_text->GetElementType()) {
868  case TYPE_BUS: {
869  Bus* bus = m_allElements.GetBusList()[index];
870  m_text->SetElement(bus);
871 
872  arrayString.Add(_("Name"));
873  arrayString.Add(_("Voltage"));
874  arrayString.Add(_("Angle"));
875  arrayString.Add(_("Fault current"));
876  arrayString.Add(_("Fault voltage"));
877  arrayString.Add(_("Short-circuit power"));
878  } break;
879  case TYPE_SYNC_GENERATOR: {
880  SyncGenerator* syncGenerator = m_allElements.GetSyncGeneratorList()[index];
881  m_text->SetElement(syncGenerator);
882 
883  arrayString.Add(_("Name"));
884  arrayString.Add(_("Active power"));
885  arrayString.Add(_("Reactive power"));
886  arrayString.Add(_("Fault current"));
887  } break;
888  case TYPE_LINE: {
889  Line* line = m_allElements.GetLineList()[index];
890  m_text->SetElement(line);
891 
892  arrayString.Add(_("Name"));
893  arrayString.Add(_("Active power flow"));
894  arrayString.Add(_("Reactive power flow"));
895  arrayString.Add(_("Losses"));
896  arrayString.Add(_("Current"));
897  arrayString.Add(_("Fault current"));
898  } break;
899  case TYPE_TRANSFORMER: {
900  Transformer* transformer = m_allElements.GetTransformerList()[index];
901  m_text->SetElement(transformer);
902 
903  arrayString.Add(_("Name"));
904  arrayString.Add(_("Active power flow"));
905  arrayString.Add(_("Reactive power flow"));
906  arrayString.Add(_("Losses"));
907  arrayString.Add(_("Current"));
908  arrayString.Add(_("Fault current"));
909  } break;
910  case TYPE_LOAD: {
911  Load* load = m_allElements.GetLoadList()[index];
912  m_text->SetElement(load);
913 
914  arrayString.Add(_("Name"));
915  arrayString.Add(_("Active power"));
916  arrayString.Add(_("Reactive power"));
917  } break;
918  case TYPE_CAPACITOR: {
919  Capacitor* capacitor = m_allElements.GetCapacitorList()[index];
920  m_text->SetElement(capacitor);
921 
922  arrayString.Add(_("Name"));
923  arrayString.Add(_("Reactive power"));
924  } break;
925  case TYPE_INDUCTOR: {
926  Inductor* inductor = m_allElements.GetInductorList()[index];
927  m_text->SetElement(inductor);
928 
929  arrayString.Add(_("Name"));
930  arrayString.Add(_("Reactive power"));
931  } break;
932  case TYPE_SYNC_MOTOR: {
933  SyncMotor* syncMotor = m_allElements.GetSyncMotorList()[index];
934  m_text->SetElement(syncMotor);
935 
936  arrayString.Add(_("Name"));
937  arrayString.Add(_("Active power"));
938  arrayString.Add(_("Reactive power"));
939  } break;
940  case TYPE_IND_MOTOR: {
941  IndMotor* indMotor = m_allElements.GetIndMotorList()[index];
942  m_text->SetElement(indMotor);
943 
944  arrayString.Add(_("Name"));
945  arrayString.Add(_("Active power"));
946  arrayString.Add(_("Reactive power"));
947  } break;
948 
949  default:
950  break;
951  }
952  m_choiceTextType->Append(arrayString);
953  m_choiceTextType->Enable();
954 }
955 
956 void TextForm::DataTypeChoice()
957 {
958  m_choiceTextFromBus->Enable(false);
959  m_choiceTextToBus->Enable(false);
960 
961  m_choiceTextToBus->Clear();
962  m_choiceTextFromBus->Clear();
963  m_choiceTextUnit->Clear();
964 
965  m_choiceTextUnit->Enable();
966 
967  wxArrayString arrayString;
968  switch(m_text->GetDataType()) {
969  case DATA_NAME: {
970  m_choiceTextUnit->Enable(false);
971  return;
972  } break;
973  case DATA_VOLTAGE:
974  case DATA_SC_VOLTAGE: {
975  arrayString.Add(_("p.u."));
976  arrayString.Add(_("V"));
977  arrayString.Add(_("kV"));
978  } break;
979  case DATA_ANGLE: {
980  arrayString.Add(_("Degrees"));
981  arrayString.Add(_("Radians"));
982  } break;
983  case DATA_SC_CURRENT:
984  case DATA_PF_CURRENT: {
985  arrayString.Add(_("p.u."));
986  arrayString.Add(_("A"));
987  arrayString.Add(_("kA"));
988  } break;
989  case DATA_SC_POWER: {
990  arrayString.Add(_("p.u."));
991  arrayString.Add(_("VA"));
992  arrayString.Add(_("kVA"));
993  arrayString.Add(_("MVA"));
994  } break;
995  case DATA_ACTIVE_POWER:
996  case DATA_PF_ACTIVE:
997  case DATA_PF_LOSSES: {
998  arrayString.Add(_("p.u."));
999  arrayString.Add(_("W"));
1000  arrayString.Add(_("kW"));
1001  arrayString.Add(_("MW"));
1002  m_choiceTextUnit->Enable();
1003  } break;
1004  case DATA_REACTIVE_POWER:
1005  case DATA_PF_REACTIVE: {
1006  arrayString.Add(_("p.u."));
1007  arrayString.Add(_("VAr"));
1008  arrayString.Add(_("kVAr"));
1009  arrayString.Add(_("MVAr"));
1010  } break;
1011  default:
1012  break;
1013  }
1014  m_choiceTextUnit->Append(arrayString);
1015 
1016  switch(m_text->GetElementType()) {
1017  case TYPE_LINE: {
1018  if(m_text->GetDataType() != DATA_PF_LOSSES) {
1019  auto it = m_allElements.GetLineList().begin();
1020  std::advance(it, m_text->GetElementNumber());
1021  Line* line = *it;
1022 
1023  Bus* bus1 = static_cast<Bus*>(line->GetParentList()[0]);
1024  Bus* bus2 = static_cast<Bus*>(line->GetParentList()[1]);
1025  wxString bus1Name = bus1->GetElectricalData().name;
1026  wxString bus2Name = bus2->GetElectricalData().name;
1027 
1028  m_choiceTextFromBus->Append(bus1Name);
1029  m_choiceTextFromBus->Append(bus2Name);
1030  m_choiceTextToBus->Append(bus2Name);
1031  m_choiceTextToBus->Append(bus1Name);
1032  m_choiceTextFromBus->SetSelection(0);
1033  m_choiceTextToBus->SetSelection(0);
1034 
1035  m_choiceTextFromBus->Enable();
1036  m_choiceTextToBus->Enable();
1037  }
1038  } break;
1039  case TYPE_TRANSFORMER: {
1040  if(m_text->GetDataType() != DATA_PF_LOSSES) {
1041  auto it = m_allElements.GetTransformerList().begin();
1042  std::advance(it, m_text->GetElementNumber());
1043  Transformer* transformer = *it;
1044 
1045  Bus* bus1 = static_cast<Bus*>(transformer->GetParentList()[0]);
1046  Bus* bus2 = static_cast<Bus*>(transformer->GetParentList()[1]);
1047  wxString bus1Name = bus1->GetElectricalData().name;
1048  wxString bus2Name = bus2->GetElectricalData().name;
1049 
1050  m_choiceTextFromBus->Append(bus1Name);
1051  m_choiceTextFromBus->Append(bus2Name);
1052  m_choiceTextToBus->Append(bus2Name);
1053  m_choiceTextToBus->Append(bus1Name);
1054  m_choiceTextFromBus->SetSelection(0);
1055  m_choiceTextToBus->SetSelection(0);
1056 
1057  m_choiceTextFromBus->Enable();
1058  m_choiceTextToBus->Enable();
1059  }
1060  } break;
1061  default:
1062  break;
1063  }
1064 }
1065 
1066 void TextForm::UnitChoice()
1067 {
1068  switch(m_text->GetDataType()) {
1069  case DATA_NAME: {
1070  m_choiceTextUnit->Enable(false);
1071  return;
1072  } break;
1073  case DATA_VOLTAGE:
1074  case DATA_SC_VOLTAGE: {
1075  switch(m_choiceTextUnit->GetSelection()) {
1076  case 0: {
1077  m_text->SetUnit(UNIT_PU);
1078  } break;
1079  case 1: {
1080  m_text->SetUnit(UNIT_V);
1081  } break;
1082  case 2: {
1083  m_text->SetUnit(UNIT_kV);
1084  } break;
1085  default:
1086  break;
1087  }
1088  } break;
1089  case DATA_ANGLE: {
1090  switch(m_choiceTextUnit->GetSelection()) {
1091  case 0: {
1092  m_text->SetUnit(UNIT_DEGREE);
1093  } break;
1094  case 1: {
1095  m_text->SetUnit(UNIT_RADIAN);
1096  } break;
1097  default:
1098  break;
1099  }
1100  } break;
1101  case DATA_SC_CURRENT:
1102  case DATA_PF_CURRENT: {
1103  switch(m_choiceTextUnit->GetSelection()) {
1104  case 0: {
1105  m_text->SetUnit(UNIT_PU);
1106  } break;
1107  case 1: {
1108  m_text->SetUnit(UNIT_A);
1109  } break;
1110  case 2: {
1111  m_text->SetUnit(UNIT_kA);
1112  } break;
1113  default:
1114  break;
1115  }
1116  } break;
1117  case DATA_SC_POWER: {
1118  switch(m_choiceTextUnit->GetSelection()) {
1119  case 0: {
1120  m_text->SetUnit(UNIT_PU);
1121  } break;
1122  case 1: {
1123  m_text->SetUnit(UNIT_VA);
1124  } break;
1125  case 2: {
1126  m_text->SetUnit(UNIT_kVA);
1127  } break;
1128  case 3: {
1129  m_text->SetUnit(UNIT_MVA);
1130  } break;
1131  default:
1132  break;
1133  }
1134  } break;
1135  case DATA_ACTIVE_POWER:
1136  case DATA_PF_ACTIVE:
1137  case DATA_PF_LOSSES: {
1138  switch(m_choiceTextUnit->GetSelection()) {
1139  case 0: {
1140  m_text->SetUnit(UNIT_PU);
1141  } break;
1142  case 1: {
1143  m_text->SetUnit(UNIT_W);
1144  } break;
1145  case 2: {
1146  m_text->SetUnit(UNIT_kW);
1147  } break;
1148  case 3: {
1149  m_text->SetUnit(UNIT_MW);
1150  } break;
1151  default:
1152  break;
1153  }
1154  } break;
1155  case DATA_REACTIVE_POWER:
1156  case DATA_PF_REACTIVE: {
1157  switch(m_choiceTextUnit->GetSelection()) {
1158  case 0: {
1159  m_text->SetUnit(UNIT_PU);
1160  } break;
1161  case 1: {
1162  m_text->SetUnit(UNIT_VAr);
1163  } break;
1164  case 2: {
1165  m_text->SetUnit(UNIT_kVAr);
1166  } break;
1167  case 3: {
1168  m_text->SetUnit(UNIT_MVAr);
1169  } break;
1170  default:
1171  break;
1172  }
1173  } break;
1174  default:
1175  break;
1176  }
1177 }
1178 
1179 void TextForm::Preview()
1180 {
1181  double decimalPlaces = m_text->GetDecimalPlaces();
1182  if(m_textCtrlDecimal->GetValue().ToDouble(&decimalPlaces)) m_text->SetDecimalPlaces(decimalPlaces);
1183 
1184  m_text->UpdateText(m_systemPowerBase);
1185 
1186  m_textCtrlPreview->SetValue(m_text->GetText());
1187 }
1188 
1189 bool TextForm::ValidateData()
1190 {
1191  if(m_choiceElement->GetSelection() == -1) return false;
1192  if(m_choiceName->GetSelection() == -1) return false;
1193  if(m_choiceTextType->GetSelection() == -1) return false;
1194  if(m_text->GetDataType() != DATA_NAME && m_choiceTextUnit->GetSelection() == -1) return false;
1195  if(m_text->GetElementType() == TYPE_LINE || m_text->GetElementType() == TYPE_TRANSFORMER) {
1196  if(m_text->GetDataType() != DATA_PF_LOSSES && m_text->GetDataType() != DATA_NAME) {
1197  if(m_choiceTextFromBus->GetSelection() == -1) return false;
1198  if(m_choiceTextToBus->GetSelection() == -1) return false;
1199  }
1200  }
1201 
1202  if(m_choiceTextFromBus->IsEnabled() && m_choiceTextToBus->IsEnabled())
1203  m_text->SetDirection(m_choiceTextFromBus->GetSelection());
1204  double decimalPlaces = m_text->GetDecimalPlaces();
1205  if(m_textCtrlDecimal->GetValue().ToDouble(&decimalPlaces)) m_text->SetDecimalPlaces(decimalPlaces);
1206 
1207  m_textToEdit->SetElementType(m_text->GetElementType());
1208  m_textToEdit->SetElementNumber(m_text->GetElementNumber());
1209  m_textToEdit->SetElement(m_text->GetElement());
1210  m_textToEdit->SetDataType(m_text->GetDataType());
1211  m_textToEdit->SetDirection(m_text->GetDirection());
1212  m_textToEdit->SetUnit(m_text->GetUnit());
1213  m_textToEdit->SetDecimalPlaces(decimalPlaces);
1214  m_textToEdit->UpdateText(m_systemPowerBase);
1215 
1216  return true;
1217 }
1218 
1219 void TextForm::OnOKButtonClick(wxCommandEvent& event)
1220 {
1221  if(ValidateData()) {
1222  EndModal(wxID_OK);
1223  } else {
1224  wxString errorMsg = _("There are blank fields.");
1225  wxMessageDialog msgDialog(this, errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1226  msgDialog.ShowModal();
1227  }
1228 }
Element that shows power element informations in workspace.
Definition: Text.h:72
- +
Synchronous generator power element.
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
-
Definition: Line.h:52
-
Definition: Load.h:35
+
Power line element.
Definition: Line.h:59
+
Loas shunt power element.
Definition: Load.h:42
- - +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
Induction motor power element.
Definition: IndMotor.h:40
- - +
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_text_form_8h.html b/docs/doxygen/html/_text_form_8h.html index 3914266..b198318 100644 --- a/docs/doxygen/html/_text_form_8h.html +++ b/docs/doxygen/html/_text_form_8h.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_text_form_8h.html','');});
#include "ElementForm.h"
-#include "Text.h"
+#include "Text.h"
#include "ElectricCalculation.h"

Go to the source code of this file.

diff --git a/docs/doxygen/html/_text_form_8h_source.html b/docs/doxygen/html/_text_form_8h_source.html index 140e411..fa0168c 100644 --- a/docs/doxygen/html/_text_form_8h_source.html +++ b/docs/doxygen/html/_text_form_8h_source.html @@ -88,10 +88,11 @@ $(document).ready(function(){initNavTree('_text_form_8h_source.html','');});
TextForm.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TEXTFORM_H
19 #define TEXTFORM_H
20 #include "ElementForm.h"
21 
22 #include "Text.h"
23 #include "ElectricCalculation.h"
24 
32 class TextForm : public TextFormBase
33 {
34  public:
35  TextForm(wxWindow* parent, Text* text, std::vector<Element*> elementList, double systemPowerBase = 100e6);
36  virtual ~TextForm();
37 
38  virtual bool LoadChoices();
39 
40  virtual void ElementTypeChoice();
41  virtual void ElementNumberChoice();
42  virtual void DataTypeChoice();
43  virtual void UnitChoice();
44 
45  virtual void Preview();
46  virtual bool ValidateData();
47 
48  protected:
49  virtual void OnUnitChoiceSelected(wxCommandEvent& event);
50  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
51  virtual void OnOKButtonClick(wxCommandEvent& event);
52  virtual void OnElementChoiceSelected(wxCommandEvent& event);
53  virtual void OnFromBusChoiceSelected(wxCommandEvent& event);
54  virtual void OnNameChoiceSelected(wxCommandEvent& event);
55  virtual void OnTextEnter(wxCommandEvent& event);
56  virtual void OnToBusChoiceSelected(wxCommandEvent& event);
57  virtual void OnTypeChoiceSelected(wxCommandEvent& event);
58 
59  Text* m_text = NULL;
60  Text* m_textToEdit = NULL;
61  wxWindow* m_parent = NULL;
62  ElectricCalculation m_allElements;
63  double m_systemPowerBase;
64 };
65 #endif // TEXTFORM_H
Definition: Text.h:65
-
Base class of electric calculations, with general methods.
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TEXTFORM_H
19 #define TEXTFORM_H
20 #include "ElementForm.h"
21 
22 #include "Text.h"
23 #include "ElectricCalculation.h"
24 
32 class TextForm : public TextFormBase
33 {
34  public:
35  TextForm(wxWindow* parent, Text* text, std::vector<Element*> elementList, double systemPowerBase = 100e6);
36  virtual ~TextForm();
37 
38  virtual bool LoadChoices();
39 
40  virtual void ElementTypeChoice();
41  virtual void ElementNumberChoice();
42  virtual void DataTypeChoice();
43  virtual void UnitChoice();
44 
45  virtual void Preview();
46  virtual bool ValidateData();
47 
48  protected:
49  virtual void OnUnitChoiceSelected(wxCommandEvent& event);
50  virtual void OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
51  virtual void OnOKButtonClick(wxCommandEvent& event);
52  virtual void OnElementChoiceSelected(wxCommandEvent& event);
53  virtual void OnFromBusChoiceSelected(wxCommandEvent& event);
54  virtual void OnNameChoiceSelected(wxCommandEvent& event);
55  virtual void OnTextEnter(wxCommandEvent& event);
56  virtual void OnToBusChoiceSelected(wxCommandEvent& event);
57  virtual void OnTypeChoiceSelected(wxCommandEvent& event);
58 
59  Text* m_text = NULL;
60  Text* m_textToEdit = NULL;
61  wxWindow* m_parent = NULL;
62  ElectricCalculation m_allElements;
63  double m_systemPowerBase;
64 };
65 #endif // TEXTFORM_H
Element that shows power element informations in workspace.
Definition: Text.h:72
+
Form to edit the text graphical data.
Definition: TextForm.h:32
- + +
Base class of electric calculations, with general methods.
diff --git a/docs/doxygen/html/_transfer_function_8cpp_source.html b/docs/doxygen/html/_transfer_function_8cpp_source.html index 6de1a4b..ea4db24 100644 --- a/docs/doxygen/html/_transfer_function_8cpp_source.html +++ b/docs/doxygen/html/_transfer_function_8cpp_source.html @@ -88,17 +88,20 @@ $(document).ready(function(){initNavTree('_transfer_function_8cpp_source.html','
TransferFunction.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransferFunction.h"
19 #include "TransferFunctionForm.h"
20 
21 TransferFunction::TransferFunction(int id) : ControlElement(id)
22 {
23  // Superscript unicode numbers
24  m_supNumber[0] = L'\u2070';
25  m_supNumber[1] = L'\u00B9';
26  m_supNumber[2] = L'\u00B2';
27  m_supNumber[3] = L'\u00B3';
28  m_supNumber[4] = L'\u2074';
29  m_supNumber[5] = L'\u2075';
30  m_supNumber[6] = L'\u2076';
31  m_supNumber[7] = L'\u2077';
32  m_supNumber[8] = L'\u2078';
33  m_supNumber[9] = L'\u2079';
34 
35  m_numerator.clear();
36  m_numerator.push_back(1);
37  m_denominator.clear();
38  m_denominator.push_back(1);
39  m_denominator.push_back(1);
40  UpdateTFText();
41 
42  Node* node1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize);
43  node1->StartMove(m_position);
44  Node* node2 = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
45  node2->SetAngle(180.0);
46  node2->StartMove(m_position);
47  m_nodeList.push_back(node1);
48  m_nodeList.push_back(node2);
49 }
50 
51 TransferFunction::~TransferFunction() {}
52 void TransferFunction::Draw(wxPoint2DDouble translation, double scale) const
53 {
54  glLineWidth(1.0);
55  if(m_selected) {
56  glColor4dv(m_selectionColour.GetRGBA());
57  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
58  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
59  }
60  glColor4d(1.0, 1.0, 1.0, 1.0);
61  DrawRectangle(m_position, m_width, m_height);
62  glColor4d(0.0, 0.0, 0.0, 1.0);
63  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
64 
65  std::vector<wxPoint2DDouble> linePts;
66  linePts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2 + 5 + m_borderSize, m_position.m_y));
67  linePts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2 - 5 - m_borderSize, m_position.m_y));
68  DrawLine(linePts);
69 
70  DrawNodes();
71 
72  glEnable(GL_TEXTURE_2D);
73  glColor4d(0.0, 0.0, 0.0, 1.0);
74  m_glStringNum->bind();
75  m_glStringNum->render(m_position.m_x, m_position.m_y - m_height / 4);
76  m_glStringDen->bind();
77  m_glStringDen->render(m_position.m_x, m_position.m_y + m_height / 4);
78  glDisable(GL_TEXTURE_2D);
79 }
80 
81 void TransferFunction::SetText(wxString numerator, wxString denominator)
82 {
83  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
84  wxScreenDC dc;
85 
86  if(m_glStringNum) {
87  delete m_glStringNum;
88  m_glStringNum = NULL;
89  }
90  m_glStringNum = new wxGLString(numerator);
91  m_glStringNum->setFont(font);
92  m_glStringNum->consolidate(&dc);
93 
94  if(m_glStringDen) {
95  delete m_glStringDen;
96  m_glStringDen = NULL;
97  }
98  m_glStringDen = new wxGLString(denominator);
99  m_glStringDen->setFont(font);
100  m_glStringDen->consolidate(&dc);
101 
102  double nWidth = m_glStringNum->getWidth() + 5 + m_borderSize;
103  double dWidth = m_glStringDen->getWidth() + 5 + m_borderSize;
104 
105  m_width = nWidth > dWidth ? nWidth : dWidth;
106  m_height = m_glStringNum->getheight() + m_glStringDen->getheight() + 2 * m_borderSize;
107  SetPosition(m_position); // Update rect properly.
108 }
109 
110 wxString TransferFunction::GetSuperscriptNumber(int number)
111 {
112  wxString strNumber = wxString::Format("%d", number);
113  wxString superscriptStr = "";
114  for(int i = 0; i < (int)strNumber.length(); ++i) {
115  wxString digitStr = strNumber[i];
116  long digit = 0;
117  digitStr.ToLong(&digit);
118  superscriptStr += wxString(m_supNumber[digit]);
119  }
120  return superscriptStr;
121 }
122 
123 void TransferFunction::GetTFString(wxString& numerator, wxString& denominator)
124 {
125  numerator = "";
126  denominator = "";
127  int index = static_cast<int>(m_numerator.size()) - 1;
128  for(auto it = m_numerator.begin(), itEnd = m_numerator.end(); it != itEnd; ++it) {
129  double value = *it;
130  if(value != 0.0) {
131  wxString signal;
132  if(index == static_cast<int>(m_numerator.size()) - 1) {
133  if(value >= 0.0)
134  signal += "";
135  else
136  signal += "-";
137  } else {
138  if(value >= 0.0)
139  signal += "+ ";
140  else
141  signal += "- ";
142  }
143 
144  if(index == 0) {
145  numerator += signal + StringFromDouble(std::abs(value), 0);
146  break;
147  } else if(index == 1) {
148  if(value == 1.0) {
149  numerator += signal + "s";
150  } else {
151  numerator += signal + StringFromDouble(std::abs(value), 0) + "s";
152  }
153  } else {
154  if(value == 1.0) {
155  numerator += signal + "s" + GetSuperscriptNumber(index);
156  } else {
157  numerator += signal + StringFromDouble(std::abs(value), 0) + "s" + GetSuperscriptNumber(index);
158  }
159  }
160  numerator += " ";
161  }
162  --index;
163  }
164 
165  index = static_cast<int>(m_denominator.size()) - 1;
166  for(auto it = m_denominator.begin(), itEnd = m_denominator.end(); it != itEnd; ++it) {
167  double value = *it;
168  if(value != 0.0) {
169  wxString signal;
170  if(index == static_cast<int>(m_denominator.size()) - 1) {
171  if(value >= 0.0)
172  signal += "";
173  else
174  signal += "-";
175  } else {
176  if(value >= 0.0)
177  signal += "+ ";
178  else
179  signal += "- ";
180  }
181 
182  if(index == 0) {
183  denominator += signal + StringFromDouble(std::abs(value), 0);
184  break;
185  } else if(index == 1) {
186  if(value == 1.0) {
187  denominator += signal + "s";
188  } else {
189  denominator += signal + StringFromDouble(std::abs(value), 0) + "s";
190  }
191  } else {
192  if(value == 1.0) {
193  denominator += signal + "s" + GetSuperscriptNumber(index);
194  } else {
195  denominator += signal + StringFromDouble(std::abs(value), 0) + "s" + GetSuperscriptNumber(index);
196  }
197  }
198  denominator += " ";
199  }
200  --index;
201  }
202 }
203 
204 void TransferFunction::UpdateTFText()
205 {
206  wxString num, den;
207  GetTFString(num, den);
208  SetText(num, den);
209  if(m_nodeList.size() == 2) {
210  if(m_angle == 0.0) {
211  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
212  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
213  } else if(m_angle == 90.0) {
214  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
215  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
216  } else if(m_angle == 180.0) {
217  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
218  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
219  } else if(m_angle == 270.0) {
220  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
221  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
222  }
223  }
224 }
225 
226 bool TransferFunction::ShowForm(wxWindow* parent, Element* element)
227 {
228  TransferFunctionForm* tfForm = new TransferFunctionForm(parent, this);
229  if(tfForm->ShowModal() == wxID_OK) {
230  tfForm->Destroy();
231  return true;
232  }
233  tfForm->Destroy();
234  return false;
235 }
236 
237 void TransferFunction::Rotate(bool clockwise)
238 {
239  if(clockwise)
240  m_angle += 90.0;
241  else
242  m_angle -= 90.0;
243  if(m_angle >= 360.0)
244  m_angle = 0.0;
245  else if(m_angle < 0)
246  m_angle = 270.0;
247 
248  if(m_angle == 0.0) {
249  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
250  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
251  } else if(m_angle == 90.0) {
252  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
253  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
254  } else if(m_angle == 180.0) {
255  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
256  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
257  } else if(m_angle == 270.0) {
258  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
259  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
260  }
261 
262  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
263  Node* node = *it;
264  node->Rotate(clockwise);
265  }
266 }
267 
268 void TransferFunction::CalculateSpaceState(int maxIteration, double error)
269 {
270  m_maxIteration = maxIteration;
271  m_error = error;
272 
273  int order = static_cast<int>(m_denominator.size());
274  std::vector<double> denominator = m_denominator;
275  std::vector<double> numerator;
276 
277  int k = order;
278  for(int i = 0; i < order; i++) {
279  int numIndex = i - (order - static_cast<int>(m_numerator.size()));
280  if(numIndex < 0)
281  numerator.push_back(0.0);
282  else
283  numerator.push_back(m_numerator[numIndex]);
284  k--;
285  }
286 
287  SpaceState ss;
288  for(int i = 0; i < (order - 1); i++) {
289  std::vector<double> lineA;
290  for(int j = 0; j < (order - 1); j++) {
291  if(j == i + 1)
292  lineA.push_back(1.0);
293  else
294  lineA.push_back(0.0);
295  }
296  ss.A.push_back(lineA);
297  ss.B.push_back(0.0);
298  ss.C.push_back(0.0);
299  }
300  for(int i = 0; i < order - 1; i++) {
301  ss.A[order - 2][i] = -(denominator[order - 1 - i] / denominator[0]);
302  ss.C[i] = (numerator[order - 1 - i] - denominator[order - 1 - i] * numerator[0]) / denominator[0];
303  }
304  ss.B[order - 2] = 1.0;
305  ss.D = numerator[0];
306 
307  m_ss = ss;
308 
309  // Reset state
310  m_x.clear();
311  m_dx.clear();
312 
313  for(unsigned int i = 0; i < m_denominator.size(); ++i) {
314  m_x.push_back(0.0);
315  m_dx.push_back(0.0);
316  }
317 }
318 
319 bool TransferFunction::Solve(double input, double timeStep)
320 {
321  int order = static_cast<int>(m_ss.A.size());
322 
323  std::vector<double> x;
324  std::vector<double> oldx;
325  std::vector<double> dx;
326  std::vector<double> olddx;
327  for(int i = 0; i < order; i++) {
328  x.push_back(m_x[i]);
329  oldx.push_back(m_x[i]);
330 
331  dx.push_back(m_dx[i]);
332  olddx.push_back(m_dx[i]);
333  }
334 
335  bool exit = false;
336  int iter = 0;
337  while(!exit) {
338  double xError = 0.0;
339  double dxError = 0.0;
340  for(int i = 0; i < order; i++) {
341  // Trapezoidal method
342  x[i] = m_x[i] + 0.5 * timeStep * (m_dx[i] + dx[i]);
343 
344  if(std::abs(x[i] - oldx[i]) > xError) xError = std::abs(x[i] - oldx[i]);
345 
346  oldx[i] = x[i];
347  }
348  for(int i = 0; i < order; i++) {
349  // x' = Ax + Bu
350  dx[i] = 0.0;
351  for(int j = 0; j < order; j++) dx[i] += m_ss.A[i][j] * x[j];
352  dx[i] += m_ss.B[i] * input;
353 
354  if(std::abs(dx[i] - olddx[i]) > dxError) dxError = std::abs(dx[i] - olddx[i]);
355 
356  olddx[i] = dx[i];
357  }
358  if(std::max(xError, dxError) < m_error) exit = true;
359 
360  iter++;
361  if(iter >= m_maxIteration) return false;
362  }
363 
364  m_output = 0.0;
365  for(int i = 0; i < order; i++) {
366  m_output += m_ss.C[i] * x[i];
367  m_x[i] = x[i];
368  m_dx[i] = dx[i];
369  }
370 
371  m_output += m_ss.D * input;
372 
373  return true;
374 }
375 
377 {
378  TransferFunction* copy = new TransferFunction(m_elementID);
379  *copy = *this;
380  m_glStringNum = NULL;
381  m_glStringDen = NULL;
382  UpdateTFText();
383  return copy;
384 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransferFunction.h"
19 #include "TransferFunctionForm.h"
20 
21 TransferFunction::TransferFunction(int id) : ControlElement(id)
22 {
23  // Superscript unicode numbers
24  m_supNumber[0] = L'\u2070';
25  m_supNumber[1] = L'\u00B9';
26  m_supNumber[2] = L'\u00B2';
27  m_supNumber[3] = L'\u00B3';
28  m_supNumber[4] = L'\u2074';
29  m_supNumber[5] = L'\u2075';
30  m_supNumber[6] = L'\u2076';
31  m_supNumber[7] = L'\u2077';
32  m_supNumber[8] = L'\u2078';
33  m_supNumber[9] = L'\u2079';
34 
35  m_numerator.clear();
36  m_numerator.push_back(1);
37  m_denominator.clear();
38  m_denominator.push_back(1);
39  m_denominator.push_back(1);
40  UpdateTFText();
41 
42  Node* node1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 0), Node::NODE_IN, m_borderSize);
43  node1->StartMove(m_position);
44  Node* node2 = new Node(m_position + wxPoint2DDouble(m_width / 2, 0), Node::NODE_OUT, m_borderSize);
45  node2->SetAngle(180.0);
46  node2->StartMove(m_position);
47  m_nodeList.push_back(node1);
48  m_nodeList.push_back(node2);
49 }
50 
51 TransferFunction::~TransferFunction() {}
52 void TransferFunction::Draw(wxPoint2DDouble translation, double scale) const
53 {
54  glLineWidth(1.0);
55  if(m_selected) {
56  glColor4dv(m_selectionColour.GetRGBA());
57  double borderSize = (m_borderSize * 2.0 + 1.0) / scale;
58  DrawRectangle(m_position, m_width + borderSize, m_height + borderSize);
59  }
60  glColor4d(1.0, 1.0, 1.0, 1.0);
61  DrawRectangle(m_position, m_width, m_height);
62  glColor4d(0.0, 0.0, 0.0, 1.0);
63  DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
64 
65  std::vector<wxPoint2DDouble> linePts;
66  linePts.push_back(wxPoint2DDouble(m_position.m_x - m_width / 2 + 5 + m_borderSize, m_position.m_y));
67  linePts.push_back(wxPoint2DDouble(m_position.m_x + m_width / 2 - 5 - m_borderSize, m_position.m_y));
68  DrawLine(linePts);
69 
70  DrawNodes();
71 
72  glEnable(GL_TEXTURE_2D);
73  glColor4d(0.0, 0.0, 0.0, 1.0);
74  m_glStringNum->bind();
75  m_glStringNum->render(m_position.m_x, m_position.m_y - m_height / 4);
76  m_glStringDen->bind();
77  m_glStringDen->render(m_position.m_x, m_position.m_y + m_height / 4);
78  glDisable(GL_TEXTURE_2D);
79 }
80 
81 void TransferFunction::SetText(wxString numerator, wxString denominator)
82 {
83  wxFont font(m_fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
84  wxScreenDC dc;
85 
86  if(m_glStringNum) {
87  delete m_glStringNum;
88  m_glStringNum = NULL;
89  }
90  m_glStringNum = new wxGLString(numerator);
91  m_glStringNum->setFont(font);
92  m_glStringNum->consolidate(&dc);
93 
94  if(m_glStringDen) {
95  delete m_glStringDen;
96  m_glStringDen = NULL;
97  }
98  m_glStringDen = new wxGLString(denominator);
99  m_glStringDen->setFont(font);
100  m_glStringDen->consolidate(&dc);
101 
102  double nWidth = m_glStringNum->getWidth() + 5 + m_borderSize;
103  double dWidth = m_glStringDen->getWidth() + 5 + m_borderSize;
104 
105  m_width = nWidth > dWidth ? nWidth : dWidth;
106  m_height = m_glStringNum->getheight() + m_glStringDen->getheight() + 2 * m_borderSize;
107  SetPosition(m_position); // Update rect properly.
108 }
109 
110 wxString TransferFunction::GetSuperscriptNumber(int number)
111 {
112  wxString strNumber = wxString::Format("%d", number);
113  wxString superscriptStr = "";
114  for(int i = 0; i < (int)strNumber.length(); ++i) {
115  wxString digitStr = strNumber[i];
116  long digit = 0;
117  digitStr.ToLong(&digit);
118  superscriptStr += wxString(m_supNumber[digit]);
119  }
120  return superscriptStr;
121 }
122 
123 void TransferFunction::GetTFString(wxString& numerator, wxString& denominator)
124 {
125  numerator = "";
126  denominator = "";
127  int index = static_cast<int>(m_numerator.size()) - 1;
128  for(auto it = m_numerator.begin(), itEnd = m_numerator.end(); it != itEnd; ++it) {
129  double value = *it;
130  if(value != 0.0) {
131  wxString signal;
132  if(index == static_cast<int>(m_numerator.size()) - 1) {
133  if(value >= 0.0)
134  signal += "";
135  else
136  signal += "-";
137  } else {
138  if(value >= 0.0)
139  signal += "+ ";
140  else
141  signal += "- ";
142  }
143 
144  if(index == 0) {
145  numerator += signal + StringFromDouble(std::abs(value), 0);
146  break;
147  } else if(index == 1) {
148  if(value == 1.0) {
149  numerator += signal + "s";
150  } else {
151  numerator += signal + StringFromDouble(std::abs(value), 0) + "s";
152  }
153  } else {
154  if(value == 1.0) {
155  numerator += signal + "s" + GetSuperscriptNumber(index);
156  } else {
157  numerator += signal + StringFromDouble(std::abs(value), 0) + "s" + GetSuperscriptNumber(index);
158  }
159  }
160  numerator += " ";
161  }
162  --index;
163  }
164 
165  index = static_cast<int>(m_denominator.size()) - 1;
166  for(auto it = m_denominator.begin(), itEnd = m_denominator.end(); it != itEnd; ++it) {
167  double value = *it;
168  if(value != 0.0) {
169  wxString signal;
170  if(index == static_cast<int>(m_denominator.size()) - 1) {
171  if(value >= 0.0)
172  signal += "";
173  else
174  signal += "-";
175  } else {
176  if(value >= 0.0)
177  signal += "+ ";
178  else
179  signal += "- ";
180  }
181 
182  if(index == 0) {
183  denominator += signal + StringFromDouble(std::abs(value), 0);
184  break;
185  } else if(index == 1) {
186  if(value == 1.0) {
187  denominator += signal + "s";
188  } else {
189  denominator += signal + StringFromDouble(std::abs(value), 0) + "s";
190  }
191  } else {
192  if(value == 1.0) {
193  denominator += signal + "s" + GetSuperscriptNumber(index);
194  } else {
195  denominator += signal + StringFromDouble(std::abs(value), 0) + "s" + GetSuperscriptNumber(index);
196  }
197  }
198  denominator += " ";
199  }
200  --index;
201  }
202 }
203 
204 void TransferFunction::UpdateTFText()
205 {
206  wxString num, den;
207  GetTFString(num, den);
208  SetText(num, den);
209  if(m_nodeList.size() == 2) {
210  if(m_angle == 0.0) {
211  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
212  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
213  } else if(m_angle == 90.0) {
214  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
215  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
216  } else if(m_angle == 180.0) {
217  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
218  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
219  } else if(m_angle == 270.0) {
220  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
221  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
222  }
223  }
224 }
225 
226 bool TransferFunction::ShowForm(wxWindow* parent, Element* element)
227 {
228  TransferFunctionForm* tfForm = new TransferFunctionForm(parent, this);
229  if(tfForm->ShowModal() == wxID_OK) {
230  tfForm->Destroy();
231  return true;
232  }
233  tfForm->Destroy();
234  return false;
235 }
236 
237 void TransferFunction::Rotate(bool clockwise)
238 {
239  if(clockwise)
240  m_angle += 90.0;
241  else
242  m_angle -= 90.0;
243  if(m_angle >= 360.0)
244  m_angle = 0.0;
245  else if(m_angle < 0)
246  m_angle = 270.0;
247 
248  if(m_angle == 0.0) {
249  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
250  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
251  } else if(m_angle == 90.0) {
252  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
253  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
254  } else if(m_angle == 180.0) {
255  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(m_width / 2, 0));
256  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(-m_width / 2, 0));
257  } else if(m_angle == 270.0) {
258  m_nodeList[0]->SetPosition(m_position + wxPoint2DDouble(0, m_height / 2));
259  m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
260  }
261 
262  for(auto it = m_nodeList.begin(), itEnd = m_nodeList.end(); it != itEnd; ++it) {
263  Node* node = *it;
264  node->Rotate(clockwise);
265  }
266 }
267 
268 void TransferFunction::CalculateSpaceState(int maxIteration, double error)
269 {
270  m_maxIteration = maxIteration;
271  m_error = error;
272 
273  int order = static_cast<int>(m_denominator.size());
274  std::vector<double> denominator = m_denominator;
275  std::vector<double> numerator;
276 
277  //[Ref.] http://lpsa.swarthmore.edu/Representations/SysRepTransformations/TF2SS.html
278  int k = order;
279  for(int i = 0; i < order; i++) {
280  int numIndex = i - (order - static_cast<int>(m_numerator.size()));
281  if(numIndex < 0)
282  numerator.push_back(0.0);
283  else
284  numerator.push_back(m_numerator[numIndex]);
285  k--;
286  }
287 
288  SpaceState ss;
289  for(int i = 0; i < (order - 1); i++) {
290  std::vector<double> lineA;
291  for(int j = 0; j < (order - 1); j++) {
292  if(j == i + 1)
293  lineA.push_back(1.0);
294  else
295  lineA.push_back(0.0);
296  }
297  ss.A.push_back(lineA);
298  ss.B.push_back(0.0);
299  ss.C.push_back(0.0);
300  }
301  for(int i = 0; i < order - 1; i++) {
302  ss.A[order - 2][i] = -(denominator[order - 1 - i] / denominator[0]);
303  ss.C[i] = (numerator[order - 1 - i] - denominator[order - 1 - i] * numerator[0]) / denominator[0];
304  }
305  ss.B[order - 2] = 1.0;
306  ss.D = numerator[0];
307 
308  m_ss = ss;
309 
310  // Reset state
311  m_x.clear();
312  m_dx.clear();
313 
314  for(unsigned int i = 0; i < m_denominator.size(); ++i) {
315  m_x.push_back(0.0);
316  m_dx.push_back(0.0);
317  }
318 }
319 
320 bool TransferFunction::Solve(double input, double timeStep)
321 {
322  int order = static_cast<int>(m_ss.A.size());
323 
324  std::vector<double> x;
325  std::vector<double> oldx;
326  std::vector<double> dx;
327  std::vector<double> olddx;
328  for(int i = 0; i < order; i++) {
329  x.push_back(m_x[i]);
330  oldx.push_back(m_x[i]);
331 
332  dx.push_back(m_dx[i]);
333  olddx.push_back(m_dx[i]);
334  }
335 
336  bool exit = false;
337  int iter = 0;
338  while(!exit) {
339  double xError = 0.0;
340  double dxError = 0.0;
341  for(int i = 0; i < order; i++) {
342  // Trapezoidal method
343  x[i] = m_x[i] + 0.5 * timeStep * (m_dx[i] + dx[i]);
344 
345  if(std::abs(x[i] - oldx[i]) > xError) xError = std::abs(x[i] - oldx[i]);
346 
347  oldx[i] = x[i];
348  }
349  for(int i = 0; i < order; i++) {
350  // x' = Ax + Bu
351  dx[i] = 0.0;
352  for(int j = 0; j < order; j++) dx[i] += m_ss.A[i][j] * x[j];
353  dx[i] += m_ss.B[i] * input;
354 
355  if(std::abs(dx[i] - olddx[i]) > dxError) dxError = std::abs(dx[i] - olddx[i]);
356 
357  olddx[i] = dx[i];
358  }
359  if(std::max(xError, dxError) < m_error) exit = true;
360 
361  iter++;
362  if(iter >= m_maxIteration) return false;
363  }
364 
365  m_output = 0.0;
366  for(int i = 0; i < order; i++) {
367  m_output += m_ss.C[i] * x[i];
368  m_x[i] = x[i];
369  m_dx[i] = dx[i];
370  }
371 
372  m_output += m_ss.D * input;
373 
374  return true;
375 }
376 
378 {
379  TransferFunction* copy = new TransferFunction(m_elementID);
380  *copy = *this;
381  m_glStringNum = NULL;
382  m_glStringDen = NULL;
383  UpdateTFText();
384  return copy;
385 }
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Node of a control element. This class manages the user interaction with the connection and control el...
-
virtual Element * GetCopy()
Get a the element copy.
+
virtual Element * GetCopy()
Get a the element copy.
+
virtual void CalculateSpaceState(int maxIteration=100, double error=1e-3)
Convert the transfer function to space state on controllable canonical form (CCF).
Form to edit the transfer function control data.
- +
virtual void Rotate(bool clockwise=true)
Rotate the element.
- +
Calculates the time response by a frequency domain transfer function.
+
virtual bool Solve(double input, double timeStep)
Calculates the time response by the space state form of transfer function.
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
+
diff --git a/docs/doxygen/html/_transfer_function_8h.html b/docs/doxygen/html/_transfer_function_8h.html new file mode 100644 index 0000000..5abcd43 --- /dev/null +++ b/docs/doxygen/html/_transfer_function_8h.html @@ -0,0 +1,119 @@ + + + + + + + + + +Project/TransferFunction.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
TransferFunction.h File Reference
+
+
+
#include "ControlElement.h"
+#include <wx/dcscreen.h>
+#include "wxGLString.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

class  TransferFunction
 Calculates the time response by a frequency domain transfer function. More...
 
struct  TransferFunction::SpaceState
 
+
+
+ + + + diff --git a/docs/doxygen/html/_transfer_function_8h_source.html b/docs/doxygen/html/_transfer_function_8h_source.html index bd51bfe..6a75258 100644 --- a/docs/doxygen/html/_transfer_function_8h_source.html +++ b/docs/doxygen/html/_transfer_function_8h_source.html @@ -88,15 +88,17 @@ $(document).ready(function(){initNavTree('_transfer_function_8h_source.html','')
TransferFunction.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFERFUNCTION_H
19 #define TRANSFERFUNCTION_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
27 
29 {
30  public:
31  struct SpaceState {
32  std::vector<std::vector<double> > A;
33  std::vector<double> B;
34  std::vector<double> C;
35  double D;
36  };
37 
38  TransferFunction(int id);
40 
41  virtual void Draw(wxPoint2DDouble translation, double scale) const;
42  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
43  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
44  virtual bool ShowForm(wxWindow* parent, Element* element);
45  virtual void Rotate(bool clockwise = true);
46 
47  virtual std::vector<double> GetNumerator() const { return m_numerator; }
48  virtual std::vector<double> GetDenominator() const { return m_denominator; }
49  virtual void SetNumerator(std::vector<double> numerator) { m_numerator = numerator; }
50  virtual void SetDenominator(std::vector<double> denominator) { m_denominator = denominator; }
51  virtual void UpdateTFText();
52  virtual void UpdateText() { UpdateTFText(); }
53  virtual SpaceState GetSpaceState() { return m_ss; }
54  virtual void CalculateSpaceState(int maxIteration = 100, double error = 1e-3);
55  virtual bool Solve(double input, double timeStep);
56 
57  virtual Element* GetCopy();
58 
59  protected:
60  virtual void SetText(wxString numerator, wxString denominator);
61  virtual wxString GetSuperscriptNumber(int number);
62  virtual void GetTFString(wxString& numerator, wxString& denominator);
63 
64  wchar_t m_supNumber[10];
65 
66  wxGLString* m_glStringNum = NULL;
67  wxGLString* m_glStringDen = NULL;
68  int m_fontSize = 10;
69 
70  std::vector<double> m_numerator;
71  std::vector<double> m_denominator;
72  SpaceState m_ss;
73 
74  std::vector<double> m_x;
75  std::vector<double> m_dx;
76  double m_error = 1e-3;
77  int m_maxIteration = 100;
78 };
79 
80 #endif // TRANSFERFUNCTION_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFERFUNCTION_H
19 #define TRANSFERFUNCTION_H
20 
21 #include "ControlElement.h"
22 
23 #include <wx/dcscreen.h>
24 #include "wxGLString.h"
25 
27 
36 {
37  public:
38  struct SpaceState {
39  std::vector<std::vector<double> > A;
40  std::vector<double> B;
41  std::vector<double> C;
42  double D;
43  };
44 
45  TransferFunction(int id);
47 
48  virtual void Draw(wxPoint2DDouble translation, double scale) const;
49  virtual bool Contains(wxPoint2DDouble position) const { return m_rect.Contains(position); }
50  virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
51  virtual bool ShowForm(wxWindow* parent, Element* element);
52  virtual void Rotate(bool clockwise = true);
53 
54  virtual std::vector<double> GetNumerator() const { return m_numerator; }
55  virtual std::vector<double> GetDenominator() const { return m_denominator; }
56  virtual void SetNumerator(std::vector<double> numerator) { m_numerator = numerator; }
57  virtual void SetDenominator(std::vector<double> denominator) { m_denominator = denominator; }
58  virtual void UpdateTFText();
59  virtual void UpdateText() { UpdateTFText(); }
60  virtual SpaceState GetSpaceState() { return m_ss; }
66  virtual void CalculateSpaceState(int maxIteration = 100, double error = 1e-3);
76  virtual bool Solve(double input, double timeStep);
77 
78  virtual Element* GetCopy();
79 
80  protected:
81  virtual void SetText(wxString numerator, wxString denominator);
82  virtual wxString GetSuperscriptNumber(int number);
83  virtual void GetTFString(wxString& numerator, wxString& denominator);
84 
85  wchar_t m_supNumber[10];
86 
87  wxGLString* m_glStringNum = NULL;
88  wxGLString* m_glStringDen = NULL;
89  int m_fontSize = 10;
90 
91  std::vector<double> m_numerator;
92  std::vector<double> m_denominator;
93  SpaceState m_ss;
94 
95  std::vector<double> m_x;
96  std::vector<double> m_dx;
97  double m_error = 1e-3;
98  int m_maxIteration = 100;
99 };
100 
101 #endif // TRANSFERFUNCTION_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
-
virtual Element * GetCopy()
Get a the element copy.
-
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
+
virtual Element * GetCopy()
Get a the element copy.
+
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
+
virtual void CalculateSpaceState(int maxIteration=100, double error=1e-3)
Convert the transfer function to space state on controllable canonical form (CCF).
Form to edit the transfer function control data.
- +
virtual void Rotate(bool clockwise=true)
Rotate the element.
-
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
- +
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
+
Calculates the time response by a frequency domain transfer function.
+
virtual bool Solve(double input, double timeStep)
Calculates the time response by the space state form of transfer function.
Base class of a control element. Provide general methods to other control classes.
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
@@ -106,7 +108,7 @@ $(document).ready(function(){initNavTree('_transfer_function_8h_source.html','')
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransferFunctionForm.h"
19 #include "TransferFunction.h"
20 
21 TransferFunctionForm::TransferFunctionForm(wxWindow* parent, TransferFunction* transferFunction)
22  : TransferFunctionFormBase(parent)
23 {
24  SetSize(GetBestSize());
25 
26  m_parent = parent;
27  m_tf = transferFunction;
28  LoadTFData();
29 }
30 
31 TransferFunctionForm::~TransferFunctionForm() {}
32 void TransferFunctionForm::OnCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
33 void TransferFunctionForm::OnOKClick(wxCommandEvent& event)
34 {
35  if(ValidateData()) EndModal(wxID_OK);
36 }
37 
38 void TransferFunctionForm::LoadTFData()
39 {
40  auto num = m_tf->GetNumerator();
41  auto den = m_tf->GetDenominator();
42 
43  wxString numStr = "";
44  for(auto it = num.begin(), itEnd = num.end(); it != itEnd; ++it) {
45  double value = *it;
46  if(it == num.begin())
47  numStr = m_tf->StringFromDouble(value, 0);
48  else
49  numStr += " " + m_tf->StringFromDouble(value, 0);
50  }
51  m_textCtrlNumerator->SetValue(numStr);
52 
53  wxString denStr = "";
54  for(auto it = den.begin(), itEnd = den.end(); it != itEnd; ++it) {
55  double value = *it;
56  if(it == den.begin())
57  denStr = m_tf->StringFromDouble(value, 0);
58  else
59  denStr += " " + m_tf->StringFromDouble(value, 0);
60  }
61  m_textCtrlDenominator->SetValue(denStr);
62 }
63 
64 bool TransferFunctionForm::ValidateData()
65 {
66  wxString num = m_textCtrlNumerator->GetValue();
67  std::vector<double> numerator;
68  while(num != "") {
69  wxString rest;
70  wxString strValue = num.BeforeFirst(' ', &rest);
71  num = rest;
72  double value = 0;
73  if(!m_tf->DoubleFromString(this, strValue, value,
74  _("Value entered incorrectly in the field \"Numerator parameters\".")))
75  return false;
76  numerator.push_back(value);
77  }
78 
79  wxString den = m_textCtrlDenominator->GetValue();
80  std::vector<double> denominator;
81  while(den != "") {
82  wxString rest;
83  wxString strValue = den.BeforeFirst(' ', &rest);
84  den = rest;
85  double value = 0;
86  if(!m_tf->DoubleFromString(this, strValue, value,
87  _("Value entered incorrectly in the field \"Denominator parameters\".")))
88  return false;
89  denominator.push_back(value);
90  }
91  m_tf->SetNumerator(numerator);
92  m_tf->SetDenominator(denominator);
93  m_tf->UpdateTFText();
94  return true;
95 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransferFunctionForm.h"
19 #include "TransferFunction.h"
20 
21 TransferFunctionForm::TransferFunctionForm(wxWindow* parent, TransferFunction* transferFunction)
22  : TransferFunctionFormBase(parent)
23 {
24  SetSize(GetBestSize());
25 
26  m_parent = parent;
27  m_tf = transferFunction;
28  LoadTFData();
29 }
30 
31 TransferFunctionForm::~TransferFunctionForm() {}
32 void TransferFunctionForm::OnCancelClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
33 void TransferFunctionForm::OnOKClick(wxCommandEvent& event)
34 {
35  if(ValidateData()) EndModal(wxID_OK);
36 }
37 
38 void TransferFunctionForm::LoadTFData()
39 {
40  auto num = m_tf->GetNumerator();
41  auto den = m_tf->GetDenominator();
42 
43  wxString numStr = "";
44  for(auto it = num.begin(), itEnd = num.end(); it != itEnd; ++it) {
45  double value = *it;
46  if(it == num.begin())
47  numStr = m_tf->StringFromDouble(value, 0);
48  else
49  numStr += " " + m_tf->StringFromDouble(value, 0);
50  }
51  m_textCtrlNumerator->SetValue(numStr);
52 
53  wxString denStr = "";
54  for(auto it = den.begin(), itEnd = den.end(); it != itEnd; ++it) {
55  double value = *it;
56  if(it == den.begin())
57  denStr = m_tf->StringFromDouble(value, 0);
58  else
59  denStr += " " + m_tf->StringFromDouble(value, 0);
60  }
61  m_textCtrlDenominator->SetValue(denStr);
62 }
63 
64 bool TransferFunctionForm::ValidateData()
65 {
66  wxString num = m_textCtrlNumerator->GetValue();
67  std::vector<double> numerator;
68  while(num != "") {
69  wxString rest;
70  wxString strValue = num.BeforeFirst(' ', &rest);
71  num = rest;
72  double value = 0;
73  if(!m_tf->DoubleFromString(this, strValue, value,
74  _("Value entered incorrectly in the field \"Numerator parameters\".")))
75  return false;
76  numerator.push_back(value);
77  }
78 
79  wxString den = m_textCtrlDenominator->GetValue();
80  std::vector<double> denominator;
81  while(den != "") {
82  wxString rest;
83  wxString strValue = den.BeforeFirst(' ', &rest);
84  den = rest;
85  double value = 0;
86  if(!m_tf->DoubleFromString(this, strValue, value,
87  _("Value entered incorrectly in the field \"Denominator parameters\".")))
88  return false;
89  denominator.push_back(value);
90  }
91  m_tf->SetNumerator(numerator);
92  m_tf->SetDenominator(denominator);
93  m_tf->UpdateTFText();
94  return true;
95 }
- +
Calculates the time response by a frequency domain transfer function.
+
diff --git a/docs/doxygen/html/_transfer_function_form_8h_source.html b/docs/doxygen/html/_transfer_function_form_8h_source.html index 20ec72f..1dfc2e7 100644 --- a/docs/doxygen/html/_transfer_function_form_8h_source.html +++ b/docs/doxygen/html/_transfer_function_form_8h_source.html @@ -90,7 +90,7 @@ $(document).ready(function(){initNavTree('_transfer_function_form_8h_source.html
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFERFUNCTIONFORM_H
19 #define TRANSFERFUNCTIONFORM_H
20 
21 #include "ElementForm.h"
22 
23 class TransferFunction;
24 
33 {
34  public:
35  TransferFunctionForm(wxWindow* parent, TransferFunction* transferFunction);
36  virtual ~TransferFunctionForm();
37  bool ValidateData();
38 
39  protected:
40  virtual void OnCancelClick(wxCommandEvent& event);
41  virtual void OnOKClick(wxCommandEvent& event);
42  void LoadTFData();
43 
44  wxWindow* m_parent = NULL;
45  TransferFunction* m_tf = NULL;
46 };
47 #endif // TRANSFERFUNCTIONFORM_H
Form to edit the transfer function control data.
- +
Calculates the time response by a frequency domain transfer function.
diff --git a/docs/doxygen/html/_transformer_8cpp_source.html b/docs/doxygen/html/_transformer_8cpp_source.html index c8465d5..27810c6 100644 --- a/docs/doxygen/html/_transformer_8cpp_source.html +++ b/docs/doxygen/html/_transformer_8cpp_source.html @@ -88,10 +88,11 @@ $(document).ready(function(){initNavTree('_transformer_8cpp_source.html','');});
Transformer.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransformerForm.h"
19 #include "Transformer.h"
20 
21 Transformer::Transformer() : Branch()
22 {
23  for(int i = 0; i < 2; i++) {
24  for(int j = 0; j < 3; j++) {
25  m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0);
26  }
27  }
28 }
29 Transformer::Transformer(wxString name) : Branch()
30 {
31  for(int i = 0; i < 2; i++) {
32  for(int j = 0; j < 3; j++) {
33  m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0);
34  }
35  }
36  m_electricalData.name = name;
37 }
38 Transformer::~Transformer() {}
39 bool Transformer::AddParent(Element* parent, wxPoint2DDouble position)
40 {
41  if(parent) {
42  // First bus.
43  if(m_parentList.size() == 0) {
44  m_position = position;
45  m_parentList.push_back(parent);
46  parent->AddChild(this);
47  wxPoint2DDouble parentPt =
48  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
49  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
50  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
51  m_pointList.push_back(parentPt); // First point
52  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
53 
54  wxRect2DDouble genRect(0, 0, 0, 0);
55  m_switchRect.push_back(genRect);
56 
57  return false;
58  }
59  // Second bus.
60  else if(parent != m_parentList[0]) {
61  m_parentList.push_back(parent);
62  parent->AddChild(this);
63  wxPoint2DDouble parentPt =
64  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
65  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
66  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
67 
68  // Get the average between the two bus points.
69  m_position =
70  wxPoint2DDouble((m_pointList[0].m_x + parentPt.m_x) / 2.0, (m_pointList[0].m_y + parentPt.m_y) / 2.0);
71  // Set the transformer rectangle.
72  m_width = 70.0;
73  m_height = 40.0;
74  SetPosition(m_position); // This method calculates the rectangle propely.
75  // Set the "side" points.
76  m_pointList.push_back(
77  wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(-10 - m_borderSize, m_height / 2.0)));
78  m_pointList.push_back(
79  wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(m_width + 10 + m_borderSize, m_height / 2.0)));
80 
81  // Set first switch point.
82  wxPoint2DDouble secondPoint = parentPt;
83  if(m_pointList.size() > 2) {
84  secondPoint = m_pointList[2];
85  }
86  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], secondPoint);
87 
88  // Set the second switch point.
89  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
90 
91  m_pointList.push_back(parentPt); // Last point.
92  m_inserted = true;
93 
94  wxRect2DDouble genRect(0, 0, 0, 0);
95  m_switchRect.push_back(genRect);
96  UpdateSwitches();
97  UpdatePowerFlowArrowsPosition();
98 
99  return true;
100  }
101  }
102  return false;
103 }
104 
105 bool Transformer::Contains(wxPoint2DDouble position) const
106 {
107  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
108  return m_rect.Contains(ptR);
109 }
110 
111 void Transformer::Draw(wxPoint2DDouble translation, double scale) const
112 {
113  OpenGLColour elementColour;
114  if(m_online) {
115  if(m_dynEvent)
116  elementColour = m_dynamicEventColour;
117  else
118  elementColour = m_onlineElementColour;
119  } else
120  elementColour = m_offlineElementColour;
121 
122  if(m_inserted) {
123  // Draw selection (layer 1).
124  if(m_selected) {
125  // Push the current matrix on stack.
126  glLineWidth(1.5 + m_borderSize * 2.0);
127  glColor4dv(m_selectionColour.GetRGBA());
128  DrawLine(m_pointList);
129  glPushMatrix();
130  // Rotate the matrix around the object position.
131  glTranslated(m_position.m_x, m_position.m_y, 0.0);
132  glRotated(m_angle, 0.0, 0.0, 1.0);
133  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
134 
135  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20,
136  GL_POLYGON);
137  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20,
138  GL_POLYGON);
139 
140  glPopMatrix();
141 
142  // Draw nodes selection.
143  if(m_pointList.size() > 0) {
144  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
145  if(m_inserted) {
146  DrawCircle(m_pointList[m_pointList.size() - 1], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
147  }
148  }
149  }
150 
151  // Draw transformer (layer 2).
152  // Transformer line
153  glLineWidth(1.5);
154  glColor4dv(elementColour.GetRGBA());
155  DrawLine(m_pointList);
156 
157  // Draw nodes.
158  if(m_pointList.size() > 0) {
159  glColor4dv(elementColour.GetRGBA());
160  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
161  if(m_inserted) {
162  DrawCircle(m_pointList[m_pointList.size() - 1], 5.0, 10, GL_POLYGON);
163  }
164  }
165 
166  DrawSwitches();
167  DrawPowerFlowPts();
168 
169  // Push the current matrix on stack.
170  glPushMatrix();
171  // Rotate the matrix around the object position.
172  glTranslated(m_position.m_x, m_position.m_y, 0.0);
173  glRotated(m_angle, 0.0, 0.0, 1.0);
174  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
175 
176  glColor4d(1.0, 1.0, 1.0, 1.0);
177  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, GL_POLYGON);
178  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, GL_POLYGON);
179 
180  glColor4dv(elementColour.GetRGBA());
181  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20);
182  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20);
183 
184  DrawPoint(m_rect.GetPosition(), 8.0 * scale);
185 
186  glPopMatrix();
187  }
188 }
189 
190 bool Transformer::Intersects(wxRect2DDouble rect) const
191 {
192  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
193  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
194 }
195 
196 void Transformer::Rotate(bool clockwise)
197 {
198  double rotAngle = m_rotationAngle;
199  if(!clockwise) rotAngle = -m_rotationAngle;
200 
201  m_angle += rotAngle;
202  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
203 
204  // Rotate all the points, except the switches and buses points.
205  for(int i = 2; i < (int)m_pointList.size() - 2; i++) {
206  m_pointList[i] = RotateAtPosition(m_pointList[i], rotAngle);
207  }
208  UpdateSwitchesPosition();
209  UpdatePowerFlowArrowsPosition();
210 }
211 
212 void Transformer::Move(wxPoint2DDouble position)
213 {
214  SetPosition(m_movePos + position - m_moveStartPt);
215 
216  // Move all the points, except the switches and buses points.
217  for(int i = 2; i < (int)m_pointList.size() - 2; i++) {
218  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
219  }
220 
221  if(!m_parentList[0]) {
222  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
223  }
224  if(!m_parentList[1]) {
225  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
226  }
227 
228  UpdateSwitchesPosition();
229  UpdatePowerFlowArrowsPosition();
230 }
231 
232 void Transformer::MoveNode(Element* parent, wxPoint2DDouble position)
233 {
234  if(parent) {
235  // First bus.
236  if(parent == m_parentList[0]) {
237  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
238  }
239  // Second bus.
240  else if(parent == m_parentList[1]) {
241  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
242  }
243  } else {
244  if(m_activeNodeID == 1) {
245  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
246  if(m_parentList[0]) {
247  m_parentList[0]->RemoveChild(this);
248  m_parentList[0] = NULL;
249  m_online = false;
250  }
251  } else if(m_activeNodeID == 2) {
252  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
253  if(m_parentList[1]) {
254  m_parentList[1]->RemoveChild(this);
255  m_parentList[1] = NULL;
256  m_online = false;
257  }
258  }
259  }
260 
261  // Recalculate switches positions
262  UpdateSwitchesPosition();
263  UpdatePowerFlowArrowsPosition();
264 }
265 
266 void Transformer::StartMove(wxPoint2DDouble position)
267 {
268  m_moveStartPt = position;
269  m_movePts = m_pointList;
270  m_movePos = m_position;
271 }
272 
273 bool Transformer::GetContextMenu(wxMenu& menu)
274 {
275  menu.Append(ID_EDIT_ELEMENT, _("Edit tranformer"));
276  GeneralMenuItens(menu);
277  return true;
278 }
279 
280 bool Transformer::ShowForm(wxWindow* parent, Element* element)
281 {
282  TransformerForm* transfForm = new TransformerForm(parent, this);
283  if(transfForm->ShowModal() == wxID_OK) {
284  transfForm->Destroy();
285  return true;
286  }
287  transfForm->Destroy();
288  return false;
289 }
290 
291 void Transformer::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
292 {
293  if(nominalVoltage.size() == 1) {
294  m_electricalData.primaryNominalVoltage = nominalVoltage[0];
295  m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
296  } else if(nominalVoltage.size() == 2) {
297  m_electricalData.primaryNominalVoltage = nominalVoltage[0];
298  m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
299  m_electricalData.secondaryNominalVoltage = nominalVoltage[1];
300  m_electricalData.secondaryNominalVoltageUnit = nominalVoltageUnit[1];
301  }
302 }
303 
304 void Transformer::UpdatePowerFlowArrowsPosition()
305 {
306  std::vector<wxPoint2DDouble> edges;
307  switch(m_pfDirection) {
308  case PF_NONE: {
309  m_powerFlowArrow.clear();
310  } break;
311  case PF_BUS1_TO_BUS2: {
312  for(int i = 1; i < (int)m_pointList.size() - 1; i++) {
313  edges.push_back(m_pointList[i]);
314  }
315  } break;
316  case PF_BUS2_TO_BUS1: {
317  for(int i = (int)m_pointList.size() - 2; i > 0; i--) {
318  edges.push_back(m_pointList[i]);
319  }
320  } break;
321  default:
322  break;
323  }
324  CalculatePowerFlowPts(edges);
325 }
326 
327 void Transformer::RotateNode(Element* parent, bool clockwise)
328 {
329  double rotAngle = m_rotationAngle;
330  if(!clockwise) rotAngle = -m_rotationAngle;
331 
332  if(parent == m_parentList[0]) {
333  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
334  } else if(parent == m_parentList[1]) {
335  m_pointList[m_pointList.size() - 1] = parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
336  }
337  UpdateSwitchesPosition();
338  UpdatePowerFlowArrowsPosition();
339 }
340 
342 {
343  if(m_activeNodeID == 1 && parent == m_parentList[0]) return false;
344  if(m_activeNodeID == 2 && parent == m_parentList[1]) return false;
345 
346  if(parent && m_activeNodeID != 0) {
347  wxRect2DDouble nodeRect(0, 0, 0, 0);
348  if(m_activeNodeID == 1) {
349  nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
350  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
351  }
352  if(m_activeNodeID == 2) {
353  nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
354  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
355  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
356  }
357 
358  if(parent->Intersects(nodeRect)) {
359  if(m_activeNodeID == 1) {
360  // Check if the user is trying to connect the same bus.
361  if(m_parentList[1] == parent) {
362  m_activeNodeID = 0;
363  return false;
364  }
365 
366  m_parentList[0] = parent;
367 
368  // Centralize the node on bus.
369  wxPoint2DDouble parentPt = parent->RotateAtPosition(
370  m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
371  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
372  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
373  m_pointList[0] = parentPt;
374 
375  UpdateSwitchesPosition();
376  UpdatePowerFlowArrowsPosition();
377  return true;
378  }
379  if(m_activeNodeID == 2) {
380  if(m_parentList[0] == parent) {
381  m_activeNodeID = 0;
382  return false;
383  }
384 
385  m_parentList[1] = parent;
386 
387  wxPoint2DDouble parentPt =
388  parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], -parent->GetAngle());
389  parentPt.m_y = parent->GetPosition().m_y;
390  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
391  m_pointList[m_pointList.size() - 1] = parentPt;
392 
393  UpdateSwitchesPosition();
394  UpdatePowerFlowArrowsPosition();
395  return true;
396  }
397  } else {
398  if(m_activeNodeID == 1) m_parentList[0] = NULL;
399  if(m_activeNodeID == 2) m_parentList[1] = NULL;
400  }
401  }
402  return false;
403 }
404 
406 {
407  m_pfDirection = pfDirection;
408  UpdatePowerFlowArrowsPosition();
409 }
410 
412 {
413  Transformer* copy = new Transformer();
414  *copy = *this;
415  return copy;
416 }
417 
418 wxString Transformer::GetTipText() const
419 {
420  wxString tipText = m_electricalData.name;
421  wxString primVoltage = StringFromDouble(m_electricalData.primaryNominalVoltage);
422  switch(m_electricalData.primaryNominalVoltageUnit) {
423  case UNIT_V: {
424  primVoltage += _(" V");
425  } break;
426  case UNIT_kV: {
427  primVoltage += _(" kV");
428  } break;
429  default:
430  break;
431  }
432  wxString secVoltage = StringFromDouble(m_electricalData.secondaryNominalVoltage);
433  switch(m_electricalData.secondaryNominalVoltageUnit) {
434  case UNIT_V: {
435  secVoltage += _(" V");
436  } break;
437  case UNIT_kV: {
438  secVoltage += _(" kV");
439  } break;
440  default:
441  break;
442  }
443 
444  tipText += "\n" + primVoltage + " / " + secVoltage;
445 
446  if(m_online) {
447  tipText += "\n";
448  int busNumber[2];
449  busNumber[0] = static_cast<Bus*>(m_parentList[0])->GetElectricalData().number + 1;
450  busNumber[1] = static_cast<Bus*>(m_parentList[1])->GetElectricalData().number + 1;
451 
452  tipText += _("\nP") + wxString::Format("(%d-%d) = ", busNumber[0], busNumber[1]) +
453  wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(" p.u.");
454  tipText += _("\nQ") + wxString::Format("(%d-%d) = ", busNumber[0], busNumber[1]) +
455  wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(" p.u.");
456  tipText += _("\nP") + wxString::Format("(%d-%d) = ", busNumber[1], busNumber[0]) +
457  wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(" p.u.");
458  tipText += _("\nQ") + wxString::Format("(%d-%d) = ", busNumber[1], busNumber[0]) +
459  wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(" p.u.");
460  }
461 
462  return tipText;
463 }
464 
465 TransformerElectricalData Transformer::GetPUElectricalData(double systemBasePower)
466 {
467  TransformerElectricalData data = m_electricalData;
468  double transformerBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
469  double baseVoltage = 0.0;
470  if(data.baseVoltage == 0) {
471  baseVoltage = GetValueFromUnit(data.primaryNominalVoltage, data.primaryNominalVoltageUnit);
472  } else {
473  baseVoltage = GetValueFromUnit(data.secondaryNominalVoltage, data.secondaryNominalVoltageUnit);
474  }
475  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
476  double transformerBaseImpedance = (baseVoltage * baseVoltage) / transformerBasePower;
477 
478  // Resistance
479  double r = data.resistance;
480  if(data.resistanceUnit == UNIT_PU) {
481  if(data.useTransformerPower) data.resistance = (r * transformerBaseImpedance) / systemBaseImpedance;
482  } else {
483  data.resistance = r / systemBaseImpedance;
484  }
485  data.resistanceUnit = UNIT_PU;
486 
487  // Indutive reactance
488  double x = data.indReactance;
489  if(data.indReactanceUnit == UNIT_PU) {
490  if(data.useTransformerPower) data.indReactance = (x * transformerBaseImpedance) / systemBaseImpedance;
491  } else {
492  data.indReactance = x / systemBaseImpedance;
493  }
494  data.indReactanceUnit = UNIT_PU;
495 
496  // Fault
497 
498  // Zero seq. resistance
499  double r0 = data.zeroResistance;
500  if(data.useTransformerPower) data.zeroResistance = (r0 * transformerBaseImpedance) / systemBaseImpedance;
501 
502  // Zero seq. ind. reactance
503  double x0 = data.zeroIndReactance;
504  if(data.useTransformerPower) data.zeroIndReactance = (x0 * transformerBaseImpedance) / systemBaseImpedance;
505 
506  // Primary ground resistance
507  double rgp = data.primaryGrndResistance;
508  if(data.useTransformerPower) data.primaryGrndResistance = (rgp * transformerBaseImpedance) / systemBaseImpedance;
509 
510  // Primary ground ind reactance
511  double xgp = data.primaryGrndReactance;
512  if(data.useTransformerPower) data.primaryGrndReactance = (xgp * transformerBaseImpedance) / systemBaseImpedance;
513 
514  // Secondary ground resistance
515  double rgs = data.secondaryGrndResistance;
516  if(data.useTransformerPower) data.secondaryGrndResistance = (rgs * transformerBaseImpedance) / systemBaseImpedance;
517 
518  // Secondary ground ind reactance
519  double xgs = data.secondaryGrndReactance;
520  if(data.useTransformerPower) data.secondaryGrndReactance = (xgs * transformerBaseImpedance) / systemBaseImpedance;
521 
522  if(!m_online) {
523  data.powerFlow[0] = std::complex<double>(0, 0);
524  data.powerFlow[1] = std::complex<double>(0, 0);
525  data.faultCurrent[0][0] = std::complex<double>(0, 0);
526  data.faultCurrent[0][1] = std::complex<double>(0, 0);
527  data.faultCurrent[0][2] = std::complex<double>(0, 0);
528  data.faultCurrent[1][0] = std::complex<double>(0, 0);
529  data.faultCurrent[1][1] = std::complex<double>(0, 0);
530  data.faultCurrent[1][2] = std::complex<double>(0, 0);
531  }
532 
533  return data;
534 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransformerForm.h"
19 #include "Transformer.h"
20 
21 Transformer::Transformer() : Branch()
22 {
23  for(int i = 0; i < 2; i++) {
24  for(int j = 0; j < 3; j++) {
25  m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0);
26  }
27  }
28 }
29 Transformer::Transformer(wxString name) : Branch()
30 {
31  for(int i = 0; i < 2; i++) {
32  for(int j = 0; j < 3; j++) {
33  m_electricalData.faultCurrent[i][j] = std::complex<double>(0.0, 0.0);
34  }
35  }
36  m_electricalData.name = name;
37 }
38 Transformer::~Transformer() {}
39 bool Transformer::AddParent(Element* parent, wxPoint2DDouble position)
40 {
41  if(parent) {
42  // First bus.
43  if(m_parentList.size() == 0) {
44  m_position = position;
45  m_parentList.push_back(parent);
46  parent->AddChild(this);
47  wxPoint2DDouble parentPt =
48  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
49  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
50  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
51  m_pointList.push_back(parentPt); // First point
52  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_position));
53 
54  wxRect2DDouble genRect(0, 0, 0, 0);
55  m_switchRect.push_back(genRect);
56 
57  return false;
58  }
59  // Second bus.
60  else if(parent != m_parentList[0]) {
61  m_parentList.push_back(parent);
62  parent->AddChild(this);
63  wxPoint2DDouble parentPt =
64  parent->RotateAtPosition(position, -parent->GetAngle()); // Rotate click to horizontal position.
65  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
66  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle()); // Rotate back.
67 
68  // Get the average between the two bus points.
69  m_position =
70  wxPoint2DDouble((m_pointList[0].m_x + parentPt.m_x) / 2.0, (m_pointList[0].m_y + parentPt.m_y) / 2.0);
71  // Set the transformer rectangle.
72  m_width = 70.0;
73  m_height = 40.0;
74  SetPosition(m_position); // This method calculates the rectangle propely.
75  // Set the "side" points.
76  m_pointList.push_back(
77  wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(-10 - m_borderSize, m_height / 2.0)));
78  m_pointList.push_back(
79  wxPoint2DDouble(m_rect.GetPosition() + wxPoint2DDouble(m_width + 10 + m_borderSize, m_height / 2.0)));
80 
81  // Set first switch point.
82  wxPoint2DDouble secondPoint = parentPt;
83  if(m_pointList.size() > 2) {
84  secondPoint = m_pointList[2];
85  }
86  m_pointList[1] = GetSwitchPoint(m_parentList[0], m_pointList[0], secondPoint);
87 
88  // Set the second switch point.
89  m_pointList.push_back(GetSwitchPoint(parent, parentPt, m_pointList[m_pointList.size() - 1]));
90 
91  m_pointList.push_back(parentPt); // Last point.
92  m_inserted = true;
93 
94  wxRect2DDouble genRect(0, 0, 0, 0);
95  m_switchRect.push_back(genRect);
96  UpdateSwitches();
97  UpdatePowerFlowArrowsPosition();
98 
99  return true;
100  }
101  }
102  return false;
103 }
104 
105 bool Transformer::Contains(wxPoint2DDouble position) const
106 {
107  wxPoint2DDouble ptR = RotateAtPosition(position, -m_angle);
108  return m_rect.Contains(ptR);
109 }
110 
111 void Transformer::Draw(wxPoint2DDouble translation, double scale) const
112 {
113  OpenGLColour elementColour;
114  if(m_online) {
115  if(m_dynEvent)
116  elementColour = m_dynamicEventColour;
117  else
118  elementColour = m_onlineElementColour;
119  } else
120  elementColour = m_offlineElementColour;
121 
122  if(m_inserted) {
123  // Draw selection (layer 1).
124  if(m_selected) {
125  // Push the current matrix on stack.
126  glLineWidth(1.5 + m_borderSize * 2.0);
127  glColor4dv(m_selectionColour.GetRGBA());
128  DrawLine(m_pointList);
129  glPushMatrix();
130  // Rotate the matrix around the object position.
131  glTranslated(m_position.m_x, m_position.m_y, 0.0);
132  glRotated(m_angle, 0.0, 0.0, 1.0);
133  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
134 
135  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20,
136  GL_POLYGON);
137  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20 + (m_borderSize + 1.5) / scale, 20,
138  GL_POLYGON);
139 
140  glPopMatrix();
141 
142  // Draw nodes selection.
143  if(m_pointList.size() > 0) {
144  DrawCircle(m_pointList[0], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
145  if(m_inserted) {
146  DrawCircle(m_pointList[m_pointList.size() - 1], 5.0 + m_borderSize / scale, 10, GL_POLYGON);
147  }
148  }
149  }
150 
151  // Draw transformer (layer 2).
152  // Transformer line
153  glLineWidth(1.5);
154  glColor4dv(elementColour.GetRGBA());
155  DrawLine(m_pointList);
156 
157  // Draw nodes.
158  if(m_pointList.size() > 0) {
159  glColor4dv(elementColour.GetRGBA());
160  DrawCircle(m_pointList[0], 5.0, 10, GL_POLYGON);
161  if(m_inserted) {
162  DrawCircle(m_pointList[m_pointList.size() - 1], 5.0, 10, GL_POLYGON);
163  }
164  }
165 
166  DrawSwitches();
167  DrawPowerFlowPts();
168 
169  // Push the current matrix on stack.
170  glPushMatrix();
171  // Rotate the matrix around the object position.
172  glTranslated(m_position.m_x, m_position.m_y, 0.0);
173  glRotated(m_angle, 0.0, 0.0, 1.0);
174  glTranslated(-m_position.m_x, -m_position.m_y, 0.0);
175 
176  glColor4d(1.0, 1.0, 1.0, 1.0);
177  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20, GL_POLYGON);
178  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20, GL_POLYGON);
179 
180  glColor4dv(elementColour.GetRGBA());
181  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(20.0, 20.0), 20, 20);
182  DrawCircle(m_rect.GetPosition() + wxPoint2DDouble(50.0, 20.0), 20, 20);
183 
184  DrawPoint(m_rect.GetPosition(), 8.0 * scale);
185 
186  glPopMatrix();
187  }
188 }
189 
190 bool Transformer::Intersects(wxRect2DDouble rect) const
191 {
192  if(m_angle == 0.0 || m_angle == 180.0) return m_rect.Intersects(rect);
193  return RotatedRectanglesIntersects(m_rect, rect, m_angle, 0.0);
194 }
195 
196 void Transformer::Rotate(bool clockwise)
197 {
198  double rotAngle = m_rotationAngle;
199  if(!clockwise) rotAngle = -m_rotationAngle;
200 
201  m_angle += rotAngle;
202  if(m_angle >= 360 || m_angle <= -360) m_angle = 0.0;
203 
204  // Rotate all the points, except the switches and buses points.
205  for(int i = 2; i < (int)m_pointList.size() - 2; i++) {
206  m_pointList[i] = RotateAtPosition(m_pointList[i], rotAngle);
207  }
208  UpdateSwitchesPosition();
209  UpdatePowerFlowArrowsPosition();
210 }
211 
212 void Transformer::Move(wxPoint2DDouble position)
213 {
214  SetPosition(m_movePos + position - m_moveStartPt);
215 
216  // Move all the points, except the switches and buses points.
217  for(int i = 2; i < (int)m_pointList.size() - 2; i++) {
218  m_pointList[i] = m_movePts[i] + position - m_moveStartPt;
219  }
220 
221  if(!m_parentList[0]) {
222  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
223  }
224  if(!m_parentList[1]) {
225  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
226  }
227 
228  UpdateSwitchesPosition();
229  UpdatePowerFlowArrowsPosition();
230 }
231 
232 void Transformer::MoveNode(Element* parent, wxPoint2DDouble position)
233 {
234  if(parent) {
235  // First bus.
236  if(parent == m_parentList[0]) {
237  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
238  }
239  // Second bus.
240  else if(parent == m_parentList[1]) {
241  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
242  }
243  } else {
244  if(m_activeNodeID == 1) {
245  m_pointList[0] = m_movePts[0] + position - m_moveStartPt;
246  if(m_parentList[0]) {
247  m_parentList[0]->RemoveChild(this);
248  m_parentList[0] = NULL;
249  m_online = false;
250  }
251  } else if(m_activeNodeID == 2) {
252  m_pointList[m_pointList.size() - 1] = m_movePts[m_pointList.size() - 1] + position - m_moveStartPt;
253  if(m_parentList[1]) {
254  m_parentList[1]->RemoveChild(this);
255  m_parentList[1] = NULL;
256  m_online = false;
257  }
258  }
259  }
260 
261  // Recalculate switches positions
262  UpdateSwitchesPosition();
263  UpdatePowerFlowArrowsPosition();
264 }
265 
266 void Transformer::StartMove(wxPoint2DDouble position)
267 {
268  m_moveStartPt = position;
269  m_movePts = m_pointList;
270  m_movePos = m_position;
271 }
272 
273 bool Transformer::GetContextMenu(wxMenu& menu)
274 {
275  menu.Append(ID_EDIT_ELEMENT, _("Edit tranformer"));
276  GeneralMenuItens(menu);
277  return true;
278 }
279 
280 bool Transformer::ShowForm(wxWindow* parent, Element* element)
281 {
282  TransformerForm* transfForm = new TransformerForm(parent, this);
283  if(transfForm->ShowModal() == wxID_OK) {
284  transfForm->Destroy();
285  return true;
286  }
287  transfForm->Destroy();
288  return false;
289 }
290 
291 void Transformer::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
292 {
293  if(nominalVoltage.size() == 1) {
294  m_electricalData.primaryNominalVoltage = nominalVoltage[0];
295  m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
296  } else if(nominalVoltage.size() == 2) {
297  m_electricalData.primaryNominalVoltage = nominalVoltage[0];
298  m_electricalData.primaryNominalVoltageUnit = nominalVoltageUnit[0];
299  m_electricalData.secondaryNominalVoltage = nominalVoltage[1];
300  m_electricalData.secondaryNominalVoltageUnit = nominalVoltageUnit[1];
301  }
302 }
303 
304 void Transformer::UpdatePowerFlowArrowsPosition()
305 {
306  std::vector<wxPoint2DDouble> edges;
307  switch(m_pfDirection) {
308  case PF_NONE: {
309  m_powerFlowArrow.clear();
310  } break;
311  case PF_BUS1_TO_BUS2: {
312  for(int i = 1; i < (int)m_pointList.size() - 1; i++) {
313  edges.push_back(m_pointList[i]);
314  }
315  } break;
316  case PF_BUS2_TO_BUS1: {
317  for(int i = (int)m_pointList.size() - 2; i > 0; i--) {
318  edges.push_back(m_pointList[i]);
319  }
320  } break;
321  default:
322  break;
323  }
324  CalculatePowerFlowPts(edges);
325 }
326 
327 void Transformer::RotateNode(Element* parent, bool clockwise)
328 {
329  double rotAngle = m_rotationAngle;
330  if(!clockwise) rotAngle = -m_rotationAngle;
331 
332  if(parent == m_parentList[0]) {
333  m_pointList[0] = parent->RotateAtPosition(m_pointList[0], rotAngle);
334  } else if(parent == m_parentList[1]) {
335  m_pointList[m_pointList.size() - 1] = parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], rotAngle);
336  }
337  UpdateSwitchesPosition();
338  UpdatePowerFlowArrowsPosition();
339 }
340 
342 {
343  if(m_activeNodeID == 1 && parent == m_parentList[0]) return false;
344  if(m_activeNodeID == 2 && parent == m_parentList[1]) return false;
345 
346  if(parent && m_activeNodeID != 0) {
347  wxRect2DDouble nodeRect(0, 0, 0, 0);
348  if(m_activeNodeID == 1) {
349  nodeRect = wxRect2DDouble(m_pointList[0].m_x - 5.0 - m_borderSize, m_pointList[0].m_y - 5.0 - m_borderSize,
350  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
351  }
352  if(m_activeNodeID == 2) {
353  nodeRect = wxRect2DDouble(m_pointList[m_pointList.size() - 1].m_x - 5.0 - m_borderSize,
354  m_pointList[m_pointList.size() - 1].m_y - 5.0 - m_borderSize,
355  10 + 2.0 * m_borderSize, 10 + 2.0 * m_borderSize);
356  }
357 
358  if(parent->Intersects(nodeRect)) {
359  if(m_activeNodeID == 1) {
360  // Check if the user is trying to connect the same bus.
361  if(m_parentList[1] == parent) {
362  m_activeNodeID = 0;
363  return false;
364  }
365 
366  m_parentList[0] = parent;
367 
368  // Centralize the node on bus.
369  wxPoint2DDouble parentPt = parent->RotateAtPosition(
370  m_pointList[0], -parent->GetAngle()); // Rotate click to horizontal position.
371  parentPt.m_y = parent->GetPosition().m_y; // Centralize on bus.
372  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
373  m_pointList[0] = parentPt;
374 
375  UpdateSwitchesPosition();
376  UpdatePowerFlowArrowsPosition();
377  return true;
378  }
379  if(m_activeNodeID == 2) {
380  if(m_parentList[0] == parent) {
381  m_activeNodeID = 0;
382  return false;
383  }
384 
385  m_parentList[1] = parent;
386 
387  wxPoint2DDouble parentPt =
388  parent->RotateAtPosition(m_pointList[m_pointList.size() - 1], -parent->GetAngle());
389  parentPt.m_y = parent->GetPosition().m_y;
390  parentPt = parent->RotateAtPosition(parentPt, parent->GetAngle());
391  m_pointList[m_pointList.size() - 1] = parentPt;
392 
393  UpdateSwitchesPosition();
394  UpdatePowerFlowArrowsPosition();
395  return true;
396  }
397  } else {
398  if(m_activeNodeID == 1) m_parentList[0] = NULL;
399  if(m_activeNodeID == 2) m_parentList[1] = NULL;
400  }
401  }
402  return false;
403 }
404 
406 {
407  m_pfDirection = pfDirection;
408  UpdatePowerFlowArrowsPosition();
409 }
410 
412 {
413  Transformer* copy = new Transformer();
414  *copy = *this;
415  return copy;
416 }
417 
418 wxString Transformer::GetTipText() const
419 {
420  wxString tipText = m_electricalData.name;
421  wxString primVoltage = StringFromDouble(m_electricalData.primaryNominalVoltage);
422  switch(m_electricalData.primaryNominalVoltageUnit) {
423  case UNIT_V: {
424  primVoltage += _(" V");
425  } break;
426  case UNIT_kV: {
427  primVoltage += _(" kV");
428  } break;
429  default:
430  break;
431  }
432  wxString secVoltage = StringFromDouble(m_electricalData.secondaryNominalVoltage);
433  switch(m_electricalData.secondaryNominalVoltageUnit) {
434  case UNIT_V: {
435  secVoltage += _(" V");
436  } break;
437  case UNIT_kV: {
438  secVoltage += _(" kV");
439  } break;
440  default:
441  break;
442  }
443 
444  tipText += "\n" + primVoltage + " / " + secVoltage;
445 
446  if(m_online) {
447  tipText += "\n";
448  int busNumber[2];
449  busNumber[0] = static_cast<Bus*>(m_parentList[0])->GetElectricalData().number + 1;
450  busNumber[1] = static_cast<Bus*>(m_parentList[1])->GetElectricalData().number + 1;
451 
452  tipText += _("\nP") + wxString::Format("(%d-%d) = ", busNumber[0], busNumber[1]) +
453  wxString::FromDouble(m_electricalData.powerFlow[0].real(), 5) + _(" p.u.");
454  tipText += _("\nQ") + wxString::Format("(%d-%d) = ", busNumber[0], busNumber[1]) +
455  wxString::FromDouble(m_electricalData.powerFlow[0].imag(), 5) + _(" p.u.");
456  tipText += _("\nP") + wxString::Format("(%d-%d) = ", busNumber[1], busNumber[0]) +
457  wxString::FromDouble(m_electricalData.powerFlow[1].real(), 5) + _(" p.u.");
458  tipText += _("\nQ") + wxString::Format("(%d-%d) = ", busNumber[1], busNumber[0]) +
459  wxString::FromDouble(m_electricalData.powerFlow[1].imag(), 5) + _(" p.u.");
460  }
461 
462  return tipText;
463 }
464 
465 TransformerElectricalData Transformer::GetPUElectricalData(double systemBasePower)
466 {
467  TransformerElectricalData data = m_electricalData;
468  double transformerBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit);
469  double baseVoltage = 0.0;
470  if(data.baseVoltage == 0) {
471  baseVoltage = GetValueFromUnit(data.primaryNominalVoltage, data.primaryNominalVoltageUnit);
472  } else {
473  baseVoltage = GetValueFromUnit(data.secondaryNominalVoltage, data.secondaryNominalVoltageUnit);
474  }
475  double systemBaseImpedance = (baseVoltage * baseVoltage) / systemBasePower;
476  double transformerBaseImpedance = (baseVoltage * baseVoltage) / transformerBasePower;
477 
478  // Resistance
479  double r = data.resistance;
480  if(data.resistanceUnit == UNIT_PU) {
481  if(data.useTransformerPower) data.resistance = (r * transformerBaseImpedance) / systemBaseImpedance;
482  } else {
483  data.resistance = r / systemBaseImpedance;
484  }
485  data.resistanceUnit = UNIT_PU;
486 
487  // Indutive reactance
488  double x = data.indReactance;
489  if(data.indReactanceUnit == UNIT_PU) {
490  if(data.useTransformerPower) data.indReactance = (x * transformerBaseImpedance) / systemBaseImpedance;
491  } else {
492  data.indReactance = x / systemBaseImpedance;
493  }
494  data.indReactanceUnit = UNIT_PU;
495 
496  // Fault
497 
498  // Zero seq. resistance
499  double r0 = data.zeroResistance;
500  if(data.useTransformerPower) data.zeroResistance = (r0 * transformerBaseImpedance) / systemBaseImpedance;
501 
502  // Zero seq. ind. reactance
503  double x0 = data.zeroIndReactance;
504  if(data.useTransformerPower) data.zeroIndReactance = (x0 * transformerBaseImpedance) / systemBaseImpedance;
505 
506  // Primary ground resistance
507  double rgp = data.primaryGrndResistance;
508  if(data.useTransformerPower) data.primaryGrndResistance = (rgp * transformerBaseImpedance) / systemBaseImpedance;
509 
510  // Primary ground ind reactance
511  double xgp = data.primaryGrndReactance;
512  if(data.useTransformerPower) data.primaryGrndReactance = (xgp * transformerBaseImpedance) / systemBaseImpedance;
513 
514  // Secondary ground resistance
515  double rgs = data.secondaryGrndResistance;
516  if(data.useTransformerPower) data.secondaryGrndResistance = (rgs * transformerBaseImpedance) / systemBaseImpedance;
517 
518  // Secondary ground ind reactance
519  double xgs = data.secondaryGrndReactance;
520  if(data.useTransformerPower) data.secondaryGrndReactance = (xgs * transformerBaseImpedance) / systemBaseImpedance;
521 
522  if(!m_online) {
523  data.powerFlow[0] = std::complex<double>(0, 0);
524  data.powerFlow[1] = std::complex<double>(0, 0);
525  data.faultCurrent[0][0] = std::complex<double>(0, 0);
526  data.faultCurrent[0][1] = std::complex<double>(0, 0);
527  data.faultCurrent[0][2] = std::complex<double>(0, 0);
528  data.faultCurrent[1][0] = std::complex<double>(0, 0);
529  data.faultCurrent[1][1] = std::complex<double>(0, 0);
530  data.faultCurrent[1][2] = std::complex<double>(0, 0);
531  }
532 
533  return data;
534 }
double GetAngle() const
Get the element angle.
Definition: Element.h:212
virtual Element * GetCopy()
Get a the element copy.
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
virtual void Rotate(bool clockwise=true)
Rotate the element.
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
@@ -104,7 +105,7 @@ $(document).ready(function(){initNavTree('_transformer_8cpp_source.html','');});
Form to edit the transformer power data.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection)
Set the direction of the power flow.
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
@@ -115,7 +116,7 @@ $(document).ready(function(){initNavTree('_transformer_8cpp_source.html','');});
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
- +
Class to manage color of OpenGL.
Definition: Element.h:67
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Transformer.cpp:39
PowerFlowDirection
Direction of power flow arrows.
Definition: PowerElement.h:78
@@ -123,9 +124,9 @@ $(document).ready(function(){initNavTree('_transformer_8cpp_source.html','');});
wxPoint2DDouble GetPosition() const
Get the element position.
Definition: Element.h:187
- +
Two-winding transformer power element.
Definition: Transformer.h:78
const GLdouble * GetRGBA() const
Get colour in RGBA.
Definition: Element.h:101
-
Definition: Branch.h:24
+
Abstract class for branch power elements.
Definition: Branch.h:31
diff --git a/docs/doxygen/html/_transformer_8h.html b/docs/doxygen/html/_transformer_8h.html new file mode 100644 index 0000000..5b3917e --- /dev/null +++ b/docs/doxygen/html/_transformer_8h.html @@ -0,0 +1,136 @@ + + + + + + + + + +Project/Transformer.h File Reference + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Transformer.h File Reference
+
+
+
#include "Branch.h"
+
+

Go to the source code of this file.

+ + + + + + + +

+Classes

struct  TransformerElectricalData
 
class  Transformer
 Two-winding transformer power element. More...
 
+ + + +

+Enumerations

enum  TransformerConnection {
+  GWYE_GWYE = 0, +WYE_GWYE, +GWYE_WYE, +WYE_WYE, +
+  DELTA_GWYE, +DELTA_WYE, +GWYE_DELTA, +WYE_DELTA, +
+  DELTA_DELTA +
+ }
 
+
+
+ + + + diff --git a/docs/doxygen/html/_transformer_8h.js b/docs/doxygen/html/_transformer_8h.js new file mode 100644 index 0000000..0cb13fd --- /dev/null +++ b/docs/doxygen/html/_transformer_8h.js @@ -0,0 +1,16 @@ +var _transformer_8h = +[ + [ "TransformerElectricalData", "struct_transformer_electrical_data.html", "struct_transformer_electrical_data" ], + [ "Transformer", "class_transformer.html", "class_transformer" ], + [ "TransformerConnection", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06", [ + [ "GWYE_GWYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06a4f417627b015a8fed7b3ebf0f8e0fdfe", null ], + [ "WYE_GWYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06afc14c39ecae15fd6b25da581ab530ed5", null ], + [ "GWYE_WYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06add500826fddc4ad0105a8d88bb8e8da7", null ], + [ "WYE_WYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06ac9f8b56645f38eb0620cb69a914f3095", null ], + [ "DELTA_GWYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06a53db8ed07cc0e8c5b6cd377bf2a37e4f", null ], + [ "DELTA_WYE", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06acdee63c4174046055f9c960c38178741", null ], + [ "GWYE_DELTA", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06a18d745d4045365a77ecf886610922218", null ], + [ "WYE_DELTA", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06ae69f44260b5da3ed29f47164d6b97de0", null ], + [ "DELTA_DELTA", "_transformer_8h.html#ace6b3807048fabdaa8bbf0c8f8860d06a5f05b987519c9c5bdc532be11940c61a", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/doxygen/html/_transformer_8h_source.html b/docs/doxygen/html/_transformer_8h_source.html index 7e5bca5..7a44441 100644 --- a/docs/doxygen/html/_transformer_8h_source.html +++ b/docs/doxygen/html/_transformer_8h_source.html @@ -88,22 +88,23 @@ $(document).ready(function(){initNavTree('_transformer_8h_source.html','');});
Transformer.h
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFORMER_H
19 #define TRANSFORMER_H
20 
21 #include "Branch.h"
22 
23 class TransformerForm;
24 
25 enum TransformerConnection {
26  GWYE_GWYE = 0,
27  WYE_GWYE,
28  GWYE_WYE,
29  WYE_WYE,
30  DELTA_GWYE,
31  DELTA_WYE,
32  GWYE_DELTA,
33  WYE_DELTA,
34  DELTA_DELTA
35 };
36 
38  // General
39  wxString name = "";
40  double primaryNominalVoltage = 138.0;
41  ElectricalUnit primaryNominalVoltageUnit = UNIT_kV;
42  double secondaryNominalVoltage = 138.0;
43  ElectricalUnit secondaryNominalVoltageUnit = UNIT_kV;
44  int baseVoltage = 0;
45  double nominalPower = 100.0;
46  ElectricalUnit nominalPowerUnit = UNIT_MVA;
47  double resistance = 0.0;
48  ElectricalUnit resistanceUnit = UNIT_PU;
49  double indReactance = 1.0;
50  ElectricalUnit indReactanceUnit = UNIT_PU;
51  TransformerConnection connection = GWYE_GWYE;
52  double turnsRatio = 1.0;
53  double phaseShift = 0.0;
54  bool useTransformerPower = false;
55 
56  // Power flow (p.u.)
57  std::complex<double> current[2] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0)};
58  std::complex<double> powerFlow[2] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0)};
59 
60  // Fault
61  double zeroResistance = 0.0;
62  double zeroIndReactance = 1.0;
63  double primaryGrndResistance = 0.0;
64  double primaryGrndReactance = 0.0;
65  double secondaryGrndResistance = 0.0;
66  double secondaryGrndReactance = 0.0;
67  // p.u. fault data
68  std::complex<double> faultCurrent[2][3];
69 };
70 
71 class Transformer : public Branch
72 {
73  public:
74  Transformer();
75  Transformer(wxString name);
76  virtual ~Transformer();
77 
78  virtual Element* GetCopy();
79  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
80  virtual bool Contains(wxPoint2DDouble position) const;
81  virtual void Draw(wxPoint2DDouble translation, double scale) const;
82  virtual bool Intersects(wxRect2DDouble rect) const;
83  virtual void Rotate(bool clockwise = true);
84  virtual void Move(wxPoint2DDouble position);
85  virtual void MoveNode(Element* parent, wxPoint2DDouble position);
86  virtual void StartMove(wxPoint2DDouble position);
87  virtual bool GetContextMenu(wxMenu& menu);
88  virtual wxString GetTipText() const;
89  virtual void RotateNode(Element* parent, bool clockwise);
90  virtual bool SetNodeParent(Element* parent);
91  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection);
92  virtual bool ShowForm(wxWindow* parent, Element* element);
93  virtual TransformerElectricalData GetElectricalData() const { return m_electricalData; }
94  virtual TransformerElectricalData GetPUElectricalData(double systemBasePower);
95  virtual void SetElectricaData(TransformerElectricalData electricalData) { m_electricalData = electricalData; }
96  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
97 
98  protected:
99  void UpdatePowerFlowArrowsPosition();
100  TransformerElectricalData m_electricalData;
101 };
102 
103 #endif // TRANSFORMER_H
+Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFORMER_H
19 #define TRANSFORMER_H
20 
21 #include "Branch.h"
22 
23 class TransformerForm;
24 
25 enum TransformerConnection {
26  GWYE_GWYE = 0,
27  WYE_GWYE,
28  GWYE_WYE,
29  WYE_WYE,
30  DELTA_GWYE,
31  DELTA_WYE,
32  GWYE_DELTA,
33  WYE_DELTA,
34  DELTA_DELTA
35 };
36 
38  // General
39  wxString name = "";
40  double primaryNominalVoltage = 138.0;
41  ElectricalUnit primaryNominalVoltageUnit = UNIT_kV;
42  double secondaryNominalVoltage = 138.0;
43  ElectricalUnit secondaryNominalVoltageUnit = UNIT_kV;
44  int baseVoltage = 0;
45  double nominalPower = 100.0;
46  ElectricalUnit nominalPowerUnit = UNIT_MVA;
47  double resistance = 0.0;
48  ElectricalUnit resistanceUnit = UNIT_PU;
49  double indReactance = 1.0;
50  ElectricalUnit indReactanceUnit = UNIT_PU;
51  TransformerConnection connection = GWYE_GWYE;
52  double turnsRatio = 1.0;
53  double phaseShift = 0.0;
54  bool useTransformerPower = false;
55 
56  // Power flow (p.u.)
57  std::complex<double> current[2] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0)};
58  std::complex<double> powerFlow[2] = {std::complex<double>(0.0, 0.0), std::complex<double>(0.0, 0.0)};
59 
60  // Fault
61  double zeroResistance = 0.0;
62  double zeroIndReactance = 1.0;
63  double primaryGrndResistance = 0.0;
64  double primaryGrndReactance = 0.0;
65  double secondaryGrndResistance = 0.0;
66  double secondaryGrndReactance = 0.0;
67  // p.u. fault data
68  std::complex<double> faultCurrent[2][3];
69 };
70 
78 class Transformer : public Branch
79 {
80  public:
81  Transformer();
82  Transformer(wxString name);
83  virtual ~Transformer();
84 
85  virtual Element* GetCopy();
86  virtual bool AddParent(Element* parent, wxPoint2DDouble position);
87  virtual bool Contains(wxPoint2DDouble position) const;
88  virtual void Draw(wxPoint2DDouble translation, double scale) const;
89  virtual bool Intersects(wxRect2DDouble rect) const;
90  virtual void Rotate(bool clockwise = true);
91  virtual void Move(wxPoint2DDouble position);
92  virtual void MoveNode(Element* parent, wxPoint2DDouble position);
93  virtual void StartMove(wxPoint2DDouble position);
94  virtual bool GetContextMenu(wxMenu& menu);
95  virtual wxString GetTipText() const;
96  virtual void RotateNode(Element* parent, bool clockwise);
97  virtual bool SetNodeParent(Element* parent);
98  virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection);
99  virtual bool ShowForm(wxWindow* parent, Element* element);
100  virtual TransformerElectricalData GetElectricalData() const { return m_electricalData; }
101  virtual TransformerElectricalData GetPUElectricalData(double systemBasePower);
102  virtual void SetElectricaData(TransformerElectricalData electricalData) { m_electricalData = electricalData; }
103  virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
104 
105  protected:
106  void UpdatePowerFlowArrowsPosition();
107  TransformerElectricalData m_electricalData;
108 };
109 
110 #endif // TRANSFORMER_H
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
Form to edit the transformer power data.
+
PowerFlowDirection
Direction of power flow arrows.
Definition: PowerElement.h:78
- -
Definition: Branch.h:24
+
Two-winding transformer power element.
Definition: Transformer.h:78
+
Abstract class for branch power elements.
Definition: Branch.h:31
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransformerForm.h"
19 #include "SwitchingForm.h"
20 #include "Transformer.h"
21 
22 TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : TransformerFormBase(parent)
23 {
24  m_choiceResistance->SetString(1, L'\u03A9');
25  m_choiceReactance->SetString(1, L'\u03A9');
26 
27  // Reset connections choice labels (to be translated)
28  m_choiceConnection->SetString(0, _("Grounded Wye - Grounded Wye"));
29  m_choiceConnection->SetString(1, _("Wye - Grounded Wye"));
30  m_choiceConnection->SetString(2, _("Grounded Wye - Wye"));
31  m_choiceConnection->SetString(3, _("Wye - Wye"));
32  m_choiceConnection->SetString(4, _("Delta - Grounded Wye"));
33  m_choiceConnection->SetString(5, _("Delta - Wye"));
34  m_choiceConnection->SetString(6, _("Grounded Wye - Delta"));
35  m_choiceConnection->SetString(7, _("Wye - Delta"));
36  m_choiceConnection->SetString(8, _("Delta - Delta"));
37 
38  SetSize(GetBestSize());
39  Layout();
40 
41  m_parent = parent;
42  m_transformer = transformer;
43 
44  TransformerElectricalData data = transformer->GetElectricalData();
45 
46  m_textCtrlName->SetValue(data.name);
47 
48  wxString primVoltStr = Transformer::StringFromDouble(data.primaryNominalVoltage);
49  switch(data.primaryNominalVoltageUnit) {
50  case UNIT_V: {
51  primVoltStr += " V";
52  } break;
53  case UNIT_kV: {
54  primVoltStr += " kV";
55  } break;
56  default:
57  break;
58  }
59  wxString secVoltStr = Transformer::StringFromDouble(data.secondaryNominalVoltage);
60  switch(data.secondaryNominalVoltageUnit) {
61  case UNIT_V: {
62  secVoltStr += " V";
63  } break;
64  case UNIT_kV: {
65  secVoltStr += " kV";
66  } break;
67  default:
68  break;
69  }
70  m_staticTextNominalVoltageValue->SetLabel(wxString::Format("%s / %s", primVoltStr, secVoltStr));
71 
72  m_choiceBaseVoltage->SetString(0, primVoltStr);
73  m_choiceBaseVoltage->SetString(1, secVoltStr);
74  m_choiceBaseVoltage->SetSelection(data.baseVoltage);
75 
76  m_textCtrlNominalPower->SetValue(Transformer::StringFromDouble(data.nominalPower));
77  switch(data.nominalPowerUnit) {
78  case UNIT_VA: {
79  m_choiceNominalPower->SetSelection(0);
80  } break;
81  case UNIT_kVA: {
82  m_choiceNominalPower->SetSelection(1);
83  } break;
84  case UNIT_MVA: {
85  m_choiceNominalPower->SetSelection(2);
86  } break;
87  default:
88  break;
89  }
90 
91  m_textCtrlResistance->SetValue(Transformer::StringFromDouble(data.resistance));
92  switch(data.resistanceUnit) {
93  case UNIT_PU: {
94  m_choiceResistance->SetSelection(0);
95  } break;
96  case UNIT_OHM: {
97  m_choiceResistance->SetSelection(1);
98  } break;
99  default:
100  break;
101  }
102 
103  m_textCtrlReactance->SetValue(Transformer::StringFromDouble(data.indReactance));
104  switch(data.indReactanceUnit) {
105  case UNIT_PU: {
106  m_choiceReactance->SetSelection(0);
107  } break;
108  case UNIT_OHM: {
109  m_choiceReactance->SetSelection(1);
110  } break;
111  default:
112  break;
113  }
114 
115  m_choiceConnection->SetSelection(data.connection);
116 
117  m_textCtrlTurnRatio->SetValue(Transformer::StringFromDouble(data.turnsRatio));
118  m_textCtrlPhaseShift->SetValue(Transformer::StringFromDouble(data.phaseShift));
119 
120  m_checkUseTransformerPower->SetValue(data.useTransformerPower);
121 
122  m_textCtrlZeroResistance->SetValue(Transformer::StringFromDouble(data.zeroResistance));
123  m_textCtrlZeroReactance->SetValue(Transformer::StringFromDouble(data.zeroIndReactance));
124  m_textCtrlPrimResistance->SetValue(Transformer::StringFromDouble(data.primaryGrndResistance));
125  m_textCtrlPrimReactance->SetValue(Transformer::StringFromDouble(data.primaryGrndReactance));
126  m_textCtrlSecResistance->SetValue(Transformer::StringFromDouble(data.secondaryGrndResistance));
127  m_textCtrlSecReactance->SetValue(Transformer::StringFromDouble(data.secondaryGrndReactance));
128 }
129 
130 TransformerForm::~TransformerForm() {}
131 void TransformerForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
132 void TransformerForm::OnOKButtonClick(wxCommandEvent& event)
133 {
134  if(ValidateData()) EndModal(wxID_OK);
135 }
136 void TransformerForm::OnStabilityButtonClick(wxCommandEvent& event)
137 {
138  if(ValidateData()) {
139  SwitchingForm swForm(m_parent, m_transformer);
140  swForm.SetTitle(_("Transfomer: Switching"));
141  swForm.ShowModal();
142  EndModal(wxID_OK);
143  }
144 }
145 
146 bool TransformerForm::ValidateData()
147 {
148  TransformerElectricalData data = m_transformer->GetElectricalData();
149 
150  data.name = m_textCtrlName->GetValue();
151  data.baseVoltage = m_choiceBaseVoltage->GetSelection();
152 
153  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlNominalPower->GetValue(), data.nominalPower,
154  _("Value entered incorrectly in the field \"Nominal power\".")))
155  return false;
156  switch(m_choiceNominalPower->GetSelection()) {
157  case 0: {
158  data.nominalPowerUnit = UNIT_VA;
159  } break;
160  case 1: {
161  data.nominalPowerUnit = UNIT_kVA;
162  } break;
163  case 2: {
164  data.nominalPowerUnit = UNIT_MVA;
165  } break;
166  }
167 
168  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlResistance->GetValue(), data.resistance,
169  _("Value entered incorrectly in the field \"Resistance\".")))
170  return false;
171  switch(m_choiceResistance->GetSelection()) {
172  case 0: {
173  data.resistanceUnit = UNIT_PU;
174  } break;
175  case 1: {
176  data.resistanceUnit = UNIT_OHM;
177  } break;
178  }
179 
180  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlReactance->GetValue(), data.indReactance,
181  _("Value entered incorrectly in the field \"Indutive reactance\".")))
182  return false;
183  switch(m_choiceReactance->GetSelection()) {
184  case 0: {
185  data.indReactanceUnit = UNIT_PU;
186  } break;
187  case 1: {
188  data.indReactanceUnit = UNIT_OHM;
189  } break;
190  }
191 
192  switch(m_choiceConnection->GetSelection()) {
193  case 0: {
194  data.connection = GWYE_GWYE;
195  } break;
196  case 1: {
197  data.connection = WYE_GWYE;
198  } break;
199  case 2: {
200  data.connection = GWYE_WYE;
201  } break;
202  case 3: {
203  data.connection = WYE_WYE;
204  } break;
205  case 4: {
206  data.connection = DELTA_GWYE;
207  } break;
208  case 5: {
209  data.connection = DELTA_WYE;
210  } break;
211  case 6: {
212  data.connection = GWYE_DELTA;
213  } break;
214  case 7: {
215  data.connection = WYE_DELTA;
216  } break;
217  case 8: {
218  data.connection = DELTA_DELTA;
219  } break;
220  }
221 
222  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlTurnRatio->GetValue(), data.turnsRatio,
223  _("Value entered incorrectly in the field \"Turns ratio\".")))
224  return false;
225 
226  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPhaseShift->GetValue(), data.phaseShift,
227  _("Value entered incorrectly in the field \"Phase shift\".")))
228  return false;
229 
230  data.useTransformerPower = m_checkUseTransformerPower->GetValue();
231 
232  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
233  _("Value entered incorrectly in the field \"Zero sequence resistance\".")))
234  return false;
235 
236  if(!m_transformer->DoubleFromString(
237  m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroIndReactance,
238  _("Value entered incorrectly in the field \"Zero sequence indutive reactance\".")))
239  return false;
240 
241  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPrimResistance->GetValue(), data.primaryGrndResistance,
242  _("Value entered incorrectly in the field \"Primary ground resistance\".")))
243  return false;
244 
245  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPrimReactance->GetValue(), data.primaryGrndReactance,
246  _("Value entered incorrectly in the field \"Primary ground reactance\".")))
247  return false;
248 
249  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlSecResistance->GetValue(), data.secondaryGrndResistance,
250  _("Value entered incorrectly in the field \"Secondary ground resistance\".")))
251  return false;
252 
253  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlSecReactance->GetValue(), data.secondaryGrndReactance,
254  _("Value entered incorrectly in the field \"Secondary ground reactance\".")))
255  return false;
256 
257  m_transformer->SetElectricaData(data);
258  return true;
259 }
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "TransformerForm.h"
19 #include "SwitchingForm.h"
20 #include "Transformer.h"
21 
22 TransformerForm::TransformerForm(wxWindow* parent, Transformer* transformer) : TransformerFormBase(parent)
23 {
24  m_choiceResistance->SetString(1, L'\u03A9');
25  m_choiceReactance->SetString(1, L'\u03A9');
26 
27  // Reset connections choice labels (to be translated)
28  m_choiceConnection->SetString(0, _("Grounded Wye - Grounded Wye"));
29  m_choiceConnection->SetString(1, _("Wye - Grounded Wye"));
30  m_choiceConnection->SetString(2, _("Grounded Wye - Wye"));
31  m_choiceConnection->SetString(3, _("Wye - Wye"));
32  m_choiceConnection->SetString(4, _("Delta - Grounded Wye"));
33  m_choiceConnection->SetString(5, _("Delta - Wye"));
34  m_choiceConnection->SetString(6, _("Grounded Wye - Delta"));
35  m_choiceConnection->SetString(7, _("Wye - Delta"));
36  m_choiceConnection->SetString(8, _("Delta - Delta"));
37 
38  SetSize(GetBestSize());
39  Layout();
40 
41  m_parent = parent;
42  m_transformer = transformer;
43 
44  TransformerElectricalData data = transformer->GetElectricalData();
45 
46  m_textCtrlName->SetValue(data.name);
47 
48  wxString primVoltStr = Transformer::StringFromDouble(data.primaryNominalVoltage);
49  switch(data.primaryNominalVoltageUnit) {
50  case UNIT_V: {
51  primVoltStr += " V";
52  } break;
53  case UNIT_kV: {
54  primVoltStr += " kV";
55  } break;
56  default:
57  break;
58  }
59  wxString secVoltStr = Transformer::StringFromDouble(data.secondaryNominalVoltage);
60  switch(data.secondaryNominalVoltageUnit) {
61  case UNIT_V: {
62  secVoltStr += " V";
63  } break;
64  case UNIT_kV: {
65  secVoltStr += " kV";
66  } break;
67  default:
68  break;
69  }
70  m_staticTextNominalVoltageValue->SetLabel(wxString::Format("%s / %s", primVoltStr, secVoltStr));
71 
72  m_choiceBaseVoltage->SetString(0, primVoltStr);
73  m_choiceBaseVoltage->SetString(1, secVoltStr);
74  m_choiceBaseVoltage->SetSelection(data.baseVoltage);
75 
76  m_textCtrlNominalPower->SetValue(Transformer::StringFromDouble(data.nominalPower));
77  switch(data.nominalPowerUnit) {
78  case UNIT_VA: {
79  m_choiceNominalPower->SetSelection(0);
80  } break;
81  case UNIT_kVA: {
82  m_choiceNominalPower->SetSelection(1);
83  } break;
84  case UNIT_MVA: {
85  m_choiceNominalPower->SetSelection(2);
86  } break;
87  default:
88  break;
89  }
90 
91  m_textCtrlResistance->SetValue(Transformer::StringFromDouble(data.resistance));
92  switch(data.resistanceUnit) {
93  case UNIT_PU: {
94  m_choiceResistance->SetSelection(0);
95  } break;
96  case UNIT_OHM: {
97  m_choiceResistance->SetSelection(1);
98  } break;
99  default:
100  break;
101  }
102 
103  m_textCtrlReactance->SetValue(Transformer::StringFromDouble(data.indReactance));
104  switch(data.indReactanceUnit) {
105  case UNIT_PU: {
106  m_choiceReactance->SetSelection(0);
107  } break;
108  case UNIT_OHM: {
109  m_choiceReactance->SetSelection(1);
110  } break;
111  default:
112  break;
113  }
114 
115  m_choiceConnection->SetSelection(data.connection);
116 
117  m_textCtrlTurnRatio->SetValue(Transformer::StringFromDouble(data.turnsRatio));
118  m_textCtrlPhaseShift->SetValue(Transformer::StringFromDouble(data.phaseShift));
119 
120  m_checkUseTransformerPower->SetValue(data.useTransformerPower);
121 
122  m_textCtrlZeroResistance->SetValue(Transformer::StringFromDouble(data.zeroResistance));
123  m_textCtrlZeroReactance->SetValue(Transformer::StringFromDouble(data.zeroIndReactance));
124  m_textCtrlPrimResistance->SetValue(Transformer::StringFromDouble(data.primaryGrndResistance));
125  m_textCtrlPrimReactance->SetValue(Transformer::StringFromDouble(data.primaryGrndReactance));
126  m_textCtrlSecResistance->SetValue(Transformer::StringFromDouble(data.secondaryGrndResistance));
127  m_textCtrlSecReactance->SetValue(Transformer::StringFromDouble(data.secondaryGrndReactance));
128 }
129 
130 TransformerForm::~TransformerForm() {}
131 void TransformerForm::OnCancelButtonClick(wxCommandEvent& event) { EndModal(wxID_CANCEL); }
132 void TransformerForm::OnOKButtonClick(wxCommandEvent& event)
133 {
134  if(ValidateData()) EndModal(wxID_OK);
135 }
136 void TransformerForm::OnStabilityButtonClick(wxCommandEvent& event)
137 {
138  if(ValidateData()) {
139  SwitchingForm swForm(m_parent, m_transformer);
140  swForm.SetTitle(_("Transfomer: Switching"));
141  swForm.ShowModal();
142  EndModal(wxID_OK);
143  }
144 }
145 
146 bool TransformerForm::ValidateData()
147 {
148  TransformerElectricalData data = m_transformer->GetElectricalData();
149 
150  data.name = m_textCtrlName->GetValue();
151  data.baseVoltage = m_choiceBaseVoltage->GetSelection();
152 
153  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlNominalPower->GetValue(), data.nominalPower,
154  _("Value entered incorrectly in the field \"Nominal power\".")))
155  return false;
156  switch(m_choiceNominalPower->GetSelection()) {
157  case 0: {
158  data.nominalPowerUnit = UNIT_VA;
159  } break;
160  case 1: {
161  data.nominalPowerUnit = UNIT_kVA;
162  } break;
163  case 2: {
164  data.nominalPowerUnit = UNIT_MVA;
165  } break;
166  }
167 
168  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlResistance->GetValue(), data.resistance,
169  _("Value entered incorrectly in the field \"Resistance\".")))
170  return false;
171  switch(m_choiceResistance->GetSelection()) {
172  case 0: {
173  data.resistanceUnit = UNIT_PU;
174  } break;
175  case 1: {
176  data.resistanceUnit = UNIT_OHM;
177  } break;
178  }
179 
180  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlReactance->GetValue(), data.indReactance,
181  _("Value entered incorrectly in the field \"Indutive reactance\".")))
182  return false;
183  switch(m_choiceReactance->GetSelection()) {
184  case 0: {
185  data.indReactanceUnit = UNIT_PU;
186  } break;
187  case 1: {
188  data.indReactanceUnit = UNIT_OHM;
189  } break;
190  }
191 
192  switch(m_choiceConnection->GetSelection()) {
193  case 0: {
194  data.connection = GWYE_GWYE;
195  } break;
196  case 1: {
197  data.connection = WYE_GWYE;
198  } break;
199  case 2: {
200  data.connection = GWYE_WYE;
201  } break;
202  case 3: {
203  data.connection = WYE_WYE;
204  } break;
205  case 4: {
206  data.connection = DELTA_GWYE;
207  } break;
208  case 5: {
209  data.connection = DELTA_WYE;
210  } break;
211  case 6: {
212  data.connection = GWYE_DELTA;
213  } break;
214  case 7: {
215  data.connection = WYE_DELTA;
216  } break;
217  case 8: {
218  data.connection = DELTA_DELTA;
219  } break;
220  }
221 
222  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlTurnRatio->GetValue(), data.turnsRatio,
223  _("Value entered incorrectly in the field \"Turns ratio\".")))
224  return false;
225 
226  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPhaseShift->GetValue(), data.phaseShift,
227  _("Value entered incorrectly in the field \"Phase shift\".")))
228  return false;
229 
230  data.useTransformerPower = m_checkUseTransformerPower->GetValue();
231 
232  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlZeroResistance->GetValue(), data.zeroResistance,
233  _("Value entered incorrectly in the field \"Zero sequence resistance\".")))
234  return false;
235 
236  if(!m_transformer->DoubleFromString(
237  m_parent, m_textCtrlZeroReactance->GetValue(), data.zeroIndReactance,
238  _("Value entered incorrectly in the field \"Zero sequence indutive reactance\".")))
239  return false;
240 
241  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPrimResistance->GetValue(), data.primaryGrndResistance,
242  _("Value entered incorrectly in the field \"Primary ground resistance\".")))
243  return false;
244 
245  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlPrimReactance->GetValue(), data.primaryGrndReactance,
246  _("Value entered incorrectly in the field \"Primary ground reactance\".")))
247  return false;
248 
249  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlSecResistance->GetValue(), data.secondaryGrndResistance,
250  _("Value entered incorrectly in the field \"Secondary ground resistance\".")))
251  return false;
252 
253  if(!m_transformer->DoubleFromString(m_parent, m_textCtrlSecReactance->GetValue(), data.secondaryGrndReactance,
254  _("Value entered incorrectly in the field \"Secondary ground reactance\".")))
255  return false;
256 
257  m_transformer->SetElectricaData(data);
258  return true;
259 }
+
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
@@ -101,7 +102,7 @@ $(document).ready(function(){initNavTree('_transformer_form_8cpp_source.html','' - +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_transformer_form_8h_source.html b/docs/doxygen/html/_transformer_form_8h_source.html index 2f3c75a..081ffc9 100644 --- a/docs/doxygen/html/_transformer_form_8h_source.html +++ b/docs/doxygen/html/_transformer_form_8h_source.html @@ -91,7 +91,7 @@ $(document).ready(function(){initNavTree('_transformer_form_8h_source.html',''); Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TRANSFORMERFORM_H
19 #define TRANSFORMERFORM_H
20 
21 #include "ElementForm.h"
22 
23 class SwitchingForm;
24 class Transformer;
25 
34 {
35  public:
36  TransformerForm(wxWindow* parent, Transformer* transformer);
37  virtual ~TransformerForm();
38  bool ValidateData();
39 
40  protected:
41  virtual void OnCancelButtonClick(wxCommandEvent& event);
42  virtual void OnOKButtonClick(wxCommandEvent& event);
43  virtual void OnStabilityButtonClick(wxCommandEvent& event);
44 
45  wxWindow* m_parent = NULL;
46  Transformer* m_transformer = NULL;
47 };
48 #endif // TRANSFORMERFORM_H
Form to edit the switching data of power elements for electromechanical transient studies...
Definition: SwitchingForm.h:32
Form to edit the transformer power data.
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_workspace_8cpp_source.html b/docs/doxygen/html/_workspace_8cpp_source.html index 8e2926a..6740df2 100644 --- a/docs/doxygen/html/_workspace_8cpp_source.html +++ b/docs/doxygen/html/_workspace_8cpp_source.html @@ -88,19 +88,21 @@ $(document).ready(function(){initNavTree('_workspace_8cpp_source.html','');});
Workspace.cpp
-
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Workspace.h"
19 #include "Camera.h"
20 #include "Element.h"
21 //#include "Bus.h"
22 #include "Line.h"
23 #include "Transformer.h"
24 #include "SyncGenerator.h"
25 #include "IndMotor.h"
26 #include "SyncMotor.h"
27 #include "Load.h"
28 #include "Inductor.h"
29 #include "Capacitor.h"
30 #include "ElementDataObject.h"
31 
32 #include "Text.h"
33 
34 #include "PowerFlow.h"
35 #include "Fault.h"
36 #include "Electromechanical.h"
37 
38 #include "ElementPlotData.h"
39 #include "ChartView.h"
40 
41 #include "PropertiesData.h"
42 
43 // Workspace
44 Workspace::Workspace() : WorkspaceBase(NULL) {}
45 Workspace::Workspace(wxWindow* parent, wxString name, wxStatusBar* statusBar) : WorkspaceBase(parent)
46 {
47  m_timer->Start();
48  m_name = name;
49  m_statusBar = statusBar;
50  m_glContext = new wxGLContext(m_glCanvas);
51  m_camera = new Camera();
52  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
53 
54  for(int i = 0; i < NUM_ELEMENTS; ++i) {
55  m_elementNumber[i] = 1;
56  }
57 
58  const int widths[4] = {-3, -1, 100, 100};
59  m_statusBar->SetStatusWidths(4, widths);
60 
61  m_properties = new PropertiesData();
62 }
63 
64 Workspace::~Workspace()
65 {
66  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
67  if(*it) delete *it;
68  }
69  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
70  if(*it) delete *it;
71  }
72  if(m_camera) delete m_camera;
73  if(m_glContext) delete m_glContext;
74  if(m_tipWindow) delete m_tipWindow;
75  if(m_properties) delete m_properties;
76 }
77 
78 void Workspace::OnPaint(wxPaintEvent& event)
79 {
80  wxPaintDC dc(m_glCanvas);
81  m_glContext->SetCurrent(*m_glCanvas);
82  SetViewport();
83 
84  // Set GLCanvas scale and translation.
85  glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale
86  glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation
87 
88  // Draw
89 
90  // Elements
91  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
92  Element* element = *it;
93  element->Draw(m_camera->GetTranslation(), m_camera->GetScale());
94  }
95 
96  // Texts
97  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
98  Text* text = *it;
99  text->Draw(m_camera->GetTranslation(), m_camera->GetScale());
100  }
101 
102  // Selection rectangle
103  glLineWidth(1.0);
104  glColor4d(0.0, 0.5, 1.0, 1.0);
105  glBegin(GL_LINE_LOOP);
106  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
107  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
108  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
109  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
110  glEnd();
111  glColor4d(0.0, 0.5, 1.0, 0.3);
112  glBegin(GL_QUADS);
113  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
114  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
115  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
116  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
117  glEnd();
118 
119  glFlush(); // Sends all pending information directly to the GPU.
120  m_glCanvas->SwapBuffers();
121  event.Skip();
122 }
123 
124 void Workspace::SetViewport()
125 {
126  glClearColor(1.0, 1.0, 1.0, 1.0); // White background.
127  glClear(GL_COLOR_BUFFER_BIT);
128  glDisable(GL_DEPTH_TEST);
129  glDisable(GL_TEXTURE_2D);
130  glEnable(GL_COLOR_MATERIAL);
131  glEnable(GL_BLEND);
132  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
133  glEnable(GL_LINE_SMOOTH);
134 
135  double width = m_glCanvas->GetSize().x - 1;
136  double height = m_glCanvas->GetSize().y - 1;
137 
138  // Viewport fit the screen.
139  glViewport(0, 0, width, height);
140 
141  glMatrixMode(GL_PROJECTION);
142  glLoadIdentity();
143  gluOrtho2D(0.0, width, height, 0.0);
144 
145  glMatrixMode(GL_MODELVIEW);
146  glLoadIdentity();
147 }
148 
149 void Workspace::OnLeftClickDown(wxMouseEvent& event)
150 {
151  wxPoint clickPoint = event.GetPosition();
152  bool foundElement = false;
153  Element* newElement = NULL;
154  bool showNewElementForm = false;
155  bool clickOnSwitch = false;
156  if(m_mode == MODE_INSERT_TEXT || m_mode == MODE_PASTE || m_mode == MODE_DRAG_PASTE) {
157  m_mode = MODE_EDIT;
158  } else if(m_mode == MODE_INSERT || m_mode == MODE_DRAG_INSERT || m_mode == MODE_DRAG_INSERT_TEXT) {
159  // Get the last element inserted on the list.
160  newElement = *(m_elementList.end() - 1);
161  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
162  Element* element = *it;
163  // Clicked in any element.
164  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
165  // Click at a bus.
166  if(typeid(*element) == typeid(Bus)) {
167  // Select the bus.
168  element->SetSelected();
169  foundElement = true; // Element found.
170  // Add the new element's parent. If the element being inserted returns true, back to
171  // edit mode.
172  if(newElement->AddParent(element, m_camera->ScreenToWorld(clickPoint))) {
173  ValidateElementsVoltages();
174  m_timer->Stop();
175  showNewElementForm = true;
176  m_mode = MODE_EDIT;
177  }
178  }
179  }
180  }
181  // The line element can have an indefined number of points.
182  if(!foundElement) {
183  if(typeid(*newElement) == typeid(Line)) {
184  newElement->AddPoint(m_camera->ScreenToWorld(clickPoint));
185  }
186  }
187  foundElement = true;
188  } else {
189  bool clickPickbox = false;
190  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
191  PowerElement* element = *it;
192  element->ResetPickboxes(); // Reset pickbox state.
193 
194  // Set movement initial position (not necessarily will be moved).
195  element->StartMove(m_camera->ScreenToWorld(clickPoint));
196 
197  // Click in selected element node.
198  if(element->NodeContains(m_camera->ScreenToWorld(clickPoint)) != 0 && element->IsSelected()) {
199  m_mode = MODE_MOVE_NODE;
200  m_disconnectedElement = true;
201  foundElement = true;
202  }
203 
204  // Click in an element.
205  else if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
206  if(!foundElement) {
207  // Select and show pickbox.
208  element->SetSelected();
209  element->ShowPickbox();
210  foundElement = true;
211  }
212  // If pickbox contains the click, move the pickbox
213  if(element->PickboxContains(m_camera->ScreenToWorld(clickPoint))) {
214  m_mode = MODE_MOVE_PICKBOX;
215  clickPickbox = true;
216  }
217  // If didn't found a pickbox, move the element
218  if(!clickPickbox) {
219  m_mode = MODE_MOVE_ELEMENT;
220  }
221  }
222 
223  // Click in a switch.
224  else if(element->SwitchesContains(m_camera->ScreenToWorld(clickPoint))) {
225  element->SetOnline(element->IsOnline() ? false : true);
226  clickOnSwitch = true;
227  }
228  }
229 
230  // Text element
231  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
232  Text* text = *it;
233 
234  text->StartMove(m_camera->ScreenToWorld(clickPoint));
235 
236  if(text->Contains(m_camera->ScreenToWorld(clickPoint))) {
237  if(!foundElement) {
238  text->SetSelected();
239  m_mode = MODE_MOVE_ELEMENT;
240  foundElement = true;
241  }
242  }
243  }
244  }
245 
246  if(!foundElement) {
247  m_mode = MODE_SELECTION_RECT;
248  m_startSelRect = m_camera->ScreenToWorld(clickPoint);
249  }
250 
251  Redraw();
252  UpdateStatusBar();
253 
254  if(showNewElementForm) {
255  if(newElement) {
256  newElement->ShowForm(this, newElement);
257  if(m_continuousCalc) RunStaticStudies();
258  }
259  }
260  if(clickOnSwitch && m_continuousCalc) RunStaticStudies();
261 
262  event.Skip();
263 }
264 
265 void Workspace::OnLeftDoubleClick(wxMouseEvent& event)
266 {
267  bool elementEdited = false;
268  bool clickOnSwitch = false;
269  bool redraw = false;
270 
271  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
272  PowerElement* element = *it;
273 
274  // Click in an element.
275  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
276  bool elementIsBus = false;
277  Bus oldBus;
278  Bus* currentBus = NULL;
279  if((currentBus = dynamic_cast<Bus*>(element))) {
280  elementIsBus = true;
281  oldBus = *currentBus;
282  }
283  m_timer->Stop();
284  element->ShowForm(this, element);
285  elementEdited = true;
286  redraw = true;
287 
288  // If the edited element is a bus and was changed the rated voltage, this voltage must be
289  // propagated through the lines
290  if(elementIsBus) {
291  // The voltage was changed
292  if(oldBus.GetElectricalData().nominalVoltage != currentBus->GetElectricalData().nominalVoltage ||
293  oldBus.GetElectricalData().nominalVoltageUnit !=
294  currentBus->GetElectricalData().nominalVoltageUnit) {
295  // Check if the bus has line as child.
296  std::vector<Element*> childList = element->GetChildList();
297  for(auto itc = childList.begin(), itcEnd = childList.end(); itc != itcEnd; ++itc) {
298  Element* child = *itc;
299  if(typeid(*child) == typeid(Line)) {
300  wxMessageDialog msgDialog(this, _("Do you want to change the rated voltage of the path?"),
301  _("Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
302  if(msgDialog.ShowModal() == wxID_YES)
303  ValidateBusesVoltages(element);
304  else {
305  auto data = currentBus->GetElectricalData();
306  data.nominalVoltage = oldBus.GetElectricalData().nominalVoltage;
307  data.nominalVoltageUnit = oldBus.GetElectricalData().nominalVoltageUnit;
308  currentBus->SetElectricalData(data);
309  }
310  break;
311  }
312  }
313  }
314  ValidateElementsVoltages();
315  }
316  }
317 
318  // Click in a switch.
319  else if(element->SwitchesContains(m_camera->ScreenToWorld(event.GetPosition()))) {
320  element->SetOnline(element->IsOnline() ? false : true);
321  clickOnSwitch = true;
322  }
323  }
324 
325  // Text element
326  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
327  Text* text = *it;
328  if(text->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
329  text->ShowForm(this, GetElementList());
330  redraw = true;
331  }
332  }
333  if(elementEdited) {
334  UpdateTextElements();
335  if(m_continuousCalc) RunStaticStudies();
336  }
337  if(clickOnSwitch && m_continuousCalc) RunStaticStudies();
338 
339  if(redraw) Redraw();
340  m_timer->Start();
341 }
342 
343 void Workspace::OnRightClickDown(wxMouseEvent& event)
344 {
345  bool redraw = false;
346  if(m_mode == MODE_EDIT) {
347  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
348  Element* element = *it;
349  if(element->IsSelected()) {
350  // Show context menu.
351  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
352  element->ShowPickbox(false);
353  wxMenu menu;
354  if(element->GetContextMenu(menu)) {
355  m_timer->Stop();
356  menu.SetClientData(element);
357  menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &Workspace::OnPopupClick, this);
358  PopupMenu(&menu);
359  redraw = true;
360 
361  if(!menu.GetClientData()) break;
362  }
363  element->ResetPickboxes();
364  }
365  }
366  }
367  }
368  if(redraw) Redraw();
369  m_timer->Start();
370 }
371 
372 void Workspace::OnLeftClickUp(wxMouseEvent& event)
373 {
374  // This event (under certain conditions) deselects the elements and back to edit mode or select the elements using
375  // the selection rectangle.
376  bool foundPickbox = false;
377  bool findNewParent = false;
378  bool updateVoltages = false;
379  auto itnp = m_elementList.begin();
380 
381  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
382  Element* element = *it;
383 
384  // The user was moving a pickbox.
385  if(m_mode == MODE_MOVE_PICKBOX) {
386  // Catch only the element that have the pickbox shown.
387  if(element->IsPickboxShown()) {
388  // If the element is a bus, check if a node is outside.
389  if(typeid(*element) == typeid(Bus)) {
390  // Get all the bus children.
391  for(int i = 0; i < (int)m_elementList.size(); i++) {
392  Element* child = m_elementList[i];
393  for(int j = 0; j < (int)child->GetParentList().size(); j++) {
394  Element* parent = child->GetParentList()[j];
395  // The child have a parent that is the element.
396  if(parent == element) {
397  child->UpdateNodes();
398  m_disconnectedElement = true;
399  }
400  }
401  }
402  }
403  }
404  }
405 
406  if(m_mode == MODE_SELECTION_RECT) {
407  if(element->Intersects(m_selectionRect)) {
408  element->SetSelected();
409  } else if(!event.ControlDown()) {
410  element->SetSelected(false);
411  }
412  } else if(m_mode == MODE_MOVE_NODE) {
413  if(element->IsSelected()) {
414  for(int i = 0; i < (int)m_elementList.size(); i++) {
415  Element* parent = m_elementList[i];
416  if(typeid(*parent) == typeid(Bus)) {
417  if(element->SetNodeParent(parent)) {
418  parent->AddChild(element);
419  findNewParent = true;
420  itnp = it;
421  element->ResetNodes();
422  break;
423  }
424  }
425  }
426  // element->ResetNodes();
427  }
428  } else {
429  // Deselect
430  if(!event.ControlDown()) {
431  if(!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
432  element->SetSelected(false);
433  }
434  }
435 
436  if(element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
437  foundPickbox = true;
438  } else {
439  element->ShowPickbox(false);
440  element->ResetPickboxes();
441  }
442  }
443  }
444 
445  // Text element
446  for(auto it = m_textList.begin(); it != m_textList.end(); it++) {
447  Text* text = *it;
448  if(m_mode == MODE_SELECTION_RECT) {
449  if(text->Intersects(m_selectionRect)) {
450  text->SetSelected();
451  } else if(!event.ControlDown()) {
452  text->SetSelected(false);
453  }
454  } else if(!event.ControlDown()) {
455  if(!text->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
456  text->SetSelected(false);
457  }
458  }
459  }
460 
461  if(findNewParent) {
462  std::rotate(itnp, itnp + 1, m_elementList.end());
463  updateVoltages = true;
464  }
465  if(!foundPickbox) {
466  SetCursor(wxCURSOR_ARROW);
467  }
468 
469  if(m_mode != MODE_INSERT) {
470  m_mode = MODE_EDIT;
471  }
472 
473  if(updateVoltages) {
474  ValidateElementsVoltages();
475  }
476 
477  if(m_continuousCalc && m_disconnectedElement) {
478  m_disconnectedElement = false;
479  RunStaticStudies();
480  }
481 
482  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
483  Redraw();
484  UpdateStatusBar();
485 }
486 
487 void Workspace::OnMouseMotion(wxMouseEvent& event)
488 {
489  bool redraw = false;
490  switch(m_mode) {
491  case MODE_INSERT: {
492  Element* newElement = *(m_elementList.end() - 1); // Get the last element in the list.
493  newElement->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
494  redraw = true;
495  } break;
496 
497  case MODE_INSERT_TEXT: {
498  Text* newText = *(m_textList.end() - 1);
499  newText->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
500  redraw = true;
501  } break;
502 
503  case MODE_DRAG:
504  case MODE_DRAG_INSERT:
505  case MODE_DRAG_INSERT_TEXT:
506  case MODE_DRAG_PASTE: {
507  m_camera->SetTranslation(event.GetPosition());
508  redraw = true;
509  } break;
510 
511  case MODE_EDIT: {
512  bool foundPickbox = false;
513  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
514  Element* element = *it;
515  if(element->IsSelected()) {
516  // Show element pickbox (when it has) if the mouse is over the selected object.
517  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
518  element->ShowPickbox();
519  redraw = true;
520 
521  // If the mouse is over a pickbox set correct mouse cursor.
522  if(element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
523  foundPickbox = true;
524  SetCursor(element->GetBestPickboxCursor());
525  } else if(!foundPickbox) {
526  SetCursor(wxCURSOR_ARROW);
527  element->ResetPickboxes();
528  }
529  } else if(!foundPickbox) {
530  if(element->IsPickboxShown()) redraw = true;
531 
532  element->ShowPickbox(false);
533  element->ResetPickboxes();
534  SetCursor(wxCURSOR_ARROW);
535  }
536  }
537  }
538  } break;
539 
540  case MODE_MOVE_NODE: {
541  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
542  Element* element = *it;
543  if(element->IsSelected()) {
544  element->MoveNode(NULL, m_camera->ScreenToWorld(event.GetPosition()));
545  redraw = true;
546  }
547  }
548  } break;
549 
550  case MODE_MOVE_PICKBOX: {
551  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
552  Element* element = *it;
553  if(element->IsSelected()) {
554  element->MovePickbox(m_camera->ScreenToWorld(event.GetPosition()));
555  redraw = true;
556  }
557  }
558  } break;
559 
560  case MODE_MOVE_ELEMENT:
561  case MODE_PASTE: {
562  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
563  Element* element = *it;
564  if(element->IsSelected()) {
565  element->Move(m_camera->ScreenToWorld(event.GetPosition()));
566  // Move child nodes
567  std::vector<Element*> childList = element->GetChildList();
568  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
569  (*it)->MoveNode(element, m_camera->ScreenToWorld(event.GetPosition()));
570  }
571  redraw = true;
572  }
573  }
574  // Text element motion
575  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; it++) {
576  Text* text = *it;
577  if(text->IsSelected()) {
578  text->Move(m_camera->ScreenToWorld(event.GetPosition()));
579  redraw = true;
580  }
581  }
582  } break;
583 
584  case MODE_SELECTION_RECT: {
585  wxPoint2DDouble currentPos = m_camera->ScreenToWorld(event.GetPosition());
586  double x, y, w, h;
587  if(currentPos.m_x < m_startSelRect.m_x) {
588  x = currentPos.m_x;
589  w = m_startSelRect.m_x - currentPos.m_x;
590  } else {
591  x = m_startSelRect.m_x;
592  w = currentPos.m_x - m_startSelRect.m_x;
593  }
594  if(currentPos.m_y < m_startSelRect.m_y) {
595  y = currentPos.m_y;
596  h = m_startSelRect.m_y - currentPos.m_y;
597  } else {
598  y = m_startSelRect.m_y;
599  h = currentPos.m_y - m_startSelRect.m_y;
600  }
601 
602  m_selectionRect = wxRect2DDouble(x, y, w, h);
603  redraw = true;
604  } break;
605  }
606 
607  if(redraw) Redraw();
608  m_camera->UpdateMousePosition(event.GetPosition());
609  UpdateStatusBar();
610  m_timer->Start(); // Restart the timer.
611  event.Skip();
612 }
613 
614 void Workspace::OnMiddleDown(wxMouseEvent& event)
615 {
616  // Set to drag mode.
617  switch(m_mode) {
618  case MODE_INSERT: {
619  m_mode = MODE_DRAG_INSERT;
620  } break;
621  case MODE_INSERT_TEXT: {
622  m_mode = MODE_DRAG_INSERT_TEXT;
623  } break;
624  case MODE_PASTE: {
625  m_mode = MODE_DRAG_PASTE;
626  } break;
627  default: {
628  m_mode = MODE_DRAG;
629  } break;
630  }
631  m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
632  UpdateStatusBar();
633  event.Skip();
634 }
635 
636 void Workspace::OnMiddleUp(wxMouseEvent& event)
637 {
638  switch(m_mode) {
639  case MODE_DRAG_INSERT: {
640  m_mode = MODE_INSERT;
641  } break;
642  case MODE_DRAG_INSERT_TEXT: {
643  m_mode = MODE_INSERT_TEXT;
644  } break;
645  case MODE_DRAG_PASTE: {
646  m_mode = MODE_PASTE;
647  } break;
648  case MODE_INSERT:
649  case MODE_INSERT_TEXT:
650  case MODE_PASTE: {
651  // Does nothing.
652  } break;
653  default: {
654  m_mode = MODE_EDIT;
655  } break;
656  }
657  UpdateStatusBar();
658  event.Skip();
659 }
660 
661 void Workspace::OnScroll(wxMouseEvent& event)
662 {
663  if(event.GetWheelRotation() > 0)
664  m_camera->SetScale(event.GetPosition(), +0.05);
665  else
666  m_camera->SetScale(event.GetPosition(), -0.05);
667 
668  UpdateStatusBar();
669  Redraw();
670 }
671 
672 void Workspace::OnKeyDown(wxKeyEvent& event)
673 {
674  bool insertingElement = false;
675  if(m_mode == MODE_INSERT || m_mode == MODE_INSERT_TEXT) insertingElement = true;
676 
677  char key = event.GetUnicodeKey();
678  if(key != WXK_NONE) {
679  switch(key) {
680  case WXK_ESCAPE: // Cancel operations.
681  {
682  if(m_mode == MODE_INSERT) {
683  m_elementList.pop_back(); // Removes the last element being inserted.
684  m_mode = MODE_EDIT;
685  Redraw();
686  } else if(m_mode == MODE_INSERT_TEXT) {
687  m_textList.pop_back();
688  m_mode = MODE_EDIT;
689  Redraw();
690  }
691  } break;
692  case WXK_DELETE: // Delete selected elements
693  {
694  DeleteSelectedElements();
695  } break;
696  case 'A': {
697  if(!insertingElement) {
698  Text* newBus = new Text(m_camera->ScreenToWorld(event.GetPosition()));
699  m_textList.push_back(newBus);
700  m_mode = MODE_INSERT_TEXT;
701  m_statusBar->SetStatusText(_("Insert Text: Click to insert, ESC to cancel."));
702  Redraw();
703  }
704  } break;
705  case 'F': {
706  if(event.GetModifiers() == wxMOD_SHIFT) {
707  Fit();
708  }
709  } break;
710  case 'R': // Rotate the selected elements.
711  {
712  RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
713  } break;
714  case 'B': // Insert a bus.
715  {
716  if(!insertingElement) {
717  Bus* newBus = new Bus(m_camera->ScreenToWorld(event.GetPosition()),
718  wxString::Format(_("Bus %d"), GetElementNumber(ID_BUS)));
719  IncrementElementNumber(ID_BUS);
720  m_elementList.push_back(newBus);
721  m_mode = MODE_INSERT;
722  m_statusBar->SetStatusText(_("Insert Bus: Click to insert, ESC to cancel."));
723  Redraw();
724  }
725  } break;
726  case 'L': {
727  if(!insertingElement) {
728  if(!event.ControlDown() && event.ShiftDown()) { // Insert a load.
729  Load* newLoad = new Load(wxString::Format(_("Load %d"), GetElementNumber(ID_LOAD)));
730  IncrementElementNumber(ID_LOAD);
731  m_elementList.push_back(newLoad);
732  m_mode = MODE_INSERT;
733  m_statusBar->SetStatusText(_("Insert Load: Click on a buses, ESC to cancel."));
734  } else if(!event.ControlDown() && !event.ShiftDown()) { // Insert a power line.
735  Line* newLine = new Line(wxString::Format(_("Line %d"), GetElementNumber(ID_LINE)));
736  IncrementElementNumber(ID_LINE);
737  m_elementList.push_back(newLine);
738  m_mode = MODE_INSERT;
739  m_statusBar->SetStatusText(_("Insert Line: Click on two buses, ESC to cancel."));
740  }
741  Redraw();
742  }
743  // Tests - Ctrl + Shift + L
744  if(event.ControlDown() && event.ShiftDown()) {
745  // Nothing...
746  }
747  } break;
748  case 'T': // Insert a transformer.
749  {
750  if(!insertingElement) {
751  Transformer* newTransformer =
752  new Transformer(wxString::Format(_("Transformer %d"), GetElementNumber(ID_TRANSFORMER)));
753  IncrementElementNumber(ID_TRANSFORMER);
754  m_elementList.push_back(newTransformer);
755  m_mode = MODE_INSERT;
756  m_statusBar->SetStatusText(_("Insert Transformer: Click on two buses, ESC to cancel."));
757  Redraw();
758  }
759  } break;
760  case 'G': // Insert a generator.
761  {
762  if(!insertingElement) {
763  SyncGenerator* newGenerator =
764  new SyncGenerator(wxString::Format(_("Generator %d"), GetElementNumber(ID_SYNCGENERATOR)));
765  IncrementElementNumber(ID_SYNCGENERATOR);
766  m_elementList.push_back(newGenerator);
767  m_mode = MODE_INSERT;
768  m_statusBar->SetStatusText(_("Insert Generator: Click on a buses, ESC to cancel."));
769  Redraw();
770  }
771  } break;
772  case 'I': {
773  if(!insertingElement) {
774  if(event.GetModifiers() == wxMOD_SHIFT) { // Insert an inductor.
775  Inductor* newInductor =
776  new Inductor(wxString::Format(_("Inductor %d"), GetElementNumber(ID_INDUCTOR)));
777  IncrementElementNumber(ID_INDUCTOR);
778  m_elementList.push_back(newInductor);
779  m_mode = MODE_INSERT;
780  m_statusBar->SetStatusText(_("Insert Inductor: Click on a buses, ESC to cancel."));
781  } else // Insert an induction motor.
782  {
783  IndMotor* newIndMotor =
784  new IndMotor(wxString::Format(_("Induction motor %d"), GetElementNumber(ID_INDMOTOR)));
785  IncrementElementNumber(ID_INDMOTOR);
786  m_elementList.push_back(newIndMotor);
787  m_mode = MODE_INSERT;
788  m_statusBar->SetStatusText(_("Insert Induction Motor: Click on a buses, ESC to cancel."));
789  }
790  Redraw();
791  }
792  } break;
793  case 'K': // Insert a synchronous condenser.
794  {
795  if(!insertingElement) {
796  SyncMotor* newSyncCondenser =
797  new SyncMotor(wxString::Format(_("Synchronous condenser %d"), GetElementNumber(ID_SYNCMOTOR)));
798  IncrementElementNumber(ID_SYNCMOTOR);
799  m_elementList.push_back(newSyncCondenser);
800  m_mode = MODE_INSERT;
801  m_statusBar->SetStatusText(_("Insert Synchronous Condenser: Click on a buses, ESC to cancel."));
802  Redraw();
803  }
804  } break;
805  case 'C': {
806  if(!insertingElement) {
807  if(event.GetModifiers() == wxMOD_SHIFT) { // Insert a capacitor.
808  Capacitor* newCapacitor =
809  new Capacitor(wxString::Format(_("Capacitor %d"), GetElementNumber(ID_CAPACITOR)));
810  IncrementElementNumber(ID_CAPACITOR);
811  m_elementList.push_back(newCapacitor);
812  m_mode = MODE_INSERT;
813  m_statusBar->SetStatusText(_("Insert Capacitor: Click on a buses, ESC to cancel."));
814  Redraw();
815  } else if(event.GetModifiers() == wxMOD_CONTROL) { // Copy.
816  CopySelection();
817  }
818  }
819  } break;
820  case 'V': {
821  if(!insertingElement) {
822  if(event.GetModifiers() == wxMOD_CONTROL) {
823  Paste();
824  }
825  }
826  } break;
827  default:
828  break;
829  }
830  }
831 
832  UpdateStatusBar();
833  event.Skip();
834 }
835 
836 void Workspace::UpdateStatusBar()
837 {
838  switch(m_mode) {
839  case MODE_DRAG: {
840  m_statusBar->SetStatusText(_("MODE: DRAG"), 1);
841  } break;
842 
843  case MODE_PASTE:
844  case MODE_DRAG_PASTE: {
845  m_statusBar->SetStatusText(_("MODE: PASTE"), 1);
846  }
847 
848  case MODE_INSERT:
849  case MODE_INSERT_TEXT:
850  case MODE_DRAG_INSERT:
851  case MODE_DRAG_INSERT_TEXT: {
852  m_statusBar->SetStatusText(_("MODE: INSERT"), 1);
853  } break;
854 
855  case MODE_MOVE_ELEMENT:
856  case MODE_MOVE_PICKBOX:
857  case MODE_MOVE_NODE:
858  case MODE_SELECTION_RECT:
859  case MODE_EDIT: {
860  m_statusBar->SetStatusText(wxT(""));
861  m_statusBar->SetStatusText(_("MODE: EDIT"), 1);
862  } break;
863  }
864 
865  m_statusBar->SetStatusText(wxString::Format(_("ZOOM: %d%%"), (int)(m_camera->GetScale() * 100.0)), 2);
866  m_statusBar->SetStatusText(
867  wxString::Format(wxT("X: %.1f Y: %.1f"), m_camera->GetMousePosition().m_x, m_camera->GetMousePosition().m_y),
868  3);
869 }
870 
871 void Workspace::OnPopupClick(wxCommandEvent& event)
872 {
873  wxMenu* menu = static_cast<wxMenu*>(event.GetEventObject());
874  Element* element = static_cast<Element*>(menu->GetClientData());
875  switch(event.GetId()) {
876  case ID_EDIT_ELEMENT: {
877  if(element->ShowForm(this, element)) UpdateTextElements();
878  } break;
879  case ID_LINE_ADD_NODE: {
880  Line* line = static_cast<Line*>(element);
881  line->AddNode(m_camera->GetMousePosition());
882  Redraw();
883  } break;
884  case ID_LINE_REMOVE_NODE: {
885  Line* line = static_cast<Line*>(element);
886  line->RemoveNode(m_camera->GetMousePosition());
887  Redraw();
888  } break;
889  case ID_ROTATE_CLOCK: {
890  element->Rotate();
891  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
892  Element* iElement = *it;
893  // Parent's element rotating...
894  for(int i = 0; i < (int)iElement->GetParentList().size(); i++) {
895  Element* parent = iElement->GetParentList()[i];
896  if(parent == element) {
897  iElement->RotateNode(parent);
898  }
899  }
900  }
901  Redraw();
902  } break;
903  case ID_ROTATE_COUNTERCLOCK: {
904  element->Rotate(false);
905  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
906  Element* iElement = *it;
907  // Parent's element rotating...
908  for(int i = 0; i < (int)iElement->GetParentList().size(); i++) {
909  Element* parent = iElement->GetParentList()[i];
910  if(parent == element) {
911  iElement->RotateNode(parent, false);
912  }
913  }
914  }
915  Redraw();
916  } break;
917  case ID_DELETE: {
918  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
919  Element* iElement = *it;
920 
921  if(element == iElement) {
922  // Remove child/parent.
923  std::vector<Element*> childList = element->GetChildList();
924  for(auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
925  Element* child = *itc;
926  if(child) {
927  child->RemoveParent(element);
928  element->RemoveChild(child);
929  }
930  }
931  std::vector<Element*> parentList = element->GetParentList();
932  for(auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
933  Element* parent = *itp;
934  if(parent) {
935  parent->RemoveChild(element);
936  }
937  }
938 
939  for(auto itt = m_textList.begin(); itt != m_textList.end(); ++itt) {
940  Text* text = *itt;
941  if(text->GetElement() == element) {
942  m_textList.erase(itt--);
943  if(text) delete text;
944  }
945  }
946 
947  m_elementList.erase(it);
948  if(element) delete element;
949  menu->SetClientData(NULL);
950  break;
951  }
952  }
953  } break;
954  }
955 }
956 
957 void Workspace::RotateSelectedElements(bool clockwise)
958 {
959  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
960  Element* element = *it;
961  // Parent's element rotating...
962  for(int i = 0; i < (int)element->GetParentList().size(); i++) {
963  Element* parent = element->GetParentList()[i];
964  if(parent) { // Check if parent is not null
965  if(parent->IsSelected()) {
966  element->RotateNode(parent, clockwise);
967  // Update the positions used on motion action, the element will not be necessarily
968  // moved.
969  element->StartMove(m_camera->GetMousePosition());
970  }
971  }
972  }
973  if(element->IsSelected()) {
974  element->Rotate(clockwise);
975  element->StartMove(m_camera->GetMousePosition());
976  }
977  }
978 
979  // Rotate text element
980  for(auto it = m_textList.begin(); it != m_textList.end(); it++) {
981  Text* text = *it;
982  if(text->IsSelected()) {
983  text->Rotate(clockwise);
984  text->StartMove(m_camera->GetMousePosition());
985  }
986  }
987  Redraw();
988 }
989 
990 void Workspace::DeleteSelectedElements()
991 {
992  // Don't set the end of the list at the loop's begin.
993  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
994  Element* element = *it;
995 
996  if(element->IsSelected()) {
997  // Remove child/parent.
998  std::vector<Element*> childList = element->GetChildList();
999  for(auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
1000  Element* child = *itc;
1001  if(child) {
1002  child->RemoveParent(element);
1003  element->RemoveChild(child);
1004  }
1005  }
1006  std::vector<Element*> parentList = element->GetParentList();
1007  for(auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
1008  Element* parent = *itp;
1009  if(parent) {
1010  parent->RemoveChild(element);
1011  }
1012  }
1013 
1014  for(auto itt = m_textList.begin(); itt != m_textList.end(); ++itt) {
1015  Text* text = *itt;
1016  if(text->GetElement() == element) {
1017  m_textList.erase(itt--);
1018  if(text) delete text;
1019  }
1020  }
1021 
1022  m_elementList.erase(it--);
1023  if(element) delete element;
1024  }
1025  }
1026 
1027  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
1028  Text* text = *it;
1029  if(text->IsSelected()) {
1030  m_textList.erase(it--);
1031  if(text) delete text;
1032  }
1033  }
1034 
1035  Redraw();
1036 }
1037 
1038 bool Workspace::GetElementsCorners(wxPoint2DDouble& leftUpCorner,
1039  wxPoint2DDouble& rightDownCorner,
1040  std::vector<Element*> elementList)
1041 {
1042  if(elementList.size() == 0) return false;
1043 
1044  elementList[0]->CalculateBoundaries(leftUpCorner, rightDownCorner);
1045 
1046  for(auto it = elementList.begin() + 1, itEnd = elementList.end(); it != itEnd; it++) {
1047  Element* element = *it;
1048  wxPoint2DDouble leftUp;
1049  wxPoint2DDouble rightDown;
1050  element->CalculateBoundaries(leftUp, rightDown);
1051  if(leftUp.m_x < leftUpCorner.m_x) leftUpCorner.m_x = leftUp.m_x;
1052  if(leftUp.m_y < leftUpCorner.m_y) leftUpCorner.m_y = leftUp.m_y;
1053  if(rightDown.m_x > rightDownCorner.m_x) rightDownCorner.m_x = rightDown.m_x;
1054  if(rightDown.m_y > rightDownCorner.m_y) rightDownCorner.m_y = rightDown.m_y;
1055  }
1056  return true;
1057 }
1058 
1059 void Workspace::Fit()
1060 {
1061  wxPoint2DDouble leftUpCorner(0, 0);
1062  wxPoint2DDouble rightDownCorner(0, 0);
1063  std::vector<Element*> elementList = GetElementList();
1064  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1065  elementList.push_back(*it);
1066  }
1067 
1068  if(!GetElementsCorners(leftUpCorner, rightDownCorner, elementList)) return;
1069  wxPoint2DDouble middleCoords = (leftUpCorner + rightDownCorner) / 2.0;
1070 
1071  int width = 0.0;
1072  int height = 0.0;
1073  GetSize(&width, &height);
1074 
1075  double scaleX = double(width) / (rightDownCorner.m_x - leftUpCorner.m_x);
1076  double scaleY = double(height) / (rightDownCorner.m_y - leftUpCorner.m_y);
1077 
1078  double scale = scaleX < scaleY ? scaleX : scaleY;
1079  if(scale > m_camera->GetZoomMax()) scale = m_camera->GetZoomMax();
1080  if(scale < m_camera->GetZoomMin()) scale = m_camera->GetZoomMin();
1081 
1082  m_camera->SetScale(scale);
1083 
1084  m_camera->StartTranslation(middleCoords);
1085  m_camera->SetTranslation(wxPoint2DDouble(width / 2, height / 2));
1086  Redraw();
1087 }
1088 
1089 void Workspace::ValidateBusesVoltages(Element* initialBus)
1090 {
1091  double nominalVoltage = static_cast<Bus*>(initialBus)->GetElectricalData().nominalVoltage;
1092  ElectricalUnit nominalVoltageUnit = static_cast<Bus*>(initialBus)->GetElectricalData().nominalVoltageUnit;
1093 
1094  for(auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1095  Element* child = *it;
1096 
1097  if(typeid(*child) == typeid(Line)) {
1098  if(child->GetParentList()[0] && child->GetParentList()[1]) {
1099  BusElectricalData data1 = static_cast<Bus*>(child->GetParentList()[0])->GetElectricalData();
1100  BusElectricalData data2 = static_cast<Bus*>(child->GetParentList()[1])->GetElectricalData();
1101 
1102  if(data1.nominalVoltage != data2.nominalVoltage ||
1103  data1.nominalVoltageUnit != data2.nominalVoltageUnit) {
1104  data1.nominalVoltage = nominalVoltage;
1105  data2.nominalVoltage = nominalVoltage;
1106  data1.nominalVoltageUnit = nominalVoltageUnit;
1107  data2.nominalVoltageUnit = nominalVoltageUnit;
1108 
1109  static_cast<Bus*>(child->GetParentList()[0])->SetElectricalData(data1);
1110  static_cast<Bus*>(child->GetParentList()[1])->SetElectricalData(data2);
1111 
1112  it = m_elementList.begin(); // Restart search.
1113  }
1114  }
1115  }
1116  }
1117 
1118  // ValidateElementsVoltages();
1119 }
1120 
1121 void Workspace::ValidateElementsVoltages()
1122 {
1123  for(auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1124  PowerElement* child = *it;
1125 
1126  std::vector<double> nominalVoltage;
1127  std::vector<ElectricalUnit> nominalVoltageUnit;
1128  for(int i = 0; i < (int)child->GetParentList().size(); i++) {
1129  Bus* parent = static_cast<Bus*>(child->GetParentList()[i]);
1130  if(parent) {
1131  nominalVoltage.push_back(parent->GetElectricalData().nominalVoltage);
1132  nominalVoltageUnit.push_back(parent->GetElectricalData().nominalVoltageUnit);
1133  }
1134  }
1135  child->SetNominalVoltage(nominalVoltage, nominalVoltageUnit);
1136  }
1137 }
1138 
1139 bool Workspace::RunPowerFlow()
1140 {
1141  PowerFlow pf(GetElementList());
1142  bool result = pf.RunGaussSeidel();
1143  if(!result) {
1144  wxMessageDialog msgDialog(this, pf.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1145  msgDialog.ShowModal();
1146  }
1147 
1148  UpdateTextElements();
1149  Redraw();
1150 
1151  return result;
1152 }
1153 
1154 void Workspace::UpdateTextElements()
1155 {
1156  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1157  Text* text = *it;
1158  text->UpdateText(m_properties->GetSimulationPropertiesData().basePower);
1159  }
1160 }
1161 
1162 void Workspace::CopySelection()
1163 {
1164  UpdateElementsID();
1165  std::vector<Element*> selectedElements;
1166  // The buses need to be numerated to associate the child's parents to the copies.
1167  int busNumber = 0;
1168  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1169  Element* element = *it;
1170  if(typeid(*element) == typeid(Bus)) {
1171  Bus* bus = static_cast<Bus*>(element);
1172  auto data = bus->GetElectricalData();
1173  data.number = busNumber;
1174  bus->SetElectricalData(data);
1175  busNumber++;
1176  }
1177  if(element->IsSelected()) {
1178  selectedElements.push_back(element);
1179  }
1180  }
1181  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1182  Text* text = *it;
1183  if(text->IsSelected()) {
1184  selectedElements.push_back(text);
1185  }
1186  }
1187  ElementDataObject* dataObject = new ElementDataObject(selectedElements);
1188  wxTheClipboard->SetData(dataObject);
1189  wxTheClipboard->Close();
1190 }
1191 
1192 bool Workspace::Paste()
1193 {
1194  if(wxTheClipboard->Open()) {
1195  ElementDataObject dataObject;
1196 
1197  if(wxTheClipboard->IsSupported(wxDataFormat("PSPCopy"))) {
1198  if(!wxTheClipboard->GetData(dataObject)) {
1199  wxMessageDialog dialog(this, _("It was not possible to paste from clipboard."), _("Error"),
1200  wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1201  dialog.ShowModal();
1202  wxTheClipboard->Close();
1203  return false;
1204  }
1205  } else {
1206  wxTheClipboard->Close();
1207  return false;
1208  }
1209  wxTheClipboard->Close();
1210 
1211  UnselectAll();
1212 
1213  std::vector<Element*> pastedElements;
1214  ElementsLists* elementsLists = dataObject.GetElementsLists();
1215 
1216  // Paste buses (parents).
1217  auto parentList = elementsLists->parentList;
1218  std::vector<Bus*> pastedBusList; // To set new parents;
1219  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
1220  Element* copy = (*it)->GetCopy();
1221  if(copy) {
1222  pastedElements.push_back(copy);
1223  pastedBusList.push_back(static_cast<Bus*>(copy));
1224  m_elementList.push_back(static_cast<PowerElement*>(copy));
1225  }
1226  }
1227 
1228  // Paste other elements.
1229  auto elementLists = elementsLists->elementList;
1230  for(auto it = elementLists.begin(), itEnd = elementLists.end(); it != itEnd; ++it) {
1231  Element* copy = (*it)->GetCopy();
1232  if(copy) {
1233  // Check if is text element
1234  if(Text* text = dynamic_cast<Text*>(copy)) {
1235  // Check if element associated with the text exists.
1236  bool elementExist = false;
1237  for(int i = 0; i < (int)m_elementList.size(); i++) {
1238  if(text->GetElement() == m_elementList[i]) {
1239  elementExist = true;
1240  break;
1241  }
1242  }
1243  if(elementExist) {
1244  pastedElements.push_back(copy);
1245  m_textList.push_back(text);
1246  }
1247  } else {
1248  // Change the parent if copied, otherwise remove it.
1249  for(int j = 0; j < (int)copy->GetParentList().size(); j++) {
1250  Bus* currentParent = static_cast<Bus*>(copy->GetParentList()[j]);
1251  if(currentParent) {
1252  int parentID = currentParent->GetID();
1253  bool parentCopied = false;
1254  for(int k = 0; k < (int)pastedBusList.size(); k++) {
1255  Bus* newParent = pastedBusList[k];
1256  if(parentID == newParent->GetID()) {
1257  parentCopied = true;
1258  copy->ReplaceParent(currentParent, newParent);
1259  break;
1260  }
1261  }
1262  if(!parentCopied) copy->RemoveParent(currentParent);
1263  }
1264  }
1265 
1266  pastedElements.push_back(copy);
1267  m_elementList.push_back(static_cast<PowerElement*>(copy));
1268  }
1269  }
1270  }
1271 
1272  // Update buses childs
1273  for(auto it = pastedBusList.begin(), itEnd = pastedBusList.end(); it != itEnd; ++it) {
1274  Bus* bus = *it;
1275  std::vector<Element*> childList = bus->GetChildList();
1276  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
1277  Element* currentChild = *it;
1278  int childID = currentChild->GetID();
1279  bool childCopied = false;
1280  for(int i = 0; i < (int)pastedElements.size(); i++) {
1281  Element* newChild = pastedElements[i];
1282  if(childID == newChild->GetID()) {
1283  childCopied = true;
1284  bus->ReplaceChild(currentChild, newChild);
1285  break;
1286  }
1287  }
1288  if(!childCopied) bus->RemoveChild(currentChild);
1289  }
1290  }
1291 
1292  // Move elements (and nodes) to the mouse position.
1293  // The start position it's the center of the pasted objects.
1294  wxPoint2DDouble leftUpCorner, rightDownCorner;
1295  GetElementsCorners(leftUpCorner, rightDownCorner, pastedElements);
1296  wxPoint2DDouble startPosition = (leftUpCorner + rightDownCorner) / 2.0;
1297  for(auto it = pastedElements.begin(), itEnd = pastedElements.end(); it != itEnd; ++it) {
1298  Element* element = *it;
1299  element->StartMove(startPosition);
1300  element->Move(m_camera->GetMousePosition());
1301  for(int i = 0; i < (int)element->GetParentList().size(); i++) {
1302  Element* parent = element->GetParentList()[i];
1303  element->MoveNode(parent, m_camera->GetMousePosition());
1304  }
1305  }
1306  } else {
1307  wxMessageDialog dialog(this, _("It was not possible to paste from clipboard."), _("Error"),
1308  wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1309  dialog.ShowModal();
1310  return false;
1311  }
1312 
1313  UpdateElementsID();
1314  m_mode = MODE_PASTE;
1315  m_statusBar->SetStatusText(_("Click to paste."));
1316  UpdateStatusBar();
1317  Redraw();
1318  return true;
1319 }
1320 
1321 void Workspace::UnselectAll()
1322 {
1323  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
1324  Element* element = *it;
1325  element->SetSelected(false);
1326  }
1327  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; it++) {
1328  Text* text = *it;
1329  text->SetSelected(false);
1330  }
1331 }
1332 
1333 void Workspace::UpdateElementsID()
1334 {
1335  int id = 0;
1336  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1337  Element* element = *it;
1338  element->SetID(id);
1339  id++;
1340  }
1341  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1342  Text* text = *it;
1343  text->SetID(id);
1344  id++;
1345  }
1346 }
1347 void Workspace::OnTimer(wxTimerEvent& event)
1348 {
1349  if(m_tipWindow) {
1350  m_tipWindow->Close();
1351  m_tipWindow = NULL;
1352  }
1353  if(m_mode == MODE_EDIT) {
1354  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1355  Element* element = *it;
1356  if(element->Contains(m_camera->GetMousePosition())) {
1357  wxString tipText = element->GetTipText();
1358  if(!tipText.IsEmpty()) {
1359  m_tipWindow = new wxTipWindow(this, tipText, 10000, &m_tipWindow);
1360  // Creates a very tiny bounding rect to remove the tip on any mouse movement.
1361  m_tipWindow->SetBoundingRect(wxRect(wxGetMousePosition(), wxSize(1, 1)));
1362  break;
1363  }
1364  }
1365  }
1366  }
1367 
1368  m_timer->Stop();
1369 }
1370 
1371 void Workspace::SetTextList(std::vector<Text*> textList)
1372 {
1373  m_textList.clear();
1374  for(auto it = textList.begin(), itEnd = textList.end(); it != itEnd; ++it) m_textList.push_back(*it);
1375 
1376  UpdateTextElements();
1377 }
1378 
1379 void Workspace::SetElementList(std::vector<Element*> elementList)
1380 {
1381  m_elementList.clear();
1382  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it)
1383  m_elementList.push_back(static_cast<PowerElement*>(*it));
1384 }
1385 
1386 void Workspace::OnIdle(wxIdleEvent& event)
1387 {
1388  // TODO: Find other solution to text displayed wrong on opened file.
1389  if(m_justOpened) {
1390  m_justOpened = false;
1391  UpdateTextElements();
1392  Redraw();
1393  }
1394 }
1395 
1396 std::vector<Element*> Workspace::GetAllElements() const
1397 {
1398  std::vector<Element*> allElements;
1399 
1400  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) allElements.push_back(*it);
1401  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) allElements.push_back(*it);
1402 
1403  return allElements;
1404 }
1405 
1406 bool Workspace::RunFault()
1407 {
1408  Fault fault(GetElementList());
1409  bool result = fault.RunFaultCalculation(100e6);
1410  if(!result) {
1411  wxMessageDialog msgDialog(this, fault.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1412  msgDialog.ShowModal();
1413  }
1414 
1415  UpdateTextElements();
1416  Redraw();
1417 
1418  return result;
1419 }
1420 
1421 std::vector<Element*> Workspace::GetElementList() const
1422 {
1423  std::vector<Element*> elementList;
1424  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) elementList.push_back(*it);
1425  return elementList;
1426 }
1427 
1428 bool Workspace::RunSCPower()
1429 {
1430  Fault fault(GetElementList());
1431  bool result = fault.RunSCPowerCalcutation(100e6);
1432  if(!result) {
1433  wxMessageDialog msgDialog(this, fault.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1434  msgDialog.ShowModal();
1435  }
1436 
1437  UpdateTextElements();
1438  Redraw();
1439 
1440  return result;
1441 }
1442 
1443 bool Workspace::RunStability()
1444 {
1445  // Run power flow before stability.
1446  RunPowerFlow();
1447 
1448  Electromechanical stability(this, GetElementList(), m_properties->GetSimulationPropertiesData());
1449  bool result = stability.RunStabilityCalculation();
1450  if(!result) {
1451  wxMessageDialog msgDialog(this, stability.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1452  msgDialog.ShowModal();
1453  }
1454  m_stabilityTimeVector.clear();
1455  m_stabilityTimeVector = stability.GetTimeVector();
1456 
1457  // Run power flow after stability.
1458  RunPowerFlow();
1459 
1460  wxMessageDialog msgDialog(this, _("Do you wish to open the stability graphics?"), _("Question"),
1461  wxYES_NO | wxCENTRE | wxICON_QUESTION);
1462  if(msgDialog.ShowModal() == wxID_YES) {
1463  std::vector<ElementPlotData> plotDataList;
1464  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1465  PowerElement* element = *it;
1466  ElementPlotData plotData;
1467  if(element->GetPlotData(plotData)) plotDataList.push_back(plotData);
1468  }
1469  ElementPlotData tests(_("Error"), ElementPlotData::CT_TEST);
1470  tests.AddData(stability.m_wErrorVector, _("Speed error"));
1471  tests.AddData(stability.m_sdCVector, _("Sd"));
1472  tests.AddData(stability.m_sqCVector, _("Sq"));
1473  tests.AddData(stability.m_numItVector, _("Number iterations"));
1474  plotDataList.push_back(tests);
1475 
1476  ChartView* cView = new ChartView(this, plotDataList, m_stabilityTimeVector);
1477  cView->Show();
1478  }
1479 
1480  return result;
1481 }
1482 void Workspace::OnMiddleDoubleClick(wxMouseEvent& event)
1483 {
1484  Fit();
1485  event.Skip();
1486 }
1487 
1488 bool Workspace::RunStaticStudies()
1489 {
1490  bool pfStatus, faultStatus, scStatus;
1491  pfStatus = faultStatus = scStatus = false;
1492 
1493  pfStatus = RunPowerFlow();
1494 
1495  if(m_properties->GetSimulationPropertiesData().faultAfterPowerFlow) {
1496  if(pfStatus) faultStatus = RunFault();
1497  } else {
1498  faultStatus = true;
1499  }
1500 
1501  if(m_properties->GetSimulationPropertiesData().scPowerAfterPowerFlow) {
1502  if(pfStatus) scStatus = RunSCPower();
1503  } else {
1504  scStatus = true;
1505  }
1506 
1507  if(pfStatus && faultStatus && scStatus) return true;
1508 
1509  return false;
1510 }
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
-
Definition: Text.h:65
+
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "Workspace.h"
19 #include "Camera.h"
20 #include "Element.h"
21 //#include "Bus.h"
22 #include "Line.h"
23 #include "Transformer.h"
24 #include "SyncGenerator.h"
25 #include "IndMotor.h"
26 #include "SyncMotor.h"
27 #include "Load.h"
28 #include "Inductor.h"
29 #include "Capacitor.h"
30 #include "ElementDataObject.h"
31 
32 #include "Text.h"
33 
34 #include "PowerFlow.h"
35 #include "Fault.h"
36 #include "Electromechanical.h"
37 
38 #include "ElementPlotData.h"
39 #include "ChartView.h"
40 
41 #include "PropertiesData.h"
42 
43 // Workspace
44 Workspace::Workspace() : WorkspaceBase(NULL) {}
45 Workspace::Workspace(wxWindow* parent, wxString name, wxStatusBar* statusBar) : WorkspaceBase(parent)
46 {
47  m_timer->Start();
48  m_name = name;
49  m_statusBar = statusBar;
50  m_glContext = new wxGLContext(m_glCanvas);
51  m_camera = new Camera();
52  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
53 
54  for(int i = 0; i < NUM_ELEMENTS; ++i) {
55  m_elementNumber[i] = 1;
56  }
57 
58  const int widths[4] = {-3, -1, 100, 100};
59  m_statusBar->SetStatusWidths(4, widths);
60 
61  m_properties = new PropertiesData();
62 }
63 
64 Workspace::~Workspace()
65 {
66  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
67  if(*it) delete *it;
68  }
69  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
70  if(*it) delete *it;
71  }
72  if(m_camera) delete m_camera;
73  if(m_glContext) delete m_glContext;
74  if(m_tipWindow) delete m_tipWindow;
75  if(m_properties) delete m_properties;
76 }
77 
78 void Workspace::OnPaint(wxPaintEvent& event)
79 {
80  wxPaintDC dc(m_glCanvas);
81  m_glContext->SetCurrent(*m_glCanvas);
82  SetViewport();
83 
84  // Set GLCanvas scale and translation.
85  glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale
86  glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation
87 
88  // Draw
89 
90  // Elements
91  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
92  Element* element = *it;
93  element->Draw(m_camera->GetTranslation(), m_camera->GetScale());
94  }
95 
96  // Texts
97  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
98  Text* text = *it;
99  text->Draw(m_camera->GetTranslation(), m_camera->GetScale());
100  }
101 
102  // Selection rectangle
103  glLineWidth(1.0);
104  glColor4d(0.0, 0.5, 1.0, 1.0);
105  glBegin(GL_LINE_LOOP);
106  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
107  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
108  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
109  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
110  glEnd();
111  glColor4d(0.0, 0.5, 1.0, 0.3);
112  glBegin(GL_QUADS);
113  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
114  glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
115  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
116  glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
117  glEnd();
118 
119  glFlush(); // Sends all pending information directly to the GPU.
120  m_glCanvas->SwapBuffers();
121  event.Skip();
122 }
123 
124 void Workspace::SetViewport()
125 {
126  glClearColor(1.0, 1.0, 1.0, 1.0); // White background.
127  glClear(GL_COLOR_BUFFER_BIT);
128  glDisable(GL_DEPTH_TEST);
129  glDisable(GL_TEXTURE_2D);
130  glEnable(GL_COLOR_MATERIAL);
131  glEnable(GL_BLEND);
132  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
133  glEnable(GL_LINE_SMOOTH);
134 
135  double width = m_glCanvas->GetSize().x - 1;
136  double height = m_glCanvas->GetSize().y - 1;
137 
138  // Viewport fit the screen.
139  glViewport(0, 0, width, height);
140 
141  glMatrixMode(GL_PROJECTION);
142  glLoadIdentity();
143  gluOrtho2D(0.0, width, height, 0.0);
144 
145  glMatrixMode(GL_MODELVIEW);
146  glLoadIdentity();
147 }
148 
149 void Workspace::OnLeftClickDown(wxMouseEvent& event)
150 {
151  wxPoint clickPoint = event.GetPosition();
152  bool foundElement = false;
153  Element* newElement = NULL;
154  bool showNewElementForm = false;
155  bool clickOnSwitch = false;
156  if(m_mode == MODE_INSERT_TEXT || m_mode == MODE_PASTE || m_mode == MODE_DRAG_PASTE) {
157  m_mode = MODE_EDIT;
158  } else if(m_mode == MODE_INSERT || m_mode == MODE_DRAG_INSERT || m_mode == MODE_DRAG_INSERT_TEXT) {
159  // Get the last element inserted on the list.
160  newElement = *(m_elementList.end() - 1);
161  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
162  Element* element = *it;
163  // Clicked in any element.
164  if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
165  // Click at a bus.
166  if(typeid(*element) == typeid(Bus)) {
167  // Select the bus.
168  element->SetSelected();
169  foundElement = true; // Element found.
170  // Add the new element's parent. If the element being inserted returns true, back to
171  // edit mode.
172  if(newElement->AddParent(element, m_camera->ScreenToWorld(clickPoint))) {
173  ValidateElementsVoltages();
174  m_timer->Stop();
175  showNewElementForm = true;
176  m_mode = MODE_EDIT;
177  }
178  }
179  }
180  }
181  // The line element can have an indefined number of points.
182  if(!foundElement) {
183  if(typeid(*newElement) == typeid(Line)) {
184  newElement->AddPoint(m_camera->ScreenToWorld(clickPoint));
185  }
186  }
187  foundElement = true;
188  } else {
189  bool clickPickbox = false;
190  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
191  PowerElement* element = *it;
192  element->ResetPickboxes(); // Reset pickbox state.
193 
194  // Set movement initial position (not necessarily will be moved).
195  element->StartMove(m_camera->ScreenToWorld(clickPoint));
196 
197  // Click in selected element node.
198  if(element->NodeContains(m_camera->ScreenToWorld(clickPoint)) != 0 && element->IsSelected()) {
199  m_mode = MODE_MOVE_NODE;
200  m_disconnectedElement = true;
201  foundElement = true;
202  }
203 
204  // Click in an element.
205  else if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
206  if(!foundElement) {
207  // Select and show pickbox.
208  element->SetSelected();
209  element->ShowPickbox();
210  foundElement = true;
211  }
212  // If pickbox contains the click, move the pickbox
213  if(element->PickboxContains(m_camera->ScreenToWorld(clickPoint))) {
214  m_mode = MODE_MOVE_PICKBOX;
215  clickPickbox = true;
216  }
217  // If didn't found a pickbox, move the element
218  if(!clickPickbox) {
219  m_mode = MODE_MOVE_ELEMENT;
220  }
221  }
222 
223  // Click in a switch.
224  else if(element->SwitchesContains(m_camera->ScreenToWorld(clickPoint))) {
225  element->SetOnline(element->IsOnline() ? false : true);
226  clickOnSwitch = true;
227  }
228  }
229 
230  // Text element
231  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
232  Text* text = *it;
233 
234  text->StartMove(m_camera->ScreenToWorld(clickPoint));
235 
236  if(text->Contains(m_camera->ScreenToWorld(clickPoint))) {
237  if(!foundElement) {
238  text->SetSelected();
239  m_mode = MODE_MOVE_ELEMENT;
240  foundElement = true;
241  }
242  }
243  }
244  }
245 
246  if(!foundElement) {
247  m_mode = MODE_SELECTION_RECT;
248  m_startSelRect = m_camera->ScreenToWorld(clickPoint);
249  }
250 
251  Redraw();
252  UpdateStatusBar();
253 
254  if(showNewElementForm) {
255  if(newElement) {
256  newElement->ShowForm(this, newElement);
257  if(m_continuousCalc) RunStaticStudies();
258  }
259  }
260  if(clickOnSwitch && m_continuousCalc) RunStaticStudies();
261 
262  event.Skip();
263 }
264 
265 void Workspace::OnLeftDoubleClick(wxMouseEvent& event)
266 {
267  bool elementEdited = false;
268  bool clickOnSwitch = false;
269  bool redraw = false;
270 
271  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
272  PowerElement* element = *it;
273 
274  // Click in an element.
275  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
276  bool elementIsBus = false;
277  Bus oldBus;
278  Bus* currentBus = NULL;
279  if((currentBus = dynamic_cast<Bus*>(element))) {
280  elementIsBus = true;
281  oldBus = *currentBus;
282  }
283  m_timer->Stop();
284  element->ShowForm(this, element);
285  elementEdited = true;
286  redraw = true;
287 
288  // If the edited element is a bus and was changed the rated voltage, this voltage must be
289  // propagated through the lines
290  if(elementIsBus) {
291  // The voltage was changed
292  if(oldBus.GetElectricalData().nominalVoltage != currentBus->GetElectricalData().nominalVoltage ||
293  oldBus.GetElectricalData().nominalVoltageUnit !=
294  currentBus->GetElectricalData().nominalVoltageUnit) {
295  // Check if the bus has line as child.
296  std::vector<Element*> childList = element->GetChildList();
297  for(auto itc = childList.begin(), itcEnd = childList.end(); itc != itcEnd; ++itc) {
298  Element* child = *itc;
299  if(typeid(*child) == typeid(Line)) {
300  wxMessageDialog msgDialog(this, _("Do you want to change the rated voltage of the path?"),
301  _("Warning"), wxYES_NO | wxCENTRE | wxICON_WARNING);
302  if(msgDialog.ShowModal() == wxID_YES)
303  ValidateBusesVoltages(element);
304  else {
305  auto data = currentBus->GetElectricalData();
306  data.nominalVoltage = oldBus.GetElectricalData().nominalVoltage;
307  data.nominalVoltageUnit = oldBus.GetElectricalData().nominalVoltageUnit;
308  currentBus->SetElectricalData(data);
309  }
310  break;
311  }
312  }
313  }
314  ValidateElementsVoltages();
315  }
316  }
317 
318  // Click in a switch.
319  else if(element->SwitchesContains(m_camera->ScreenToWorld(event.GetPosition()))) {
320  element->SetOnline(element->IsOnline() ? false : true);
321  clickOnSwitch = true;
322  }
323  }
324 
325  // Text element
326  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
327  Text* text = *it;
328  if(text->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
329  text->ShowForm(this, GetElementList());
330  redraw = true;
331  }
332  }
333  if(elementEdited) {
334  UpdateTextElements();
335  if(m_continuousCalc) RunStaticStudies();
336  }
337  if(clickOnSwitch && m_continuousCalc) RunStaticStudies();
338 
339  if(redraw) Redraw();
340  m_timer->Start();
341 }
342 
343 void Workspace::OnRightClickDown(wxMouseEvent& event)
344 {
345  bool redraw = false;
346  if(m_mode == MODE_EDIT) {
347  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
348  Element* element = *it;
349  if(element->IsSelected()) {
350  // Show context menu.
351  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
352  element->ShowPickbox(false);
353  wxMenu menu;
354  if(element->GetContextMenu(menu)) {
355  m_timer->Stop();
356  menu.SetClientData(element);
357  menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &Workspace::OnPopupClick, this);
358  PopupMenu(&menu);
359  redraw = true;
360 
361  if(!menu.GetClientData()) break;
362  }
363  element->ResetPickboxes();
364  }
365  }
366  }
367  }
368  if(redraw) Redraw();
369  m_timer->Start();
370 }
371 
372 void Workspace::OnLeftClickUp(wxMouseEvent& event)
373 {
374  // This event (under certain conditions) deselects the elements and back to edit mode or select the elements using
375  // the selection rectangle.
376  bool foundPickbox = false;
377  bool findNewParent = false;
378  bool updateVoltages = false;
379  auto itnp = m_elementList.begin();
380 
381  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
382  Element* element = *it;
383 
384  // The user was moving a pickbox.
385  if(m_mode == MODE_MOVE_PICKBOX) {
386  // Catch only the element that have the pickbox shown.
387  if(element->IsPickboxShown()) {
388  // If the element is a bus, check if a node is outside.
389  if(typeid(*element) == typeid(Bus)) {
390  // Get all the bus children.
391  for(int i = 0; i < (int)m_elementList.size(); i++) {
392  Element* child = m_elementList[i];
393  for(int j = 0; j < (int)child->GetParentList().size(); j++) {
394  Element* parent = child->GetParentList()[j];
395  // The child have a parent that is the element.
396  if(parent == element) {
397  child->UpdateNodes();
398  m_disconnectedElement = true;
399  }
400  }
401  }
402  }
403  }
404  }
405 
406  if(m_mode == MODE_SELECTION_RECT) {
407  if(element->Intersects(m_selectionRect)) {
408  element->SetSelected();
409  } else if(!event.ControlDown()) {
410  element->SetSelected(false);
411  }
412  } else if(m_mode == MODE_MOVE_NODE) {
413  if(element->IsSelected()) {
414  for(int i = 0; i < (int)m_elementList.size(); i++) {
415  Element* parent = m_elementList[i];
416  if(typeid(*parent) == typeid(Bus)) {
417  if(element->SetNodeParent(parent)) {
418  parent->AddChild(element);
419  findNewParent = true;
420  itnp = it;
421  element->ResetNodes();
422  break;
423  }
424  }
425  }
426  // element->ResetNodes();
427  }
428  } else {
429  // Deselect
430  if(!event.ControlDown()) {
431  if(!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
432  element->SetSelected(false);
433  }
434  }
435 
436  if(element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
437  foundPickbox = true;
438  } else {
439  element->ShowPickbox(false);
440  element->ResetPickboxes();
441  }
442  }
443  }
444 
445  // Text element
446  for(auto it = m_textList.begin(); it != m_textList.end(); it++) {
447  Text* text = *it;
448  if(m_mode == MODE_SELECTION_RECT) {
449  if(text->Intersects(m_selectionRect)) {
450  text->SetSelected();
451  } else if(!event.ControlDown()) {
452  text->SetSelected(false);
453  }
454  } else if(!event.ControlDown()) {
455  if(!text->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
456  text->SetSelected(false);
457  }
458  }
459  }
460 
461  if(findNewParent) {
462  std::rotate(itnp, itnp + 1, m_elementList.end());
463  updateVoltages = true;
464  }
465  if(!foundPickbox) {
466  SetCursor(wxCURSOR_ARROW);
467  }
468 
469  if(m_mode != MODE_INSERT) {
470  m_mode = MODE_EDIT;
471  }
472 
473  if(updateVoltages) {
474  ValidateElementsVoltages();
475  }
476 
477  if(m_continuousCalc && m_disconnectedElement) {
478  m_disconnectedElement = false;
479  RunStaticStudies();
480  }
481 
482  m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
483  Redraw();
484  UpdateStatusBar();
485 }
486 
487 void Workspace::OnMouseMotion(wxMouseEvent& event)
488 {
489  bool redraw = false;
490  switch(m_mode) {
491  case MODE_INSERT: {
492  Element* newElement = *(m_elementList.end() - 1); // Get the last element in the list.
493  newElement->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
494  redraw = true;
495  } break;
496 
497  case MODE_INSERT_TEXT: {
498  Text* newText = *(m_textList.end() - 1);
499  newText->SetPosition(m_camera->ScreenToWorld(event.GetPosition()));
500  redraw = true;
501  } break;
502 
503  case MODE_DRAG:
504  case MODE_DRAG_INSERT:
505  case MODE_DRAG_INSERT_TEXT:
506  case MODE_DRAG_PASTE: {
507  m_camera->SetTranslation(event.GetPosition());
508  redraw = true;
509  } break;
510 
511  case MODE_EDIT: {
512  bool foundPickbox = false;
513  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
514  Element* element = *it;
515  if(element->IsSelected()) {
516  // Show element pickbox (when it has) if the mouse is over the selected object.
517  if(element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
518  element->ShowPickbox();
519  redraw = true;
520 
521  // If the mouse is over a pickbox set correct mouse cursor.
522  if(element->PickboxContains(m_camera->ScreenToWorld(event.GetPosition()))) {
523  foundPickbox = true;
524  SetCursor(element->GetBestPickboxCursor());
525  } else if(!foundPickbox) {
526  SetCursor(wxCURSOR_ARROW);
527  element->ResetPickboxes();
528  }
529  } else if(!foundPickbox) {
530  if(element->IsPickboxShown()) redraw = true;
531 
532  element->ShowPickbox(false);
533  element->ResetPickboxes();
534  SetCursor(wxCURSOR_ARROW);
535  }
536  }
537  }
538  } break;
539 
540  case MODE_MOVE_NODE: {
541  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
542  Element* element = *it;
543  if(element->IsSelected()) {
544  element->MoveNode(NULL, m_camera->ScreenToWorld(event.GetPosition()));
545  redraw = true;
546  }
547  }
548  } break;
549 
550  case MODE_MOVE_PICKBOX: {
551  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
552  Element* element = *it;
553  if(element->IsSelected()) {
554  element->MovePickbox(m_camera->ScreenToWorld(event.GetPosition()));
555  redraw = true;
556  }
557  }
558  } break;
559 
560  case MODE_MOVE_ELEMENT:
561  case MODE_PASTE: {
562  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
563  Element* element = *it;
564  if(element->IsSelected()) {
565  element->Move(m_camera->ScreenToWorld(event.GetPosition()));
566  // Move child nodes
567  std::vector<Element*> childList = element->GetChildList();
568  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
569  (*it)->MoveNode(element, m_camera->ScreenToWorld(event.GetPosition()));
570  }
571  redraw = true;
572  }
573  }
574  // Text element motion
575  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; it++) {
576  Text* text = *it;
577  if(text->IsSelected()) {
578  text->Move(m_camera->ScreenToWorld(event.GetPosition()));
579  redraw = true;
580  }
581  }
582  } break;
583 
584  case MODE_SELECTION_RECT: {
585  wxPoint2DDouble currentPos = m_camera->ScreenToWorld(event.GetPosition());
586  double x, y, w, h;
587  if(currentPos.m_x < m_startSelRect.m_x) {
588  x = currentPos.m_x;
589  w = m_startSelRect.m_x - currentPos.m_x;
590  } else {
591  x = m_startSelRect.m_x;
592  w = currentPos.m_x - m_startSelRect.m_x;
593  }
594  if(currentPos.m_y < m_startSelRect.m_y) {
595  y = currentPos.m_y;
596  h = m_startSelRect.m_y - currentPos.m_y;
597  } else {
598  y = m_startSelRect.m_y;
599  h = currentPos.m_y - m_startSelRect.m_y;
600  }
601 
602  m_selectionRect = wxRect2DDouble(x, y, w, h);
603  redraw = true;
604  } break;
605  }
606 
607  if(redraw) Redraw();
608  m_camera->UpdateMousePosition(event.GetPosition());
609  UpdateStatusBar();
610  m_timer->Start(); // Restart the timer.
611  event.Skip();
612 }
613 
614 void Workspace::OnMiddleDown(wxMouseEvent& event)
615 {
616  // Set to drag mode.
617  switch(m_mode) {
618  case MODE_INSERT: {
619  m_mode = MODE_DRAG_INSERT;
620  } break;
621  case MODE_INSERT_TEXT: {
622  m_mode = MODE_DRAG_INSERT_TEXT;
623  } break;
624  case MODE_PASTE: {
625  m_mode = MODE_DRAG_PASTE;
626  } break;
627  default: {
628  m_mode = MODE_DRAG;
629  } break;
630  }
631  m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
632  UpdateStatusBar();
633  event.Skip();
634 }
635 
636 void Workspace::OnMiddleUp(wxMouseEvent& event)
637 {
638  switch(m_mode) {
639  case MODE_DRAG_INSERT: {
640  m_mode = MODE_INSERT;
641  } break;
642  case MODE_DRAG_INSERT_TEXT: {
643  m_mode = MODE_INSERT_TEXT;
644  } break;
645  case MODE_DRAG_PASTE: {
646  m_mode = MODE_PASTE;
647  } break;
648  case MODE_INSERT:
649  case MODE_INSERT_TEXT:
650  case MODE_PASTE: {
651  // Does nothing.
652  } break;
653  default: {
654  m_mode = MODE_EDIT;
655  } break;
656  }
657  UpdateStatusBar();
658  event.Skip();
659 }
660 
661 void Workspace::OnScroll(wxMouseEvent& event)
662 {
663  if(event.GetWheelRotation() > 0)
664  m_camera->SetScale(event.GetPosition(), +0.05);
665  else
666  m_camera->SetScale(event.GetPosition(), -0.05);
667 
668  UpdateStatusBar();
669  Redraw();
670 }
671 
672 void Workspace::OnKeyDown(wxKeyEvent& event)
673 {
674  bool insertingElement = false;
675  if(m_mode == MODE_INSERT || m_mode == MODE_INSERT_TEXT) insertingElement = true;
676 
677  char key = event.GetUnicodeKey();
678  if(key != WXK_NONE) {
679  switch(key) {
680  case WXK_ESCAPE: // Cancel operations.
681  {
682  if(m_mode == MODE_INSERT) {
683  m_elementList.pop_back(); // Removes the last element being inserted.
684  m_mode = MODE_EDIT;
685  Redraw();
686  } else if(m_mode == MODE_INSERT_TEXT) {
687  m_textList.pop_back();
688  m_mode = MODE_EDIT;
689  Redraw();
690  }
691  } break;
692  case WXK_DELETE: // Delete selected elements
693  {
694  DeleteSelectedElements();
695  } break;
696  case 'A': {
697  if(!insertingElement) {
698  Text* newBus = new Text(m_camera->ScreenToWorld(event.GetPosition()));
699  m_textList.push_back(newBus);
700  m_mode = MODE_INSERT_TEXT;
701  m_statusBar->SetStatusText(_("Insert Text: Click to insert, ESC to cancel."));
702  Redraw();
703  }
704  } break;
705  case 'F': {
706  if(event.GetModifiers() == wxMOD_SHIFT) {
707  Fit();
708  }
709  } break;
710  case 'R': // Rotate the selected elements.
711  {
712  RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
713  } break;
714  case 'B': // Insert a bus.
715  {
716  if(!insertingElement) {
717  Bus* newBus = new Bus(m_camera->ScreenToWorld(event.GetPosition()),
718  wxString::Format(_("Bus %d"), GetElementNumber(ID_BUS)));
719  IncrementElementNumber(ID_BUS);
720  m_elementList.push_back(newBus);
721  m_mode = MODE_INSERT;
722  m_statusBar->SetStatusText(_("Insert Bus: Click to insert, ESC to cancel."));
723  Redraw();
724  }
725  } break;
726  case 'L': {
727  if(!insertingElement) {
728  if(!event.ControlDown() && event.ShiftDown()) { // Insert a load.
729  Load* newLoad = new Load(wxString::Format(_("Load %d"), GetElementNumber(ID_LOAD)));
730  IncrementElementNumber(ID_LOAD);
731  m_elementList.push_back(newLoad);
732  m_mode = MODE_INSERT;
733  m_statusBar->SetStatusText(_("Insert Load: Click on a buses, ESC to cancel."));
734  } else if(!event.ControlDown() && !event.ShiftDown()) { // Insert a power line.
735  Line* newLine = new Line(wxString::Format(_("Line %d"), GetElementNumber(ID_LINE)));
736  IncrementElementNumber(ID_LINE);
737  m_elementList.push_back(newLine);
738  m_mode = MODE_INSERT;
739  m_statusBar->SetStatusText(_("Insert Line: Click on two buses, ESC to cancel."));
740  }
741  Redraw();
742  }
743  // Tests - Ctrl + Shift + L
744  if(event.ControlDown() && event.ShiftDown()) {
745  // Nothing...
746  }
747  } break;
748  case 'T': // Insert a transformer.
749  {
750  if(!insertingElement) {
751  Transformer* newTransformer =
752  new Transformer(wxString::Format(_("Transformer %d"), GetElementNumber(ID_TRANSFORMER)));
753  IncrementElementNumber(ID_TRANSFORMER);
754  m_elementList.push_back(newTransformer);
755  m_mode = MODE_INSERT;
756  m_statusBar->SetStatusText(_("Insert Transformer: Click on two buses, ESC to cancel."));
757  Redraw();
758  }
759  } break;
760  case 'G': // Insert a generator.
761  {
762  if(!insertingElement) {
763  SyncGenerator* newGenerator =
764  new SyncGenerator(wxString::Format(_("Generator %d"), GetElementNumber(ID_SYNCGENERATOR)));
765  IncrementElementNumber(ID_SYNCGENERATOR);
766  m_elementList.push_back(newGenerator);
767  m_mode = MODE_INSERT;
768  m_statusBar->SetStatusText(_("Insert Generator: Click on a buses, ESC to cancel."));
769  Redraw();
770  }
771  } break;
772  case 'I': {
773  if(!insertingElement) {
774  if(event.GetModifiers() == wxMOD_SHIFT) { // Insert an inductor.
775  Inductor* newInductor =
776  new Inductor(wxString::Format(_("Inductor %d"), GetElementNumber(ID_INDUCTOR)));
777  IncrementElementNumber(ID_INDUCTOR);
778  m_elementList.push_back(newInductor);
779  m_mode = MODE_INSERT;
780  m_statusBar->SetStatusText(_("Insert Inductor: Click on a buses, ESC to cancel."));
781  } else // Insert an induction motor.
782  {
783  IndMotor* newIndMotor =
784  new IndMotor(wxString::Format(_("Induction motor %d"), GetElementNumber(ID_INDMOTOR)));
785  IncrementElementNumber(ID_INDMOTOR);
786  m_elementList.push_back(newIndMotor);
787  m_mode = MODE_INSERT;
788  m_statusBar->SetStatusText(_("Insert Induction Motor: Click on a buses, ESC to cancel."));
789  }
790  Redraw();
791  }
792  } break;
793  case 'K': // Insert a synchronous condenser.
794  {
795  if(!insertingElement) {
796  SyncMotor* newSyncCondenser =
797  new SyncMotor(wxString::Format(_("Synchronous condenser %d"), GetElementNumber(ID_SYNCMOTOR)));
798  IncrementElementNumber(ID_SYNCMOTOR);
799  m_elementList.push_back(newSyncCondenser);
800  m_mode = MODE_INSERT;
801  m_statusBar->SetStatusText(_("Insert Synchronous Condenser: Click on a buses, ESC to cancel."));
802  Redraw();
803  }
804  } break;
805  case 'C': {
806  if(!insertingElement) {
807  if(event.GetModifiers() == wxMOD_SHIFT) { // Insert a capacitor.
808  Capacitor* newCapacitor =
809  new Capacitor(wxString::Format(_("Capacitor %d"), GetElementNumber(ID_CAPACITOR)));
810  IncrementElementNumber(ID_CAPACITOR);
811  m_elementList.push_back(newCapacitor);
812  m_mode = MODE_INSERT;
813  m_statusBar->SetStatusText(_("Insert Capacitor: Click on a buses, ESC to cancel."));
814  Redraw();
815  } else if(event.GetModifiers() == wxMOD_CONTROL) { // Copy.
816  CopySelection();
817  }
818  }
819  } break;
820  case 'V': {
821  if(!insertingElement) {
822  if(event.GetModifiers() == wxMOD_CONTROL) {
823  Paste();
824  }
825  }
826  } break;
827  default:
828  break;
829  }
830  }
831 
832  UpdateStatusBar();
833  event.Skip();
834 }
835 
836 void Workspace::UpdateStatusBar()
837 {
838  switch(m_mode) {
839  case MODE_DRAG: {
840  m_statusBar->SetStatusText(_("MODE: DRAG"), 1);
841  } break;
842 
843  case MODE_PASTE:
844  case MODE_DRAG_PASTE: {
845  m_statusBar->SetStatusText(_("MODE: PASTE"), 1);
846  }
847 
848  case MODE_INSERT:
849  case MODE_INSERT_TEXT:
850  case MODE_DRAG_INSERT:
851  case MODE_DRAG_INSERT_TEXT: {
852  m_statusBar->SetStatusText(_("MODE: INSERT"), 1);
853  } break;
854 
855  case MODE_MOVE_ELEMENT:
856  case MODE_MOVE_PICKBOX:
857  case MODE_MOVE_NODE:
858  case MODE_SELECTION_RECT:
859  case MODE_EDIT: {
860  m_statusBar->SetStatusText(wxT(""));
861  m_statusBar->SetStatusText(_("MODE: EDIT"), 1);
862  } break;
863  }
864 
865  m_statusBar->SetStatusText(wxString::Format(_("ZOOM: %d%%"), (int)(m_camera->GetScale() * 100.0)), 2);
866  m_statusBar->SetStatusText(
867  wxString::Format(wxT("X: %.1f Y: %.1f"), m_camera->GetMousePosition().m_x, m_camera->GetMousePosition().m_y),
868  3);
869 }
870 
871 void Workspace::OnPopupClick(wxCommandEvent& event)
872 {
873  wxMenu* menu = static_cast<wxMenu*>(event.GetEventObject());
874  Element* element = static_cast<Element*>(menu->GetClientData());
875  switch(event.GetId()) {
876  case ID_EDIT_ELEMENT: {
877  if(element->ShowForm(this, element)) UpdateTextElements();
878  } break;
879  case ID_LINE_ADD_NODE: {
880  Line* line = static_cast<Line*>(element);
881  line->AddNode(m_camera->GetMousePosition());
882  Redraw();
883  } break;
884  case ID_LINE_REMOVE_NODE: {
885  Line* line = static_cast<Line*>(element);
886  line->RemoveNode(m_camera->GetMousePosition());
887  Redraw();
888  } break;
889  case ID_ROTATE_CLOCK: {
890  element->Rotate();
891  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
892  Element* iElement = *it;
893  // Parent's element rotating...
894  for(int i = 0; i < (int)iElement->GetParentList().size(); i++) {
895  Element* parent = iElement->GetParentList()[i];
896  if(parent == element) {
897  iElement->RotateNode(parent);
898  }
899  }
900  }
901  Redraw();
902  } break;
903  case ID_ROTATE_COUNTERCLOCK: {
904  element->Rotate(false);
905  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
906  Element* iElement = *it;
907  // Parent's element rotating...
908  for(int i = 0; i < (int)iElement->GetParentList().size(); i++) {
909  Element* parent = iElement->GetParentList()[i];
910  if(parent == element) {
911  iElement->RotateNode(parent, false);
912  }
913  }
914  }
915  Redraw();
916  } break;
917  case ID_DELETE: {
918  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
919  Element* iElement = *it;
920 
921  if(element == iElement) {
922  // Remove child/parent.
923  std::vector<Element*> childList = element->GetChildList();
924  for(auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
925  Element* child = *itc;
926  if(child) {
927  child->RemoveParent(element);
928  element->RemoveChild(child);
929  }
930  }
931  std::vector<Element*> parentList = element->GetParentList();
932  for(auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
933  Element* parent = *itp;
934  if(parent) {
935  parent->RemoveChild(element);
936  }
937  }
938 
939  for(auto itt = m_textList.begin(); itt != m_textList.end(); ++itt) {
940  Text* text = *itt;
941  if(text->GetElement() == element) {
942  m_textList.erase(itt--);
943  if(text) delete text;
944  }
945  }
946 
947  m_elementList.erase(it);
948  if(element) delete element;
949  menu->SetClientData(NULL);
950  break;
951  }
952  }
953  } break;
954  }
955 }
956 
957 void Workspace::RotateSelectedElements(bool clockwise)
958 {
959  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
960  Element* element = *it;
961  // Parent's element rotating...
962  for(int i = 0; i < (int)element->GetParentList().size(); i++) {
963  Element* parent = element->GetParentList()[i];
964  if(parent) { // Check if parent is not null
965  if(parent->IsSelected()) {
966  element->RotateNode(parent, clockwise);
967  // Update the positions used on motion action, the element will not be necessarily
968  // moved.
969  element->StartMove(m_camera->GetMousePosition());
970  }
971  }
972  }
973  if(element->IsSelected()) {
974  element->Rotate(clockwise);
975  element->StartMove(m_camera->GetMousePosition());
976  }
977  }
978 
979  // Rotate text element
980  for(auto it = m_textList.begin(); it != m_textList.end(); it++) {
981  Text* text = *it;
982  if(text->IsSelected()) {
983  text->Rotate(clockwise);
984  text->StartMove(m_camera->GetMousePosition());
985  }
986  }
987  Redraw();
988 }
989 
990 void Workspace::DeleteSelectedElements()
991 {
992  // Don't set the end of the list at the loop's begin.
993  for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
994  Element* element = *it;
995 
996  if(element->IsSelected()) {
997  // Remove child/parent.
998  std::vector<Element*> childList = element->GetChildList();
999  for(auto itc = childList.begin(), itEnd = childList.end(); itc != itEnd; ++itc) {
1000  Element* child = *itc;
1001  if(child) {
1002  child->RemoveParent(element);
1003  element->RemoveChild(child);
1004  }
1005  }
1006  std::vector<Element*> parentList = element->GetParentList();
1007  for(auto itp = parentList.begin(), itEnd = parentList.end(); itp != itEnd; ++itp) {
1008  Element* parent = *itp;
1009  if(parent) {
1010  parent->RemoveChild(element);
1011  }
1012  }
1013 
1014  for(auto itt = m_textList.begin(); itt != m_textList.end(); ++itt) {
1015  Text* text = *itt;
1016  if(text->GetElement() == element) {
1017  m_textList.erase(itt--);
1018  if(text) delete text;
1019  }
1020  }
1021 
1022  m_elementList.erase(it--);
1023  if(element) delete element;
1024  }
1025  }
1026 
1027  for(auto it = m_textList.begin(); it != m_textList.end(); ++it) {
1028  Text* text = *it;
1029  if(text->IsSelected()) {
1030  m_textList.erase(it--);
1031  if(text) delete text;
1032  }
1033  }
1034 
1035  Redraw();
1036 }
1037 
1038 bool Workspace::GetElementsCorners(wxPoint2DDouble& leftUpCorner,
1039  wxPoint2DDouble& rightDownCorner,
1040  std::vector<Element*> elementList)
1041 {
1042  if(elementList.size() == 0) return false;
1043 
1044  elementList[0]->CalculateBoundaries(leftUpCorner, rightDownCorner);
1045 
1046  for(auto it = elementList.begin() + 1, itEnd = elementList.end(); it != itEnd; it++) {
1047  Element* element = *it;
1048  wxPoint2DDouble leftUp;
1049  wxPoint2DDouble rightDown;
1050  element->CalculateBoundaries(leftUp, rightDown);
1051  if(leftUp.m_x < leftUpCorner.m_x) leftUpCorner.m_x = leftUp.m_x;
1052  if(leftUp.m_y < leftUpCorner.m_y) leftUpCorner.m_y = leftUp.m_y;
1053  if(rightDown.m_x > rightDownCorner.m_x) rightDownCorner.m_x = rightDown.m_x;
1054  if(rightDown.m_y > rightDownCorner.m_y) rightDownCorner.m_y = rightDown.m_y;
1055  }
1056  return true;
1057 }
1058 
1059 void Workspace::Fit()
1060 {
1061  wxPoint2DDouble leftUpCorner(0, 0);
1062  wxPoint2DDouble rightDownCorner(0, 0);
1063  std::vector<Element*> elementList = GetElementList();
1064  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1065  elementList.push_back(*it);
1066  }
1067 
1068  if(!GetElementsCorners(leftUpCorner, rightDownCorner, elementList)) return;
1069  wxPoint2DDouble middleCoords = (leftUpCorner + rightDownCorner) / 2.0;
1070 
1071  int width = 0.0;
1072  int height = 0.0;
1073  GetSize(&width, &height);
1074 
1075  double scaleX = double(width) / (rightDownCorner.m_x - leftUpCorner.m_x);
1076  double scaleY = double(height) / (rightDownCorner.m_y - leftUpCorner.m_y);
1077 
1078  double scale = scaleX < scaleY ? scaleX : scaleY;
1079  if(scale > m_camera->GetZoomMax()) scale = m_camera->GetZoomMax();
1080  if(scale < m_camera->GetZoomMin()) scale = m_camera->GetZoomMin();
1081 
1082  m_camera->SetScale(scale);
1083 
1084  m_camera->StartTranslation(middleCoords);
1085  m_camera->SetTranslation(wxPoint2DDouble(width / 2, height / 2));
1086  Redraw();
1087 }
1088 
1089 void Workspace::ValidateBusesVoltages(Element* initialBus)
1090 {
1091  double nominalVoltage = static_cast<Bus*>(initialBus)->GetElectricalData().nominalVoltage;
1092  ElectricalUnit nominalVoltageUnit = static_cast<Bus*>(initialBus)->GetElectricalData().nominalVoltageUnit;
1093 
1094  for(auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1095  Element* child = *it;
1096 
1097  if(typeid(*child) == typeid(Line)) {
1098  if(child->GetParentList()[0] && child->GetParentList()[1]) {
1099  BusElectricalData data1 = static_cast<Bus*>(child->GetParentList()[0])->GetElectricalData();
1100  BusElectricalData data2 = static_cast<Bus*>(child->GetParentList()[1])->GetElectricalData();
1101 
1102  if(data1.nominalVoltage != data2.nominalVoltage ||
1103  data1.nominalVoltageUnit != data2.nominalVoltageUnit) {
1104  data1.nominalVoltage = nominalVoltage;
1105  data2.nominalVoltage = nominalVoltage;
1106  data1.nominalVoltageUnit = nominalVoltageUnit;
1107  data2.nominalVoltageUnit = nominalVoltageUnit;
1108 
1109  static_cast<Bus*>(child->GetParentList()[0])->SetElectricalData(data1);
1110  static_cast<Bus*>(child->GetParentList()[1])->SetElectricalData(data2);
1111 
1112  it = m_elementList.begin(); // Restart search.
1113  }
1114  }
1115  }
1116  }
1117 
1118  // ValidateElementsVoltages();
1119 }
1120 
1121 void Workspace::ValidateElementsVoltages()
1122 {
1123  for(auto it = m_elementList.begin(); it != m_elementList.end(); it++) {
1124  PowerElement* child = *it;
1125 
1126  std::vector<double> nominalVoltage;
1127  std::vector<ElectricalUnit> nominalVoltageUnit;
1128  for(int i = 0; i < (int)child->GetParentList().size(); i++) {
1129  Bus* parent = static_cast<Bus*>(child->GetParentList()[i]);
1130  if(parent) {
1131  nominalVoltage.push_back(parent->GetElectricalData().nominalVoltage);
1132  nominalVoltageUnit.push_back(parent->GetElectricalData().nominalVoltageUnit);
1133  }
1134  }
1135  child->SetNominalVoltage(nominalVoltage, nominalVoltageUnit);
1136  }
1137 }
1138 
1139 bool Workspace::RunPowerFlow()
1140 {
1141  PowerFlow pf(GetElementList());
1142  bool result = pf.RunGaussSeidel();
1143  if(!result) {
1144  wxMessageDialog msgDialog(this, pf.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1145  msgDialog.ShowModal();
1146  }
1147 
1148  UpdateTextElements();
1149  Redraw();
1150 
1151  return result;
1152 }
1153 
1154 void Workspace::UpdateTextElements()
1155 {
1156  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1157  Text* text = *it;
1158  text->UpdateText(m_properties->GetSimulationPropertiesData().basePower);
1159  }
1160 }
1161 
1162 void Workspace::CopySelection()
1163 {
1164  UpdateElementsID();
1165  std::vector<Element*> selectedElements;
1166  // The buses need to be numerated to associate the child's parents to the copies.
1167  int busNumber = 0;
1168  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1169  Element* element = *it;
1170  if(typeid(*element) == typeid(Bus)) {
1171  Bus* bus = static_cast<Bus*>(element);
1172  auto data = bus->GetElectricalData();
1173  data.number = busNumber;
1174  bus->SetElectricalData(data);
1175  busNumber++;
1176  }
1177  if(element->IsSelected()) {
1178  selectedElements.push_back(element);
1179  }
1180  }
1181  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1182  Text* text = *it;
1183  if(text->IsSelected()) {
1184  selectedElements.push_back(text);
1185  }
1186  }
1187  ElementDataObject* dataObject = new ElementDataObject(selectedElements);
1188  wxTheClipboard->SetData(dataObject);
1189  wxTheClipboard->Close();
1190 }
1191 
1192 bool Workspace::Paste()
1193 {
1194  if(wxTheClipboard->Open()) {
1195  ElementDataObject dataObject;
1196 
1197  if(wxTheClipboard->IsSupported(wxDataFormat("PSPCopy"))) {
1198  if(!wxTheClipboard->GetData(dataObject)) {
1199  wxMessageDialog dialog(this, _("It was not possible to paste from clipboard."), _("Error"),
1200  wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1201  dialog.ShowModal();
1202  wxTheClipboard->Close();
1203  return false;
1204  }
1205  } else {
1206  wxTheClipboard->Close();
1207  return false;
1208  }
1209  wxTheClipboard->Close();
1210 
1211  UnselectAll();
1212 
1213  std::vector<Element*> pastedElements;
1214  ElementsLists* elementsLists = dataObject.GetElementsLists();
1215 
1216  // Paste buses (parents).
1217  auto parentList = elementsLists->parentList;
1218  std::vector<Bus*> pastedBusList; // To set new parents;
1219  for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
1220  Element* copy = (*it)->GetCopy();
1221  if(copy) {
1222  pastedElements.push_back(copy);
1223  pastedBusList.push_back(static_cast<Bus*>(copy));
1224  m_elementList.push_back(static_cast<PowerElement*>(copy));
1225  }
1226  }
1227 
1228  // Paste other elements.
1229  auto elementLists = elementsLists->elementList;
1230  for(auto it = elementLists.begin(), itEnd = elementLists.end(); it != itEnd; ++it) {
1231  Element* copy = (*it)->GetCopy();
1232  if(copy) {
1233  // Check if is text element
1234  if(Text* text = dynamic_cast<Text*>(copy)) {
1235  // Check if element associated with the text exists.
1236  bool elementExist = false;
1237  for(int i = 0; i < (int)m_elementList.size(); i++) {
1238  if(text->GetElement() == m_elementList[i]) {
1239  elementExist = true;
1240  break;
1241  }
1242  }
1243  if(elementExist) {
1244  pastedElements.push_back(copy);
1245  m_textList.push_back(text);
1246  }
1247  } else {
1248  // Change the parent if copied, otherwise remove it.
1249  for(int j = 0; j < (int)copy->GetParentList().size(); j++) {
1250  Bus* currentParent = static_cast<Bus*>(copy->GetParentList()[j]);
1251  if(currentParent) {
1252  int parentID = currentParent->GetID();
1253  bool parentCopied = false;
1254  for(int k = 0; k < (int)pastedBusList.size(); k++) {
1255  Bus* newParent = pastedBusList[k];
1256  if(parentID == newParent->GetID()) {
1257  parentCopied = true;
1258  copy->ReplaceParent(currentParent, newParent);
1259  break;
1260  }
1261  }
1262  if(!parentCopied) copy->RemoveParent(currentParent);
1263  }
1264  }
1265 
1266  pastedElements.push_back(copy);
1267  m_elementList.push_back(static_cast<PowerElement*>(copy));
1268  }
1269  }
1270  }
1271 
1272  // Update buses childs
1273  for(auto it = pastedBusList.begin(), itEnd = pastedBusList.end(); it != itEnd; ++it) {
1274  Bus* bus = *it;
1275  std::vector<Element*> childList = bus->GetChildList();
1276  for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
1277  Element* currentChild = *it;
1278  int childID = currentChild->GetID();
1279  bool childCopied = false;
1280  for(int i = 0; i < (int)pastedElements.size(); i++) {
1281  Element* newChild = pastedElements[i];
1282  if(childID == newChild->GetID()) {
1283  childCopied = true;
1284  bus->ReplaceChild(currentChild, newChild);
1285  break;
1286  }
1287  }
1288  if(!childCopied) bus->RemoveChild(currentChild);
1289  }
1290  }
1291 
1292  // Move elements (and nodes) to the mouse position.
1293  // The start position it's the center of the pasted objects.
1294  wxPoint2DDouble leftUpCorner, rightDownCorner;
1295  GetElementsCorners(leftUpCorner, rightDownCorner, pastedElements);
1296  wxPoint2DDouble startPosition = (leftUpCorner + rightDownCorner) / 2.0;
1297  for(auto it = pastedElements.begin(), itEnd = pastedElements.end(); it != itEnd; ++it) {
1298  Element* element = *it;
1299  element->StartMove(startPosition);
1300  element->Move(m_camera->GetMousePosition());
1301  for(int i = 0; i < (int)element->GetParentList().size(); i++) {
1302  Element* parent = element->GetParentList()[i];
1303  element->MoveNode(parent, m_camera->GetMousePosition());
1304  }
1305  }
1306  } else {
1307  wxMessageDialog dialog(this, _("It was not possible to paste from clipboard."), _("Error"),
1308  wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1309  dialog.ShowModal();
1310  return false;
1311  }
1312 
1313  UpdateElementsID();
1314  m_mode = MODE_PASTE;
1315  m_statusBar->SetStatusText(_("Click to paste."));
1316  UpdateStatusBar();
1317  Redraw();
1318  return true;
1319 }
1320 
1321 void Workspace::UnselectAll()
1322 {
1323  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
1324  Element* element = *it;
1325  element->SetSelected(false);
1326  }
1327  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; it++) {
1328  Text* text = *it;
1329  text->SetSelected(false);
1330  }
1331 }
1332 
1333 void Workspace::UpdateElementsID()
1334 {
1335  int id = 0;
1336  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1337  Element* element = *it;
1338  element->SetID(id);
1339  id++;
1340  }
1341  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) {
1342  Text* text = *it;
1343  text->SetID(id);
1344  id++;
1345  }
1346 }
1347 void Workspace::OnTimer(wxTimerEvent& event)
1348 {
1349  if(m_tipWindow) {
1350  m_tipWindow->Close();
1351  m_tipWindow = NULL;
1352  }
1353  if(m_mode == MODE_EDIT) {
1354  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1355  Element* element = *it;
1356  if(element->Contains(m_camera->GetMousePosition())) {
1357  wxString tipText = element->GetTipText();
1358  if(!tipText.IsEmpty()) {
1359  m_tipWindow = new wxTipWindow(this, tipText, 10000, &m_tipWindow);
1360  // Creates a very tiny bounding rect to remove the tip on any mouse movement.
1361  m_tipWindow->SetBoundingRect(wxRect(wxGetMousePosition(), wxSize(1, 1)));
1362  break;
1363  }
1364  }
1365  }
1366  }
1367 
1368  m_timer->Stop();
1369 }
1370 
1371 void Workspace::SetTextList(std::vector<Text*> textList)
1372 {
1373  m_textList.clear();
1374  for(auto it = textList.begin(), itEnd = textList.end(); it != itEnd; ++it) m_textList.push_back(*it);
1375 
1376  UpdateTextElements();
1377 }
1378 
1379 void Workspace::SetElementList(std::vector<Element*> elementList)
1380 {
1381  m_elementList.clear();
1382  for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it)
1383  m_elementList.push_back(static_cast<PowerElement*>(*it));
1384 }
1385 
1386 void Workspace::OnIdle(wxIdleEvent& event)
1387 {
1388  // TODO: Find other solution to text displayed wrong on opened file.
1389  if(m_justOpened) {
1390  m_justOpened = false;
1391  UpdateTextElements();
1392  Redraw();
1393  }
1394 }
1395 
1396 std::vector<Element*> Workspace::GetAllElements() const
1397 {
1398  std::vector<Element*> allElements;
1399 
1400  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) allElements.push_back(*it);
1401  for(auto it = m_textList.begin(), itEnd = m_textList.end(); it != itEnd; ++it) allElements.push_back(*it);
1402 
1403  return allElements;
1404 }
1405 
1406 bool Workspace::RunFault()
1407 {
1408  Fault fault(GetElementList());
1409  bool result = fault.RunFaultCalculation(100e6);
1410  if(!result) {
1411  wxMessageDialog msgDialog(this, fault.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1412  msgDialog.ShowModal();
1413  }
1414 
1415  UpdateTextElements();
1416  Redraw();
1417 
1418  return result;
1419 }
1420 
1421 std::vector<Element*> Workspace::GetElementList() const
1422 {
1423  std::vector<Element*> elementList;
1424  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) elementList.push_back(*it);
1425  return elementList;
1426 }
1427 
1428 bool Workspace::RunSCPower()
1429 {
1430  Fault fault(GetElementList());
1431  bool result = fault.RunSCPowerCalcutation(100e6);
1432  if(!result) {
1433  wxMessageDialog msgDialog(this, fault.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1434  msgDialog.ShowModal();
1435  }
1436 
1437  UpdateTextElements();
1438  Redraw();
1439 
1440  return result;
1441 }
1442 
1443 bool Workspace::RunStability()
1444 {
1445  // Run power flow before stability.
1446  RunPowerFlow();
1447 
1448  Electromechanical stability(this, GetElementList(), m_properties->GetSimulationPropertiesData());
1449  bool result = stability.RunStabilityCalculation();
1450  if(!result) {
1451  wxMessageDialog msgDialog(this, stability.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
1452  msgDialog.ShowModal();
1453  }
1454  m_stabilityTimeVector.clear();
1455  m_stabilityTimeVector = stability.GetTimeVector();
1456 
1457  // Run power flow after stability.
1458  RunPowerFlow();
1459 
1460  wxMessageDialog msgDialog(this, _("Do you wish to open the stability graphics?"), _("Question"),
1461  wxYES_NO | wxCENTRE | wxICON_QUESTION);
1462  if(msgDialog.ShowModal() == wxID_YES) {
1463  std::vector<ElementPlotData> plotDataList;
1464  for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
1465  PowerElement* element = *it;
1466  ElementPlotData plotData;
1467  if(element->GetPlotData(plotData)) plotDataList.push_back(plotData);
1468  }
1469  ElementPlotData tests(_("Error"), ElementPlotData::CT_TEST);
1470  tests.AddData(stability.m_wErrorVector, _("Speed error"));
1471  tests.AddData(stability.m_sdCVector, _("Sd"));
1472  tests.AddData(stability.m_sqCVector, _("Sq"));
1473  tests.AddData(stability.m_numItVector, _("Number iterations"));
1474  plotDataList.push_back(tests);
1475 
1476  ChartView* cView = new ChartView(this, plotDataList, m_stabilityTimeVector);
1477  cView->Show();
1478  }
1479 
1480  return result;
1481 }
1482 void Workspace::OnMiddleDoubleClick(wxMouseEvent& event)
1483 {
1484  Fit();
1485  event.Skip();
1486 }
1487 
1488 bool Workspace::RunStaticStudies()
1489 {
1490  bool pfStatus, faultStatus, scStatus;
1491  pfStatus = faultStatus = scStatus = false;
1492 
1493  pfStatus = RunPowerFlow();
1494 
1495  if(m_properties->GetSimulationPropertiesData().faultAfterPowerFlow) {
1496  if(pfStatus) faultStatus = RunFault();
1497  } else {
1498  faultStatus = true;
1499  }
1500 
1501  if(m_properties->GetSimulationPropertiesData().scPowerAfterPowerFlow) {
1502  if(pfStatus) scStatus = RunSCPower();
1503  } else {
1504  scStatus = true;
1505  }
1506 
1507  if(pfStatus && faultStatus && scStatus) return true;
1508 
1509  return false;
1510 }
virtual bool Contains(wxPoint2DDouble position) const
Checks if the element contains a position.
Definition: Text.cpp:47
+
Element that shows power element informations in workspace.
Definition: Text.h:72
void ShowPickbox(bool showPickbox=true)
Set if the pickbox is shown.
Definition: Element.h:161
- +
General and simulation data manager.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Definition: Element.cpp:123
virtual void AddPoint(wxPoint2DDouble point)
Add point to the list of points that connect the element to the bus.
Definition: Element.h:318
- +
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
void SetSelected(bool selected=true)
Set element selection.
Definition: Element.h:146
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Text.cpp:162
+
virtual std::vector< Element * > GetParentList() const
Get the parent list.
Definition: Element.h:506
- -
Calculates the electromechanical transient based on disturbances (e.g. system fault).
+
Calculate the power flow.
Definition: PowerFlow.h:33
+ +
virtual std::vector< Element * > GetChildList() const
Get the Child list.
Definition: Element.h:511
virtual void ResetPickboxes()
Remove the pickboxes.
Definition: Element.h:393
@@ -110,9 +112,10 @@ $(document).ready(function(){initNavTree('_workspace_8cpp_source.html','');});
virtual void UpdateNodes()
Update the nodes according to the parents. If a parent is removed, use this method.
Definition: Element.h:347
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
+
virtual void RemoveChild(Element *child)
Remove a child from the list.
Definition: Element.cpp:354
- +
Synchronous generator power element.
virtual bool Intersects(wxRect2DDouble rect) const
Check if the element&#39;s rect intersects other rect.
Definition: Text.cpp:92
virtual bool Intersects(wxRect2DDouble rect) const =0
Check if the element&#39;s rect intersects other rect.
@@ -120,40 +123,49 @@ $(document).ready(function(){initNavTree('_workspace_8cpp_source.html','');});
Class responsible for the correct visualization of the elements on screen.
Definition: Camera.h:30
ElectricalUnit
Electrical units.
Definition: PowerElement.h:28
virtual void CalculateBoundaries(wxPoint2DDouble &leftUp, wxPoint2DDouble &rightBottom) const
Calculate the element boundaries.
Definition: Element.cpp:263
+
virtual bool AddParent(Element *parent, wxPoint2DDouble position)
Add a parent to the element. This method must be used on power elements that connect to a bus...
Definition: Element.h:240
-
Class to manage color of OpenGL.
+
virtual void ReplaceChild(Element *oldChild, Element *newChild)
Replace a child from the list.
Definition: Element.cpp:362
-
Definition: Bus.h:62
+
Node for power elements. All others power elements are connected through this.
Definition: Bus.h:69
virtual void Draw(wxPoint2DDouble translation, double scale) const
Draw the element.
Definition: Element.h:302
virtual bool GetPlotData(ElementPlotData &plotData)
Fill the plot data.
Definition: PowerElement.h:198
bool IsPickboxShown() const
Checks if the pickbox is shown.
Definition: Element.h:222
bool IsOnline() const
Checks if the element is online or offline.
Definition: Element.h:227
- + + + +
virtual wxString GetTipText() const
Get the tip text.
Definition: Element.h:296
- +
Class to store the elements in the clipboard.
void SetPosition(const wxPoint2DDouble position)
Set the element position and update the rectangle.
Definition: Element.cpp:25
+
virtual void Rotate(bool clockwise=true)
Rotate the element.
Definition: Element.h:307
-
Calculate the fault of the system and update the elements data.
+
virtual void AddChild(Element *child)
Add a child to the child list.
Definition: Element.cpp:353
-
Definition: Line.h:52
- -
Definition: Load.h:35
+
Power line element.
Definition: Line.h:59
+
Calculates the electromechanical transient based on disturbances (e.g. system fault).
+
Loas shunt power element.
Definition: Load.h:42
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition: Element.h:313
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition: Element.h:534
virtual void MovePickbox(wxPoint2DDouble position)
Move the pickbox.
Definition: Element.h:384
+ - + +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
virtual wxCursor GetBestPickboxCursor() const
Get the best cursor to shown to the user when the mouse is above a pickbox.
Definition: Element.h:389
-
Definition: Fault.h:30
- +
Calculate the fault of the system and update the elements data.
Definition: Fault.h:30
+
Induction motor power element.
Definition: IndMotor.h:40
bool IsSelected() const
Checks if the element is selected.
Definition: Element.h:202
virtual void RotateNode(Element *parent, bool clockwise=true)
Rotate a node.
Definition: Element.h:372
+
virtual void SetID(int id)
Set the element ID.
Definition: Element.h:267
virtual bool SetNodeParent(Element *parent)
Set a perent to the node. If all conditions are met, a new parent are added to the element and the po...
Definition: Element.h:354
virtual bool SwitchesContains(wxPoint2DDouble position) const
Check if switch contains position.
@@ -161,14 +173,15 @@ $(document).ready(function(){initNavTree('_workspace_8cpp_source.html','');});
virtual int GetID() const
Get the element ID.
Definition: Element.h:272
virtual void ReplaceParent(Element *oldParent, Element *newParent)
Replace a parent.
Definition: Element.cpp:346
virtual void RemoveParent(Element *parent)
Remove a parent.
Definition: Element.h:359
- +
Shunt capactior power element.
Definition: Capacitor.h:38
virtual bool Contains(wxPoint2DDouble position) const =0
Checks if the element contains a position.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
Definition: Element.cpp:117
- - +
Abstract class of power elements.
Definition: PowerElement.h:117
+
Inductor shunt power element.
Definition: Inductor.h:38
virtual void ResetNodes()
Remove the active nodes.
Definition: Element.h:397
+
virtual Element * GetCopy()
Get a the element copy.
Definition: Element.h:262
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/_workspace_8h.html b/docs/doxygen/html/_workspace_8h.html index f80d426..7d16e44 100644 --- a/docs/doxygen/html/_workspace_8h.html +++ b/docs/doxygen/html/_workspace_8h.html @@ -99,7 +99,7 @@ $(document).ready(function(){initNavTree('_workspace_8h.html','');}); #include <wx/clipbrd.h>
#include <wx/tipwin.h>
#include "WorkspaceBase.h"
-#include "Bus.h"
+#include "Bus.h"
#include "ControlEditor.h"

Go to the source code of this file.

diff --git a/docs/doxygen/html/_workspace_8h_source.html b/docs/doxygen/html/_workspace_8h_source.html index 2b1e648..767bdba 100644 --- a/docs/doxygen/html/_workspace_8h_source.html +++ b/docs/doxygen/html/_workspace_8h_source.html @@ -88,27 +88,28 @@ $(document).ready(function(){initNavTree('_workspace_8h_source.html','');});
Workspace.h
-Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef WORKSPACE_H
19 #define WORKSPACE_H
20 
21 #include <GL/gl.h>
22 #include <GL/glu.h>
23 #include <wx/dcclient.h>
24 #include <wx/msgdlg.h>
25 #include <wx/statusbr.h>
26 #include <wx/clipbrd.h>
27 #include <wx/tipwin.h>
28 
29 #include "WorkspaceBase.h"
30 #include "Bus.h"
31 
32 #include "ControlEditor.h"
33 
34 class Camera;
35 class Element;
36 // class Bus;
37 class Line;
38 class Transformer;
39 class SyncGenerator;
40 class IndMotor;
41 class SyncMotor;
42 class Load;
43 class Inductor;
44 class Capacitor;
45 class ElementDataObject;
46 
47 class Text;
48 
49 class PowerFlow;
50 class Fault;
51 class Electromechanical;
52 
53 class ElementPlotData;
54 class ChartView;
55 
56 class PropertiesData;
57 
58 enum ElementID {
59  ID_BUS = 0,
60  ID_LINE,
61  ID_TRANSFORMER,
62  ID_SYNCGENERATOR,
63  ID_INDMOTOR,
64  ID_SYNCMOTOR,
65  ID_LOAD,
66  ID_CAPACITOR,
67  ID_INDUCTOR,
68  ID_TEXT,
69 
70  NUM_ELEMENTS
71 };
72 
81 class Workspace : public WorkspaceBase
82 {
83  public:
84  enum WorkspaceMode {
85  MODE_EDIT = 0,
86  MODE_MOVE_ELEMENT,
87  MODE_MOVE_PICKBOX,
88  MODE_MOVE_NODE,
89  MODE_DRAG,
90  MODE_DRAG_INSERT,
91  MODE_DRAG_INSERT_TEXT,
92  MODE_INSERT,
93  MODE_INSERT_TEXT,
94  MODE_SELECTION_RECT,
95  MODE_PASTE,
96  MODE_DRAG_PASTE
97  };
98 
99  Workspace();
100  Workspace(wxWindow* parent, wxString name = wxEmptyString, wxStatusBar* statusBar = NULL);
101  ~Workspace();
102 
103  wxString GetName() const { return m_name; }
104  std::vector<Element*> GetElementList() const;
105  std::vector<Text*> GetTextList() const { return m_textList; }
106  std::vector<Element*> GetAllElements() const;
107  WorkspaceMode GetWorkspaceMode() const { return m_mode; }
108  Camera* GetCamera() const { return m_camera; }
109  void CopySelection();
110  bool Paste();
111 
112  wxFileName GetSavedPath() const { return m_savedPath; }
113  void SetName(wxString name) { m_name = name; }
114  void SetElementList(std::vector<Element*> elementList);
115  void SetTextList(std::vector<Text*> textList);
116  void SetStatusBarText(wxString text) { m_statusBar->SetStatusText(text); }
117  void SetWorkspaceMode(WorkspaceMode mode) { m_mode = mode; }
118  void SetSavedPath(wxFileName savedPath) { m_savedPath = savedPath; }
119  void SetJustOpened(bool justOpened) { m_justOpened = justOpened; }
120  void Redraw() { m_glCanvas->Refresh(); }
121  void RotateSelectedElements(bool clockwise = true);
122  void DeleteSelectedElements();
123  bool GetElementsCorners(wxPoint2DDouble& leftUpCorner,
124  wxPoint2DDouble& rightDownCorner,
125  std::vector<Element*> elementList);
126  void Fit();
127  void UnselectAll();
128 
129  void ValidateBusesVoltages(Element* initialBus);
130  void ValidateElementsVoltages();
131 
132  void UpdateElementsID();
133  void UpdateTextElements();
134 
135  int GetElementNumber(ElementID elementID) { return m_elementNumber[elementID]; }
136  void IncrementElementNumber(ElementID elementID) { m_elementNumber[elementID]++; }
137  PropertiesData* GetProperties() const { return m_properties; }
138  std::vector<double> GetStabilityTimeVector() const { return m_stabilityTimeVector; }
139  bool IsContinuousCalculationActive() const { return m_continuousCalc; }
140  void SetContinuousCalculationActive(bool value = true) { m_continuousCalc = value; }
141  bool RunPowerFlow();
142  bool RunFault();
143  bool RunSCPower();
144  bool RunStaticStudies();
145  bool RunStability();
146 
147  protected:
148  virtual void OnMiddleDoubleClick(wxMouseEvent& event);
149  virtual void OnIdle(wxIdleEvent& event);
150  virtual void OnTimer(wxTimerEvent& event);
151  virtual void OnLeftDoubleClick(wxMouseEvent& event);
152  virtual void OnRightClickDown(wxMouseEvent& event);
153  virtual void OnLeftClickUp(wxMouseEvent& event);
154  virtual void OnScroll(wxMouseEvent& event);
155  virtual void OnMiddleDown(wxMouseEvent& event);
156  virtual void OnMiddleUp(wxMouseEvent& event);
157  virtual void OnMouseMotion(wxMouseEvent& event);
158  virtual void OnKeyDown(wxKeyEvent& event);
159  virtual void OnLeftClickDown(wxMouseEvent& event);
160  virtual void OnPaint(wxPaintEvent& event);
161  virtual void OnPopupClick(wxCommandEvent& event);
162 
163  void SetViewport();
164  void UpdateStatusBar();
165 
166  wxGLContext* m_glContext = NULL;
167  wxStatusBar* m_statusBar = NULL;
168  Camera* m_camera = NULL;
169  wxTipWindow* m_tipWindow = NULL;
170  wxString m_name;
171 
172  WorkspaceMode m_mode = MODE_EDIT;
173 
174  std::vector<PowerElement*> m_elementList;
175  int m_elementNumber[NUM_ELEMENTS];
176 
177  std::vector<Text*> m_textList;
178 
179  wxFileName m_savedPath;
180 
181  wxRect2DDouble m_selectionRect;
182  wxPoint2DDouble m_startSelRect;
183 
184  PropertiesData* m_properties = NULL;
185 
186  std::vector<double> m_stabilityTimeVector;
187 
188  bool m_continuousCalc = false;
189  bool m_disconnectedElement = false;
190  bool m_justOpened = false;
191 };
192 
193 #endif // WORKSPACE_H
Definition: Text.h:65
- - - - +Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef WORKSPACE_H
19 #define WORKSPACE_H
20 
21 #include <GL/gl.h>
22 #include <GL/glu.h>
23 #include <wx/dcclient.h>
24 #include <wx/msgdlg.h>
25 #include <wx/statusbr.h>
26 #include <wx/clipbrd.h>
27 #include <wx/tipwin.h>
28 
29 #include "WorkspaceBase.h"
30 #include "Bus.h"
31 
32 #include "ControlEditor.h"
33 
34 class Camera;
35 class Element;
36 // class Bus;
37 class Line;
38 class Transformer;
39 class SyncGenerator;
40 class IndMotor;
41 class SyncMotor;
42 class Load;
43 class Inductor;
44 class Capacitor;
45 class ElementDataObject;
46 
47 class Text;
48 
49 class PowerFlow;
50 class Fault;
51 class Electromechanical;
52 
53 class ElementPlotData;
54 class ChartView;
55 
56 class PropertiesData;
57 
58 enum ElementID {
59  ID_BUS = 0,
60  ID_LINE,
61  ID_TRANSFORMER,
62  ID_SYNCGENERATOR,
63  ID_INDMOTOR,
64  ID_SYNCMOTOR,
65  ID_LOAD,
66  ID_CAPACITOR,
67  ID_INDUCTOR,
68  ID_TEXT,
69 
70  NUM_ELEMENTS
71 };
72 
81 class Workspace : public WorkspaceBase
82 {
83  public:
84  enum WorkspaceMode {
85  MODE_EDIT = 0,
86  MODE_MOVE_ELEMENT,
87  MODE_MOVE_PICKBOX,
88  MODE_MOVE_NODE,
89  MODE_DRAG,
90  MODE_DRAG_INSERT,
91  MODE_DRAG_INSERT_TEXT,
92  MODE_INSERT,
93  MODE_INSERT_TEXT,
94  MODE_SELECTION_RECT,
95  MODE_PASTE,
96  MODE_DRAG_PASTE
97  };
98 
99  Workspace();
100  Workspace(wxWindow* parent, wxString name = wxEmptyString, wxStatusBar* statusBar = NULL);
101  ~Workspace();
102 
103  wxString GetName() const { return m_name; }
104  std::vector<Element*> GetElementList() const;
105  std::vector<Text*> GetTextList() const { return m_textList; }
106  std::vector<Element*> GetAllElements() const;
107  WorkspaceMode GetWorkspaceMode() const { return m_mode; }
108  Camera* GetCamera() const { return m_camera; }
109  void CopySelection();
110  bool Paste();
111 
112  wxFileName GetSavedPath() const { return m_savedPath; }
113  void SetName(wxString name) { m_name = name; }
114  void SetElementList(std::vector<Element*> elementList);
115  void SetTextList(std::vector<Text*> textList);
116  void SetStatusBarText(wxString text) { m_statusBar->SetStatusText(text); }
117  void SetWorkspaceMode(WorkspaceMode mode) { m_mode = mode; }
118  void SetSavedPath(wxFileName savedPath) { m_savedPath = savedPath; }
119  void SetJustOpened(bool justOpened) { m_justOpened = justOpened; }
120  void Redraw() { m_glCanvas->Refresh(); }
121  void RotateSelectedElements(bool clockwise = true);
122  void DeleteSelectedElements();
123  bool GetElementsCorners(wxPoint2DDouble& leftUpCorner,
124  wxPoint2DDouble& rightDownCorner,
125  std::vector<Element*> elementList);
126  void Fit();
127  void UnselectAll();
128 
129  void ValidateBusesVoltages(Element* initialBus);
130  void ValidateElementsVoltages();
131 
132  void UpdateElementsID();
133  void UpdateTextElements();
134 
135  int GetElementNumber(ElementID elementID) { return m_elementNumber[elementID]; }
136  void IncrementElementNumber(ElementID elementID) { m_elementNumber[elementID]++; }
137  PropertiesData* GetProperties() const { return m_properties; }
138  std::vector<double> GetStabilityTimeVector() const { return m_stabilityTimeVector; }
139  bool IsContinuousCalculationActive() const { return m_continuousCalc; }
140  void SetContinuousCalculationActive(bool value = true) { m_continuousCalc = value; }
141  bool RunPowerFlow();
142  bool RunFault();
143  bool RunSCPower();
144  bool RunStaticStudies();
145  bool RunStability();
146 
147  protected:
148  virtual void OnMiddleDoubleClick(wxMouseEvent& event);
149  virtual void OnIdle(wxIdleEvent& event);
150  virtual void OnTimer(wxTimerEvent& event);
151  virtual void OnLeftDoubleClick(wxMouseEvent& event);
152  virtual void OnRightClickDown(wxMouseEvent& event);
153  virtual void OnLeftClickUp(wxMouseEvent& event);
154  virtual void OnScroll(wxMouseEvent& event);
155  virtual void OnMiddleDown(wxMouseEvent& event);
156  virtual void OnMiddleUp(wxMouseEvent& event);
157  virtual void OnMouseMotion(wxMouseEvent& event);
158  virtual void OnKeyDown(wxKeyEvent& event);
159  virtual void OnLeftClickDown(wxMouseEvent& event);
160  virtual void OnPaint(wxPaintEvent& event);
161  virtual void OnPopupClick(wxCommandEvent& event);
162 
163  void SetViewport();
164  void UpdateStatusBar();
165 
166  wxGLContext* m_glContext = NULL;
167  wxStatusBar* m_statusBar = NULL;
168  Camera* m_camera = NULL;
169  wxTipWindow* m_tipWindow = NULL;
170  wxString m_name;
171 
172  WorkspaceMode m_mode = MODE_EDIT;
173 
174  std::vector<PowerElement*> m_elementList;
175  int m_elementNumber[NUM_ELEMENTS];
176 
177  std::vector<Text*> m_textList;
178 
179  wxFileName m_savedPath;
180 
181  wxRect2DDouble m_selectionRect;
182  wxPoint2DDouble m_startSelRect;
183 
184  PropertiesData* m_properties = NULL;
185 
186  std::vector<double> m_stabilityTimeVector;
187 
188  bool m_continuousCalc = false;
189  bool m_disconnectedElement = false;
190  bool m_justOpened = false;
191 };
192 
193 #endif // WORKSPACE_H
Element that shows power element informations in workspace.
Definition: Text.h:72
+
General and simulation data manager.
+
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition: Element.h:113
+
Calculate the power flow.
Definition: PowerFlow.h:33
+
Synchronous generator power element.
Class responsible for the correct visualization of the elements on screen.
Definition: Camera.h:30
+ - - -
Definition: Line.h:52
- -
Definition: Load.h:35
+ +
Class to store the elements in the clipboard.
+
Power line element.
Definition: Line.h:59
+
Calculates the electromechanical transient based on disturbances (e.g. system fault).
+
Loas shunt power element.
Definition: Load.h:42
This class is responsible to manage the charts generated in the transient electromechanical studies...
Definition: ChartView.h:40
- -
Definition: Fault.h:30
- - - +
Synchronous motor (synchronous compensator) power element.
Definition: SyncMotor.h:134
+
Calculate the fault of the system and update the elements data.
Definition: Fault.h:30
+
Induction motor power element.
Definition: IndMotor.h:40
+
Shunt capactior power element.
Definition: Capacitor.h:38
+
Inductor shunt power element.
Definition: Inductor.h:38
This class manages the graphical and power elements. It is responsible for handling the user&#39;s intera...
Definition: Workspace.h:81
- +
Two-winding transformer power element.
Definition: Transformer.h:78
diff --git a/docs/doxygen/html/annotated.html b/docs/doxygen/html/annotated.html index 6455b40..3949517 100644 --- a/docs/doxygen/html/annotated.html +++ b/docs/doxygen/html/annotated.html @@ -92,13 +92,13 @@ $(document).ready(function(){initNavTree('annotated.html','');});
[detail level 12]
- - + + - + @@ -116,18 +116,18 @@ $(document).ready(function(){initNavTree('annotated.html','');}); - - - - + + + + - + - + - + @@ -135,39 +135,39 @@ $(document).ready(function(){initNavTree('annotated.html','');}); - - + + - + - + - + - + - + - - - - - + + + + + @@ -175,33 +175,33 @@ $(document).ready(function(){initNavTree('annotated.html','');}); - + - + - + - + - + - + - + - + diff --git a/docs/doxygen/html/class_branch.html b/docs/doxygen/html/class_branch.html index 7fe4ac0..e69acbd 100644 --- a/docs/doxygen/html/class_branch.html +++ b/docs/doxygen/html/class_branch.html @@ -92,16 +92,21 @@ $(document).ready(function(){initNavTree('class_branch.html','');});
Branch Class Reference
+ +

Abstract class for branch power elements. + More...

+ +

#include <Branch.h>

Inheritance diagram for Branch:
-PowerElement -Element -Line -Transformer +PowerElement +Element +Line +Transformer
 CAboutFormForm to show some informations
 CAboutFormBase
 CBranch
 CBus
 CBranchAbstract class for branch power elements
 CBusNode for power elements. All others power elements are connected through this
 CBusElectricalData
 CBusFormForm to edit the bus power data
 CBusFormBase
 CCameraClass responsible for the correct visualization of the elements on screen
 CCapacitor
 CCapacitorShunt capactior power element
 CCapacitorElectricalData
 CChartViewThis class is responsible to manage the charts generated in the transient electromechanical studies
 CChartViewBase
 CControlSystemTestBase
 CDataReportForm that shows the results of power flow and fault calculations
 CDataReportBase
 CElectricCalculation
 CElectromechanical
 CElement
 CElementDataObject
 CElectricCalculationBase class of electric calculations, with general methods
 CElectromechanicalCalculates the electromechanical transient based on disturbances (e.g. system fault)
 CElementBase class of all elements of the program. This class is responsible for manage graphical and his data
 CElementDataObjectClass to store the elements in the clipboard
 CElementPlotData
 CElementsLists
 CExponentialGenerates an output following an exponential function. \( output = A\cdot e^{B\cdot input} \)
 CExponentialGenerates an output following an exponential function
 CExponentialFormForm to edit the exponential control data
 CExponentialFormBase
 CFault
 CFaultCalculate the fault of the system and update the elements data
 CFileHandingSave and opens the projects created on disk
 CGainProvide an output multiplying the input by a constant. \( output = K \cdot input \)
 CGainProvide an output multiplying the input by a constant
 CGainFormForm to edit the gain control data
 CGainFormBase
 CGeneralData
 CGeneralPropertiesFormBase
 CGeneratorStabFormForm to edit the synchronous generator data for electromechanical studies
 CGeneratorStabFormBase
 CGraphicalElement
 CIndMotor
 CGraphicalElementAbstract class for graphical elements shown with power elements in workspace
 CIndMotorInduction motor power element
 CIndMotorElectricalData
 CIndMotorFormForm to edit the induction motor power data
 CIndMotorFormBase
 CInductor
 CInductorInductor shunt power element
 CInductorElectricalData
 CIntegrationConstant
 CIntegrationConstantIntegration constants to calculate dynamic elements through trapezoidal integration method
 CIOControlProvides the communication with the power element
 CIOControlFormForm to edit the input/output control data
 CIOControlFormBase
 CLimiterLimits the input value by superior and inferior values
 CLimiterFormForm to edit the limit control data
 CLimiterFormBase
 CLine
 CLinePower line element
 CLineElectricalData
 CLineFormForm to edit the line power data
 CLineFormBase
 CLoad
 CLoadLoas shunt power element
 CLoadElectricalData
 CLoadFormForm to edit the load power data
 CLoadFormBase
 CMachines
 CMachinesAbstract class for rotary machines power elements
 CMainApp
 CMainFrameMain frame of the program. This class manage the ribbon menu and the notebook behavior
 CMainFrameBase
 CMultiplierMultiplies two inputs
 CNodeNode of a control element. This class manages the user interaction with the connection and control elements
 COpenGLColour
 CPlotData
 CPowerElement
 CPowerFlow
 CPropertiesData
 COpenGLColourClass to manage color of OpenGL
 CPlotDataThis class is responsible to manage the graphical data of electromechanical result to be plotted on chart viewer
 CPowerElementAbstract class of power elements
 CPowerFlowCalculate the power flow
 CPropertiesDataGeneral and simulation data manager
 CRateLimiterLimits the rising and/or falling rate.
 CRateLimiterFormForm to edit the rate limit control data
 CReactiveLimits
 CReactiveShuntElementFormForm to edit the reactive shunt element power data
 CReactiveShuntElementFormBase
 CShunt
 CShuntAbstract class for shunt power elements
 CSimulationData
 CSimulationsSettingsFormForm to edit the simulation data
 CSimulationsSettingsFormBase
 CSum
 CSumSum the all inputs (can choose the input signal)
 CSumFormForm to edit the sum control data
 CSumFormBase
 CSwitchingData
 CSwitchingDataSwitching data of power elements
 CSwitchingFormForm to edit the switching data of power elements for electromechanical transient studies
 CSwitchingFormBase
 CSyncGenerator
 CSyncGeneratorSynchronous generator power element
 CSyncGeneratorElectricalData
 CSyncMachineFormForm to edit the synchronous machine power data
 CSyncMachineFormBase
 CSyncMachineModelDataSynchronous machine data for different models
 CSyncMotor
 CSyncMotorSynchronous motor (synchronous compensator) power element
 CSyncMotorElectricalData
 CText
 CTextElement that shows power element informations in workspace
 CTextFormForm to edit the text graphical data
 CTextFormBase
 CTextGLDrawable
 CTextTexture
 CTransferFunction
 CTransferFunctionCalculates the time response by a frequency domain transfer function
 CTransferFunctionFormForm to edit the transfer function control data
 CTransferFunctionFormBase
 CTransformer
 CTransformerTwo-winding transformer power element
 CTransformerElectricalData
 CTransformerFormForm to edit the transformer power data
 CTransformerFormBase
@@ -508,8 +513,11 @@ Additional Inherited Members
 

Detailed Description

-
-

Definition at line 24 of file Branch.h.

+

Abstract class for branch power elements.

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+
Date
06/10/2017
+ +

Definition at line 31 of file Branch.h.

Member Function Documentation

◆ AddPoint()

@@ -547,7 +555,7 @@ Additional Inherited Members

Reimplemented in Line.

-

Definition at line 44 of file Branch.h.

+

Definition at line 51 of file Branch.h.

@@ -587,7 +595,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 30 of file Branch.h.

+

Definition at line 37 of file Branch.h.

@@ -638,7 +646,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 31 of file Branch.h.

+

Definition at line 38 of file Branch.h.

@@ -672,7 +680,7 @@ Additional Inherited Members

Reimplemented in Line.

-

Definition at line 39 of file Branch.h.

+

Definition at line 46 of file Branch.h.

@@ -713,7 +721,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 45 of file Branch.h.

+

Definition at line 52 of file Branch.h.

@@ -753,7 +761,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 40 of file Branch.h.

+

Definition at line 47 of file Branch.h.

@@ -793,7 +801,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 32 of file Branch.h.

+

Definition at line 39 of file Branch.h.

@@ -844,7 +852,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 34 of file Branch.h.

+

Definition at line 41 of file Branch.h.

@@ -884,7 +892,7 @@ Additional Inherited Members

Reimplemented in Line.

-

Definition at line 41 of file Branch.h.

+

Definition at line 48 of file Branch.h.

@@ -964,7 +972,7 @@ Additional Inherited Members

Reimplemented in Line.

-

Definition at line 42 of file Branch.h.

+

Definition at line 49 of file Branch.h.

@@ -1134,7 +1142,7 @@ Additional Inherited Members

Reimplemented in Transformer, and Line.

-

Definition at line 33 of file Branch.h.

+

Definition at line 40 of file Branch.h.

diff --git a/docs/doxygen/html/class_bus.html b/docs/doxygen/html/class_bus.html index 0c3edc9..c613d83 100644 --- a/docs/doxygen/html/class_bus.html +++ b/docs/doxygen/html/class_bus.html @@ -92,14 +92,19 @@ $(document).ready(function(){initNavTree('class_bus.html','');});
Bus Class Reference
+ +

Node for power elements. All others power elements are connected through this. + More...

+ +

#include <Bus.h>

Inheritance diagram for Bus:
-PowerElement -Element +PowerElement +Element
@@ -515,8 +520,11 @@ Additional Inherited Members
 

Detailed Description

-
-

Definition at line 62 of file Bus.h.

+

Node for power elements. All others power elements are connected through this.

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+
Date
06/10/2017
+ +

Definition at line 69 of file Bus.h.

Member Function Documentation

◆ AddParent()

@@ -555,7 +563,7 @@ Additional Inherited Members

Add a parent to the element. This method must be used on power elements that connect to a bus, so the parent must be a bus. The element basic points are calculated in this method, so apply this when the element is being inserted.

Parameters
- +
parentElement parent.
parentElement parent.
positionNode position in the parent.
@@ -563,7 +571,7 @@ Additional Inherited Members

Reimplemented from Element.

-

Definition at line 70 of file Bus.h.

+

Definition at line 77 of file Bus.h.

@@ -1019,7 +1027,7 @@ Additional Inherited Members
Parameters
- +
parentForm parent
elementElement that will be edited.
elementElement that will be edited.
diff --git a/docs/doxygen/html/class_capacitor.html b/docs/doxygen/html/class_capacitor.html index 12e844a..3ebe8fc 100644 --- a/docs/doxygen/html/class_capacitor.html +++ b/docs/doxygen/html/class_capacitor.html @@ -92,15 +92,20 @@ $(document).ready(function(){initNavTree('class_capacitor.html','');});
Capacitor Class Reference
+ +

Shunt capactior power element. + More...

+ +

#include <Capacitor.h>

Inheritance diagram for Capacitor:
-Shunt -PowerElement -Element +Shunt +PowerElement +Element
@@ -531,8 +536,11 @@ void 
DrawGround (wxPoi
 

Detailed Description

-
-

Definition at line 31 of file Capacitor.h.

+

Shunt capactior power element.

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+
Date
06/10/2017
+ +

Definition at line 38 of file Capacitor.h.

Member Function Documentation

◆ AddParent()

@@ -571,7 +579,7 @@ void DrawGround (wxPoi

Add a parent to the element. This method must be used on power elements that connect to a bus, so the parent must be a bus. The element basic points are calculated in this method, so apply this when the element is being inserted.

Parameters
- +
parentElement parent.
parentElement parent.
positionNode position in the parent.
@@ -887,7 +895,7 @@ void DrawGround (wxPoi
Parameters
- +
parentForm parent
elementElement that will be edited.
elementElement that will be edited.
diff --git a/docs/doxygen/html/class_connection_line.html b/docs/doxygen/html/class_connection_line.html index 1818ccc..131c5ce 100644 --- a/docs/doxygen/html/class_connection_line.html +++ b/docs/doxygen/html/class_connection_line.html @@ -105,7 +105,7 @@ Inheritance diagram for ConnectionLine:
ControlElement -Element +Element
diff --git a/docs/doxygen/html/class_constant.html b/docs/doxygen/html/class_constant.html index b14b5c9..433d2d7 100644 --- a/docs/doxygen/html/class_constant.html +++ b/docs/doxygen/html/class_constant.html @@ -104,7 +104,7 @@ Inheritance diagram for Constant: ControlElement -Element +Element
@@ -718,7 +718,7 @@ Additional Inherited Members
Parameters
- +
parentForm parent
elementElement that will be edited.
elementElement that will be edited.
diff --git a/docs/doxygen/html/class_control_element.html b/docs/doxygen/html/class_control_element.html index bf511f1..01f556a 100644 --- a/docs/doxygen/html/class_control_element.html +++ b/docs/doxygen/html/class_control_element.html @@ -100,17 +100,17 @@ Inheritance diagram for ControlElement:
-Element +Element ConnectionLine Constant -Exponential -Gain +Exponential +Gain IOControl Limiter Multiplier RateLimiter -Sum -TransferFunction +Sum +TransferFunction
diff --git a/docs/doxygen/html/class_electric_calculation.html b/docs/doxygen/html/class_electric_calculation.html index ccd0b4e..8ec98e6 100644 --- a/docs/doxygen/html/class_electric_calculation.html +++ b/docs/doxygen/html/class_electric_calculation.html @@ -93,6 +93,9 @@ $(document).ready(function(){initNavTree('class_electric_calculation.html','');}
+

Base class of electric calculations, with general methods. + More...

+

#include <ElectricCalculation.h>

Inheritance diagram for ElectricCalculation:
@@ -100,9 +103,9 @@ Inheritance diagram for ElectricCalculation:
-Electromechanical -Fault -PowerFlow +Electromechanical +Fault +PowerFlow
@@ -211,7 +214,8 @@ std::vector< Transformer * &g
 

Detailed Description

-
Author
Thales Lima Oliveira
+

Base class of electric calculations, with general methods.

+
Author
Thales Lima Oliveira
Date
09/01/2017

Definition at line 66 of file ElectricCalculation.h.

diff --git a/docs/doxygen/html/class_electromechanical.html b/docs/doxygen/html/class_electromechanical.html index 1cc28de..27527be 100644 --- a/docs/doxygen/html/class_electromechanical.html +++ b/docs/doxygen/html/class_electromechanical.html @@ -95,6 +95,9 @@ $(document).ready(function(){initNavTree('class_electromechanical.html','');});
+

Calculates the electromechanical transient based on disturbances (e.g. system fault). + More...

+

#include <Electromechanical.h>

Inheritance diagram for Electromechanical:
@@ -102,7 +105,7 @@ Inheritance diagram for Electromechanical:
-ElectricCalculation +ElectricCalculation
@@ -378,7 +381,8 @@ std::vector< Transformer * &g
 

Detailed Description

-
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+

Calculates the electromechanical transient based on disturbances (e.g. system fault).

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
Date
23/09/2017

Definition at line 51 of file Electromechanical.h.

diff --git a/docs/doxygen/html/class_element.html b/docs/doxygen/html/class_element.html index e22ec4d..2045891 100644 --- a/docs/doxygen/html/class_element.html +++ b/docs/doxygen/html/class_element.html @@ -94,6 +94,9 @@ $(document).ready(function(){initNavTree('class_element.html','');});
+

Base class of all elements of the program. This class is responsible for manage graphical and his data. + More...

+

#include <Element.h>

Inheritance diagram for Element:
@@ -102,23 +105,23 @@ Inheritance diagram for Element:
ControlElement -GraphicalElement -PowerElement +GraphicalElement +PowerElement ConnectionLine Constant -Exponential -Gain +Exponential +Gain IOControl Limiter Multiplier RateLimiter -Sum -TransferFunction -Text -Branch -Bus -Machines -Shunt +Sum +TransferFunction +Text +Branch +Bus +Machines +Shunt
@@ -425,7 +428,8 @@ bool 
m_online = true 

Detailed Description

-
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+

Base class of all elements of the program. This class is responsible for manage graphical and his data.

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
Date
19/09/2017

Definition at line 113 of file Element.h.

@@ -503,7 +507,7 @@ bool m_online = trueAdd a parent to the element. This method must be used on power elements that connect to a bus, so the parent must be a bus. The element basic points are calculated in this method, so apply this when the element is being inserted.

Parameters
- +
parentElement parent.
parentElement parent.
positionNode position in the parent.
@@ -542,7 +546,7 @@ bool m_online = trueAdd a parent to the element.

Parameters
- +
parentElement parent.
parentElement parent.
@@ -670,7 +674,7 @@ bool m_online = true
-

Implemented in Transformer, Text, Bus, Line, IOControl, Gain, Constant, TransferFunction, Capacitor, Inductor, Exponential, ConnectionLine, Limiter, Multiplier, RateLimiter, Machines, Sum, Branch, and Shunt.

+

Implemented in Transformer, Text, Bus, Line, IOControl, TransferFunction, Capacitor, Inductor, Constant, Gain, Machines, Sum, ConnectionLine, Exponential, Limiter, Multiplier, RateLimiter, Branch, and Shunt.

@@ -778,7 +782,7 @@ bool m_online = true -

Reimplemented in Transformer, Bus, Line, IOControl, Load, Gain, Constant, TransferFunction, Capacitor, Inductor, Exponential, ConnectionLine, Limiter, Multiplier, RateLimiter, Machines, Sum, and Branch.

+

Reimplemented in Transformer, Bus, Line, Load, IOControl, TransferFunction, Capacitor, Inductor, Machines, Constant, Gain, Sum, Branch, ConnectionLine, Exponential, Limiter, Multiplier, and RateLimiter.

Definition at line 302 of file Element.h.

@@ -882,7 +886,7 @@ bool m_online = trueDraw line.

Parameters
- +
pointsLine vertices.
pointsLine vertices.
modeOpenGl primitive.
@@ -1323,7 +1327,7 @@ bool m_online = trueGet a the element copy.

Returns
Copy of the element.
-

Reimplemented in SyncGenerator, SyncMotor, Transformer, Text, Bus, RateLimiter, Line, IOControl, ConnectionLine, TransferFunction, Gain, Exponential, Constant, Limiter, Multiplier, Sum, Load, IndMotor, Capacitor, and Inductor.

+

Reimplemented in SyncGenerator, SyncMotor, Transformer, Text, TransferFunction, Bus, Line, RateLimiter, IOControl, Gain, ConnectionLine, Exponential, Sum, Constant, Limiter, Load, Multiplier, IndMotor, Capacitor, and Inductor.

Definition at line 262 of file Element.h.

@@ -1353,7 +1357,7 @@ bool m_online = true

Get the element height.

-
Returns
Element height.
+
Returns
Element height.

Definition at line 197 of file Element.h.

@@ -1383,7 +1387,7 @@ bool m_online = true

Get the element ID.

-
Returns
Element ID.
+
Returns
Element ID.

Definition at line 272 of file Element.h.

@@ -1473,7 +1477,7 @@ bool m_online = true

Get the element position.

-
Returns
Element position.
+
Returns
Element position.

Definition at line 187 of file Element.h.

@@ -1503,7 +1507,7 @@ bool m_online = true

Get the element rectangle.

-
Returns
Element rectangle.
+
Returns
Element rectangle.

Definition at line 182 of file Element.h.

@@ -1595,7 +1599,7 @@ bool m_online = true

Get the element width.

-
Returns
Element width.
+
Returns
Element width.

Definition at line 207 of file Element.h.

@@ -1633,7 +1637,7 @@ bool m_online = true
-

Implemented in Transformer, Text, Bus, Line, IOControl, Gain, Constant, TransferFunction, Capacitor, Inductor, Exponential, Branch, ConnectionLine, Limiter, Multiplier, RateLimiter, Machines, Sum, and Shunt.

+

Implemented in Transformer, Text, Bus, Line, IOControl, TransferFunction, Capacitor, Inductor, Branch, Machines, Constant, Gain, Sum, ConnectionLine, Exponential, Limiter, Multiplier, RateLimiter, and Shunt.

@@ -1850,7 +1854,7 @@ bool m_online = true -

Reimplemented in ControlElement, Transformer, Line, Gain, ConnectionLine, Machines, Branch, and Shunt.

+

Reimplemented in ControlElement, Transformer, Line, Gain, Machines, ConnectionLine, Branch, and Shunt.

Definition at line 123 of file Element.cpp.

@@ -2137,7 +2141,7 @@ bool m_online = true -

Reimplemented in Machines, ConnectionLine, Branch, and Shunt.

+

Reimplemented in Machines, Branch, Shunt, and ConnectionLine.

Definition at line 359 of file Element.h.

@@ -2269,7 +2273,7 @@ bool m_online = true -

Reimplemented in Transformer, Text, Bus, IOControl, Gain, Machines, Constant, Load, TransferFunction, Capacitor, Exponential, Inductor, Limiter, Multiplier, RateLimiter, and Sum.

+

Reimplemented in Transformer, Text, Bus, IOControl, Machines, Load, TransferFunction, Capacitor, Inductor, Constant, Gain, Sum, Exponential, Limiter, Multiplier, and RateLimiter.

Definition at line 307 of file Element.h.

@@ -2610,7 +2614,7 @@ bool m_online = trueSet the element ID.

Parameters
- +
idElement ID.
idElement ID.
@@ -2862,13 +2866,13 @@ bool m_online = true
Parameters
- +
parentForm parent
elementElement that will be edited.
elementElement that will be edited.
Returns
True if the form is shown, false otherwise.
-

Reimplemented in SyncGenerator, SyncMotor, Transformer, Bus, Line, IOControl, Load, Capacitor, Inductor, Gain, Constant, IndMotor, TransferFunction, Exponential, Limiter, Multiplier, RateLimiter, and Sum.

+

Reimplemented in SyncGenerator, SyncMotor, Transformer, Bus, Line, Load, Capacitor, Inductor, IOControl, IndMotor, TransferFunction, Constant, Gain, Sum, Exponential, Limiter, Multiplier, and RateLimiter.

Definition at line 534 of file Element.h.

@@ -2942,7 +2946,7 @@ bool m_online = true -

Reimplemented in ControlElement, Transformer, Line, ConnectionLine, Machines, Shunt, and Branch.

+

Reimplemented in Transformer, ControlElement, Line, Machines, ConnectionLine, Shunt, and Branch.

Definition at line 117 of file Element.cpp.

diff --git a/docs/doxygen/html/class_element_data_object.html b/docs/doxygen/html/class_element_data_object.html index f8fc6b8..0acfd3b 100644 --- a/docs/doxygen/html/class_element_data_object.html +++ b/docs/doxygen/html/class_element_data_object.html @@ -92,6 +92,11 @@ $(document).ready(function(){initNavTree('class_element_data_object.html','');})
ElementDataObject Class Reference
+ +

Class to store the elements in the clipboard. + More...

+ +

#include <ElementDataObject.h>

Inheritance diagram for ElementDataObject:
@@ -126,8 +131,11 @@ Protected Attributes  

Detailed Description

-
-

Definition at line 29 of file ElementDataObject.h.

+

Class to store the elements in the clipboard.

+
Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
+
Date
06/10/2017
+ +

Definition at line 36 of file ElementDataObject.h.


The documentation for this class was generated from the following files:
  • Project/ElementDataObject.h
  • Project/ElementDataObject.cpp
  • diff --git a/docs/doxygen/html/class_element_plot_data.html b/docs/doxygen/html/class_element_plot_data.html index 49e37fa..cda9cc2 100644 --- a/docs/doxygen/html/class_element_plot_data.html +++ b/docs/doxygen/html/class_element_plot_data.html @@ -195,7 +195,7 @@ std::vector< PlotData * >

    Detailed Description

    -

    Definition at line 56 of file ElementPlotData.h.

    +

    Definition at line 64 of file ElementPlotData.h.


    The documentation for this class was generated from the following files:
    • Project/ElementPlotData.h
    • Project/ElementPlotData.cpp
    • diff --git a/docs/doxygen/html/class_exponential-members.html b/docs/doxygen/html/class_exponential-members.html index dea5915..32393c9 100644 --- a/docs/doxygen/html/class_exponential-members.html +++ b/docs/doxygen/html/class_exponential-members.html @@ -198,7 +198,7 @@ $(document).ready(function(){initNavTree('class_exponential.html','');}); SetWidth(double width)Elementinline ShowForm(wxWindow *parent, Element *element)Exponentialvirtual ShowPickbox(bool showPickbox=true)Elementinline - Solve(double input, double timeStep) (defined in Exponential)Exponentialvirtual + Solve(double input, double timeStep)Exponentialvirtual StartMove(wxPoint2DDouble position)ControlElementvirtual StringFromDouble(double value, int minDecimal=1)Elementstatic UpdateNodes()Elementinlinevirtual diff --git a/docs/doxygen/html/class_exponential.html b/docs/doxygen/html/class_exponential.html index c5a7707..f7b9b7b 100644 --- a/docs/doxygen/html/class_exponential.html +++ b/docs/doxygen/html/class_exponential.html @@ -93,7 +93,7 @@ $(document).ready(function(){initNavTree('class_exponential.html','');});
-

Generates an output following an exponential function. \( output = A\cdot e^{B\cdot input} \). +

Generates an output following an exponential function. More...

#include <Exponential.h>

@@ -104,7 +104,7 @@ Inheritance diagram for Exponential:
ControlElement -Element +Element
@@ -137,8 +137,8 @@ virtual void  - + + @@ -476,11 +476,11 @@ Additional Inherited Members
GetValues
virtual void SetValues (double aValue, double bValue)
 
-virtual bool Solve (double input, double timeStep)
virtual bool Solve (double input, double timeStep)
 Calculates the exponential. More...
 
virtual ElementGetCopy ()
 Get a the element copy. More...
 

Detailed Description

-

Generates an output following an exponential function. \( output = A\cdot e^{B\cdot input} \).

+

Generates an output following an exponential function.

Author
Thales Lima Oliveira thale.nosp@m.s@uf.nosp@m.u.br
Date
05/10/2017
-

Definition at line 33 of file Exponential.h.

+

Definition at line 32 of file Exponential.h.

Member Function Documentation

◆ Contains()

@@ -516,7 +516,7 @@ Additional Inherited Members

Implements Element.

-

Definition at line 40 of file Exponential.h.

+

Definition at line 39 of file Exponential.h.

@@ -635,7 +635,7 @@ Additional Inherited Members

Implements Element.

-

Definition at line 41 of file Exponential.h.

+

Definition at line 40 of file Exponential.h.

@@ -715,7 +715,7 @@ Additional Inherited Members
Parameters
- +
parentForm parent
elementElement that will be edited.
elementElement that will be edited.
@@ -725,6 +725,56 @@ Additional Inherited Members

Definition at line 73 of file Exponential.cpp.

+ + + +

◆ Solve()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
bool Exponential::Solve (double input,
double timeStep 
)
+
+virtual
+
+ +

Calculates the exponential.

+
\( output = A\cdot e^{B\cdot input} \)
Parameters
+ + + +
inputInput value.
timeStepTime step.
+
+
+
Returns
Aways true.
+ +

Reimplemented from ControlElement.

+ +

Definition at line 132 of file Exponential.cpp.

+

The documentation for this class was generated from the following files: