46HMPlane::HMPlane(
const double& width,
const double& height,
const double limits[2]) : m_width(width), m_height(height)
49 for (
auto accHeight = 0; accHeight <= m_height + m_meshSize; accHeight += m_meshSize) {
50 std::vector<BufferMeshCoords*> line;
51 for (
auto accWidth = 0; accWidth <= m_width + m_meshSize; accWidth += m_meshSize) {
56 line.emplace_back(bmc);
58 if (accHeight < 0.1f) m_meshTickX++;
61 m_coords.emplace_back(line);
63 m_coordsT.resize(m_coords[0].size());
64 for (
auto& line : m_coordsT) line.resize(m_coords.size());
65 for (
size_t i = 0; i < m_coords.size(); ++i) {
66 const auto& line = m_coords[i];
67 for (
size_t j = 0; j < line.size(); ++j) {
68 m_coordsT[j][i] = m_coords[i][j];
72 m_limits[0] = limits[0];
73 m_limits[1] = limits[1];
93 for (
const auto& line : m_coords) {
94 for (
auto* bmv : line) {
124void HMPlane::DrawDC(wxGraphicsContext* gc)
const
126 if (m_isClear)
return;
127 gc->SetPen(*wxTRANSPARENT_PEN);
128 for (
const auto& line : m_coords) {
129 wxGraphicsGradientStops gStops;
130 gStops.Add(wxColor(255, 255, 255), 0);
132 gStops.Add(VoltToColour(coords->z), coords->x / (m_width));
134 wxGraphicsBrush brush = gc->CreateLinearGradientBrush(0, line[0]->y, m_width, line[0]->y, gStops);
136 gc->DrawRectangle(0, line[0]->y, m_width, m_meshSize);
139 for (
const auto& line : m_coordsT) {
140 wxGraphicsGradientStops gStops;
141 gStops.Add(wxColor(255, 255, 255), 0);
143 gStops.Add(VoltToColour(coords->z), coords->y / (m_height));
145 wxGraphicsBrush brush = gc->CreateLinearGradientBrush(line[0]->x, 0, line[0]->x, m_height, gStops);
147 gc->DrawRectangle(line[0]->x, 0, m_meshSize, m_height);
151void HMPlane::DrawDC(wxDC& dc)
const
153 if (m_isClear)
return;
154 dc.SetPen(*wxTRANSPARENT_PEN);
186 for (
const auto& line : m_coords)
188 int y = wxRound(line[0]->y);
195 std::vector<Stop> stops;
197 stops.push_back({ 0.0, wxColour(255,255,255) });
201 double pos = coords->x / m_width;
202 stops.push_back({ pos, VoltToColour(coords->z) });
205 auto ColorAt = [&](
double t) -> wxColour
207 if (t <= stops.front().pos)
208 return stops.front().color;
210 if (t >= stops.back().pos)
211 return stops.back().color;
213 for (
size_t i = 0; i < stops.size() - 1; ++i)
215 if (t >= stops[i].pos && t <= stops[i + 1].pos)
219 (stops[i + 1].pos - stops[i].pos);
221 const wxColour& c1 = stops[i].color;
222 const wxColour& c2 = stops[i + 1].color;
225 c1.Red() + localT * (c2.Red() - c1.Red()),
226 c1.Green() + localT * (c2.Green() - c1.Green()),
227 c1.Blue() + localT * (c2.Blue() - c1.Blue())
232 return stops.back().color;
235 for (
size_t i = 0; i < stops.size() - 1; ++i)
237 int x1 = wxRound(stops[i].pos * m_width);
238 int x2 = wxRound(stops[i + 1].pos * m_width);
243 double t1 = stops[i].pos;
244 double t2 = stops[i + 1].pos;
246 wxColour c1 = ColorAt(t1);
247 wxColour c2 = ColorAt(t2);
249 wxRect rect(x1, y, x2 - x1, m_meshSize);
251 dc.GradientFillLinear(rect, c1, c2, wxEAST);
283void HMPlane::DrawLabelDC(wxGraphicsContext* gc)
const
285 wxGraphicsMatrix identityMatrix = gc->GetTransform();
286 identityMatrix.Set();
288 gc->SetTransform(identityMatrix);
289 gc->SetPen(*wxBLACK_PEN);
290 wxGraphicsGradientStops gStops;
291 gStops.Add(VoltToColour(-1.0, 210), 0.0);
292 gStops.Add(VoltToColour(-0.5, 210), 0.25);
293 gStops.Add(VoltToColour(0.0, 210), 0.5);
294 gStops.Add(VoltToColour(0.5, 210), 0.75);
295 gStops.Add(VoltToColour(1.0, 210), 1.0);
296 wxGraphicsBrush brush = gc->CreateLinearGradientBrush(30, m_height - 45, 330, m_height - 45, gStops);
299 gc->DrawRectangle(30, m_height - 45, 300, 30);
301 wxPoint2DDouble lines[10];
302 lines[0] = wxPoint2DDouble(30, m_height - 50);
303 lines[1] = wxPoint2DDouble(30, m_height - 40);
304 lines[2] = wxPoint2DDouble(105, m_height - 50);
305 lines[3] = wxPoint2DDouble(105, m_height - 40);
306 lines[4] = wxPoint2DDouble(180, m_height - 50);
307 lines[5] = wxPoint2DDouble(180, m_height - 40);
308 lines[6] = wxPoint2DDouble(255, m_height - 50);
309 lines[7] = wxPoint2DDouble(255, m_height - 40);
310 lines[8] = wxPoint2DDouble(330, m_height - 50);
311 lines[9] = wxPoint2DDouble(330, m_height - 40);
313 for (
size_t i = 0; i < 10; i += 2) {
314 gc->StrokeLine(lines[i].m_x, lines[i].m_y, lines[i + 1].m_x, lines[i + 1].m_y);
317 gc->SetFont(gc->CreateFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)));
318 gc->DrawText(_(
"Voltage (p.u.)"), 30, m_height - 15);
319 wxString voltageText =
"";
320 double textWidth, textHeight;
321 voltageText = wxString::Format(
"%.3f", m_limits[0]);
322 gc->GetTextExtent(voltageText, &textWidth, &textHeight);
323 gc->DrawText(voltageText, 330 - textWidth / 2, m_height - 65);
324 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.75 + m_limits[1] * 0.25);
325 gc->GetTextExtent(voltageText, &textWidth, &textHeight);
326 gc->DrawText(voltageText, 255 - textWidth / 2, m_height - 65);
327 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.5 + m_limits[1] * 0.5);
328 gc->GetTextExtent(voltageText, &textWidth, &textHeight);
329 gc->DrawText(voltageText, 180 - textWidth / 2, m_height - 65);
330 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.25 + m_limits[1] * 0.75);
331 gc->GetTextExtent(voltageText, &textWidth, &textHeight);
332 gc->DrawText(voltageText, 105 - textWidth / 2, m_height - 65);
333 voltageText = wxString::Format(
"%.3f", m_limits[1]);
334 gc->GetTextExtent(voltageText, &textWidth, &textHeight);
335 gc->DrawText(voltageText, 30 - textWidth / 2, m_height - 65);
340void HMPlane::DrawLabelDC(wxDC& dc)
const
342 dc.SetUserScale(1.0, 1.0);
343 dc.SetDeviceOrigin(0, 0);
345 dc.SetPen(*wxBLACK_PEN);
347 int yStart = m_height - 45;
356 std::vector<Stop> stops = {
357 {0.00, VoltToColour(-1.0, 210)},
358 {0.25, VoltToColour(-0.5, 210)},
359 {0.50, VoltToColour(0.0, 210)},
360 {0.75, VoltToColour(0.5, 210)},
361 {1.00, VoltToColour(1.0, 210)}
364 auto ColorAt = [&](
double t) -> wxColour
366 for (
size_t i = 0; i < stops.size() - 1; ++i)
368 if (t >= stops[i].pos && t <= stops[i + 1].pos)
372 (stops[i + 1].pos - stops[i].pos);
374 const wxColour& c1 = stops[i].color;
375 const wxColour& c2 = stops[i + 1].color;
378 c1.Red() + localT * (c2.Red() - c1.Red()),
379 c1.Green() + localT * (c2.Green() - c1.Green()),
380 c1.Blue() + localT * (c2.Blue() - c1.Blue())
384 return stops.back().color;
387 for (
int x = 0; x < width; ++x)
389 double t = (double)x / width;
391 wxColour c = ColorAt(t);
394 dc.DrawLine(xStart + x,
400 dc.SetPen(*wxBLACK_PEN);
401 dc.SetBrush(*wxTRANSPARENT_BRUSH);
402 dc.DrawRectangle(xStart, yStart, width, height);
403 wxPoint2DDouble lines[10];
404 lines[0] = wxPoint2DDouble(30, m_height - 50);
405 lines[1] = wxPoint2DDouble(30, m_height - 40);
406 lines[2] = wxPoint2DDouble(105, m_height - 50);
407 lines[3] = wxPoint2DDouble(105, m_height - 40);
408 lines[4] = wxPoint2DDouble(180, m_height - 50);
409 lines[5] = wxPoint2DDouble(180, m_height - 40);
410 lines[6] = wxPoint2DDouble(255, m_height - 50);
411 lines[7] = wxPoint2DDouble(255, m_height - 40);
412 lines[8] = wxPoint2DDouble(330, m_height - 50);
413 lines[9] = wxPoint2DDouble(330, m_height - 40);
415 for (
size_t i = 0; i < 10; i += 2) {
416 dc.DrawLine(lines[i].m_x, lines[i].m_y, lines[i + 1].m_x, lines[i + 1].m_y);
419 dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
420 dc.DrawText(_(
"Voltage (p.u.)"), 30, m_height - 15);
421 wxString voltageText =
"";
422 int textWidth, textHeight;
423 voltageText = wxString::Format(
"%.3f", m_limits[0]);
424 dc.GetTextExtent(voltageText, &textWidth, &textHeight);
425 dc.DrawText(voltageText, 330 - textWidth / 2, m_height - 65);
426 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.75 + m_limits[1] * 0.25);
427 dc.GetTextExtent(voltageText, &textWidth, &textHeight);
428 dc.DrawText(voltageText, 255 - textWidth / 2, m_height - 65);
429 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.5 + m_limits[1] * 0.5);
430 dc.GetTextExtent(voltageText, &textWidth, &textHeight);
431 dc.DrawText(voltageText, 180 - textWidth / 2, m_height - 65);
432 voltageText = wxString::Format(
"%.3f", m_limits[0] * 0.25 + m_limits[1] * 0.75);
433 dc.GetTextExtent(voltageText, &textWidth, &textHeight);
434 dc.DrawText(voltageText, 105 - textWidth / 2, m_height - 65);
435 voltageText = wxString::Format(
"%.3f", m_limits[1]);
436 dc.GetTextExtent(voltageText, &textWidth, &textHeight);
437 dc.DrawText(voltageText, 30 - textWidth / 2, m_height - 65);
440void HMPlane::SetLabelLimits(
const double& min,
const double& max)
452void HMPlane::SetRectSlope(
const wxRect2DDouble& rect,
const double& angle,
const double& depth)
454 for (
const auto& line : m_coords) {
455 for (
auto* coord : line) {
456 wxPoint2DDouble pt(coord->x, coord->y);
457 if (std::abs(angle) > 0.01) {
459 wxPoint2DDouble rotPt;
460 rotPt.m_x = cos(angle) * (pt.m_x - rect.GetCentre().m_x) + sin(angle) * (pt.m_y - rect.GetCentre().m_y) + rect.GetCentre().m_x;
461 rotPt.m_y = sin(angle) * (pt.m_x - rect.GetCentre().m_x) - cos(angle) * (pt.m_y - rect.GetCentre().m_y) + rect.GetCentre().m_y;
465 if (rect.Contains(pt)) {
467 if (coord->z > 1.0f) coord->z = 1.0f;
468 if (coord->z < -1.0f) coord->z = -1.0f;
478void HMPlane::Resize(
const double& width,
const double& height)
486 for (
const auto& line : m_coords) {
487 for (
auto* bmv : line) {
494 for (
auto accHeight = 0; accHeight < m_height + m_meshSize; accHeight += m_meshSize) {
495 std::vector<BufferMeshCoords*> line;
496 for (
auto accWidth = 0; accWidth < m_width + m_meshSize; accWidth += m_meshSize) {
501 line.emplace_back(bmc);
503 if (accHeight < 0.1f) m_meshTickX++;
506 m_coords.emplace_back(line);
522void HMPlane::ResizeDC(
const double& width,
const double& height)
529 for (
const auto& line : m_coords) {
530 for (
auto* bmv : line) {
538 for (
auto accHeight = 0; accHeight < m_height + m_meshSize; accHeight += m_meshSize) {
539 std::vector<BufferMeshCoords*> line;
540 for (
auto accWidth = 0; accWidth < m_width + m_meshSize; accWidth += m_meshSize) {
545 line.emplace_back(bmc);
547 if (accHeight < 0.1f) m_meshTickX++;
550 m_coords.emplace_back(line);
552 m_coordsT.resize(m_coords[0].size());
553 for (
auto& line : m_coordsT) line.resize(m_coords.size());
554 for (
size_t i = 0; i < m_coords.size(); ++i) {
555 const auto& line = m_coords[i];
556 for (
size_t j = 0; j < line.size(); ++j) {
557 m_coordsT[j][i] = m_coords[i][j];
564void HMPlane::SmoothPlane(
const unsigned int& iterations)
566 const int maxTickX =
static_cast<int>(m_meshTickX);
567 const int maxTickY =
static_cast<int>(m_meshTickY);
569 std::vector< std::vector<BufferMeshCoords> > tmpCoords;
570 for (
const auto& line : m_coords) {
571 std::vector<BufferMeshCoords> tmpCoordsLine;
572 for (
auto* bmv : line) {
573 tmpCoordsLine.push_back(*bmv);
575 tmpCoords.push_back(tmpCoordsLine);
599 float gaussianKernel[5][5] =
601 {1.0f / 256.0f, 4.0f / 256.0f, 6 / 256.0f, 4.0f / 256, 1.0f / 256.0f},
602 {4.0f / 256.0f, 16.0f / 256.0f, 24 / 256.0f, 16.0f / 256, 4.0f / 256.0f},
603 {6.0f / 256.0f, 24.0f / 256.0f, 36 / 256.0f, 24.0f / 256, 6.0f / 256.0f},
604 {4.0f / 256.0f, 16.0f / 256.0f, 24 / 256.0f, 16.0f / 256, 4.0f / 256.0f},
605 {1.0f / 256.0f, 4.0f / 256.0f, 6 / 256.0f, 4.0f / 256, 1.0f / 256.0f}
608 for (
size_t it = 0; it < iterations; ++it) {
609 for (
size_t i = 0; i < m_meshTickY; ++i) {
610 for (
size_t j = 0; j < m_meshTickX; ++j) {
614 for (
size_t ii = i - 2; ii <= i + 2; ++ii) {
615 for (
size_t jj = j - 2; jj <= j + 2; ++jj) {
617 if (ii >= 0 && ii < m_meshTickY && jj >= 0 && jj < m_meshTickX) {
618 value += tmpCoords[ii][jj].z * gaussianKernel[ii - i + 2][jj - j + 2];
622 m_coords[i][j]->z = value;
625 if (it < iterations - 1) {
626 for (
size_t i = 0; i < m_meshTickY; ++i) {
627 for (
size_t j = 0; j < m_meshTickX; ++j) {
628 tmpCoords[i][j].z = m_coords[i][j]->z;
641 for (
const auto& line : m_coords) {
642 for (
auto* bmv : line) {
651void HMPlane::FillCoordsBuffer()
653 m_bufferCoords.clear();
655 for (
const auto& line : m_coords) {
656 for (
auto* bmv : line) {
657 m_bufferCoords.push_back(bmv->x);
658 m_bufferCoords.push_back(bmv->y);
659 m_bufferCoords.push_back(bmv->z);
747wxColor HMPlane::VoltToColour(
double volt,
int alpha)
const
755 int red = 255, green = 255, blue = 255;
757 red = -100 * volt - 50;
758 green = 200 * volt + 300;
761 else if (volt > -0.5 && volt < 0) {
762 red = 510 * volt + 255;
763 green = 110 * volt + 255;
766 else if (volt >= 0.0 && volt < 0.5) {
768 green = -110 * volt + 255;
769 blue = -510 * volt + 255;
771 else if (volt >= 0.5) {
773 green = -200 * volt + 300;
774 blue = 100 * volt - 50;
776 return wxColor(red, green, blue, alpha);