OpenCPN Partial API docs
Loading...
Searching...
No Matches
s57_ocpn_utils.cpp
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * Copyright (C) 2024 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 **************************************************************************/
20
23#include "s57_ocpn_utils.h"
24
25#include "chartimg.h"
26#include "chcanv.h"
27#include "ocpn_plugin.h"
28#include "pluginmanager.h"
29#include "Quilt.h"
30#include "s52plib.h"
31
32extern PlugInManager *g_pi_manager; // FIXME: MOve to header
33extern s52plib *ps52plib; // FIXME: MOve to header
34
35bool s57_GetVisibleLightSectors(ChartCanvas *cc, double lat, double lon,
36 ViewPort &viewport,
37 std::vector<s57Sector_t> &sectorlegs) {
38 if (!cc) return false;
39
40 static float lastLat, lastLon;
41
42 if (!ps52plib) return false;
43
44 ChartPlugInWrapper *target_plugin_chart = NULL;
45 s57chart *Chs57 = NULL;
46
47 // Find the chart that is currently shown at the given lat/lon
48 wxPoint calcPoint = viewport.GetPixFromLL(lat, lon);
49 ChartBase *target_chart;
50 if (cc->m_singleChart &&
51 (cc->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
52 target_chart = cc->m_singleChart;
53 else if (viewport.b_quilt)
54 target_chart = cc->m_pQuilt->GetChartAtPix(viewport, calcPoint);
55 else
56 target_chart = NULL;
57
58 if (target_chart) {
59 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
60 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
61 target_plugin_chart = dynamic_cast<ChartPlugInWrapper *>(target_chart);
62 else
63 Chs57 = dynamic_cast<s57chart *>(target_chart);
64 }
65
66 bool newSectorsNeedDrawing = false;
67
68 if (target_plugin_chart || Chs57) {
69 ListOfObjRazRules *rule_list = NULL;
70 ListOfPI_S57Obj *pi_rule_list = NULL;
71
72 // Go get the array of all objects at the cursor lat/lon
73 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
74
75 if (Chs57)
76 rule_list =
77 Chs57->GetLightsObjRuleListVisibleAtLatLon(lat, lon, &viewport);
78 else if (target_plugin_chart)
79 pi_rule_list = g_pi_manager->GetLightsObjRuleListVisibleAtLatLon(
80 target_plugin_chart, lat, lon, viewport);
81
82 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
83 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
84
85 if (rule_list) {
86 rule_list->Clear();
87 delete rule_list;
88 }
89
90 if (pi_rule_list) {
91 pi_rule_list->Clear();
92 delete pi_rule_list;
93 }
94 }
95
96 return newSectorsNeedDrawing;
97}
98
99bool s57_ProcessExtendedLightSectors(ChartCanvas *cc,
100 ChartPlugInWrapper *target_plugin_chart,
101 s57chart *Chs57,
102 ListOfObjRazRules *rule_list,
103 ListOfPI_S57Obj *pi_rule_list,
104 std::vector<s57Sector_t> &sectorlegs) {
105 bool newSectorsNeedDrawing = false;
106
107 bool bhas_red_green = false;
108 bool bleading_attribute = false;
109
110 int opacity = 100;
111 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
112 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
113
114 int yOpacity = (float)opacity *
115 1.3; // Matched perception of white/yellow with red/green
116
117 if (target_plugin_chart || Chs57) {
118 sectorlegs.clear();
119
120 wxPoint2DDouble objPos;
121
122 char *curr_att = NULL;
123 int n_attr = 0;
124 wxArrayOfS57attVal *attValArray = NULL;
125
126 ListOfObjRazRules::Node *snode = NULL;
127 ListOfPI_S57Obj::Node *pnode = NULL;
128
129 if (Chs57 && rule_list)
130 snode = rule_list->GetLast();
131 else if (target_plugin_chart && pi_rule_list)
132 pnode = pi_rule_list->GetLast();
133
134 while (1) {
135 wxPoint2DDouble lightPosD(0, 0);
136 bool is_light = false;
137 if (Chs57) {
138 if (!snode) break;
139
140 ObjRazRules *current = snode->GetData();
141 S57Obj *light = current->obj;
142 if (!strcmp(light->FeatureName, "LIGHTS")) {
143 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
144 curr_att = light->att_array;
145 n_attr = light->n_attr;
146 attValArray = light->attVal;
147 is_light = true;
148 }
149 } else if (target_plugin_chart) {
150 if (!pnode) break;
151 PI_S57Obj *light = pnode->GetData();
152 if (!strcmp(light->FeatureName, "LIGHTS")) {
153 objPos = wxPoint2DDouble(light->m_lat, light->m_lon);
154 curr_att = light->att_array;
155 n_attr = light->n_attr;
156 attValArray = light->attVal;
157 is_light = true;
158 }
159 }
160
161 // Ready to go
162 int attrCounter;
163 double sectr1 = -1;
164 double sectr2 = -1;
165 double valnmr = -1;
166 wxString curAttrName;
167 wxColor color;
168
169 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
170
171 if (is_light && (lightPosD == objPos)) {
172 if (curr_att) {
173 bool bviz = true;
174
175 attrCounter = 0;
176 int noAttr = 0;
177 s57Sector_t sector;
178
179 bleading_attribute = false;
180
181 while (attrCounter < n_attr) {
182 curAttrName = wxString(curr_att, wxConvUTF8, 6);
183 noAttr++;
184
185 S57attVal *pAttrVal = NULL;
186 if (attValArray) {
187 if (Chs57)
188 pAttrVal = attValArray->Item(attrCounter);
189 else if (target_plugin_chart)
190 pAttrVal = attValArray->Item(attrCounter);
191 }
192
193 wxString value =
194 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
195
196 if (curAttrName == _T("LITVIS")) {
197 if (value.StartsWith(_T("obsc"))) bviz = false;
198 }
199 if (curAttrName == _T("SECTR1")) value.ToDouble(&sectr1);
200 if (curAttrName == _T("SECTR2")) value.ToDouble(&sectr2);
201 if (curAttrName == _T("VALNMR")) value.ToDouble(&valnmr);
202 if (curAttrName == _T("COLOUR")) {
203 if (value == _T("red(3)")) {
204 color = wxColor(255, 0, 0, opacity);
205 sector.iswhite = false;
206 bhas_red_green = true;
207 }
208
209 if (value == _T("green(4)")) {
210 color = wxColor(0, 255, 0, opacity);
211 sector.iswhite = false;
212 bhas_red_green = true;
213 }
214 }
215
216 if (curAttrName == _T("EXCLIT")) {
217 if (value.Find(_T("(3)"))) valnmr = 1.0; // Fog lights.
218 }
219
220 if (curAttrName == _T("CATLIT")) {
221 if (value.Upper().StartsWith(_T("DIRECT")) ||
222 value.Upper().StartsWith(_T("LEAD")))
223 bleading_attribute = true;
224 }
225
226 attrCounter++;
227 curr_att += 6;
228 }
229
230 if ((sectr1 >= 0) && (sectr2 >= 0)) {
231 if (sectr1 > sectr2) { // normalize
232 sectr2 += 360.0;
233 }
234
235 sector.pos.m_x = objPos.m_y; // lon
236 sector.pos.m_y = objPos.m_x;
237
238 sector.range =
239 (valnmr > 0.0) ? valnmr : 2.5; // Short default range.
240 sector.sector1 = sectr1;
241 sector.sector2 = sectr2;
242
243 if (!color.IsOk()) {
244 color = wxColor(255, 255, 0, yOpacity);
245 sector.iswhite = true;
246 }
247 sector.color = color;
248 sector.isleading = false; // tentative judgment, check below
249
250 if (bleading_attribute) sector.isleading = true;
251
252 bool newsector = true;
253 for (unsigned int i = 0; i < sectorlegs.size(); i++) {
254 if (sectorlegs[i].pos == sector.pos &&
255 sectorlegs[i].sector1 == sector.sector1 &&
256 sectorlegs[i].sector2 == sector.sector2) {
257 newsector = false;
258 // In the case of duplicate sectors, choose the instance with
259 // largest range. This applies to the case where day and night
260 // VALNMR are different, and so makes the vector result
261 // independent of the order of day/night light features.
262 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
263 }
264 }
265
266 if (!bviz) newsector = false;
267
268 if ((sector.sector2 == 360) && (sector.sector1 == 0)) // FS#1437
269 newsector = false;
270
271 if (newsector) {
272 sectorlegs.push_back(sector);
273 newSectorsNeedDrawing = true;
274 }
275 }
276 }
277 }
278
279 if (Chs57)
280 snode = snode->GetPrevious();
281 else if (target_plugin_chart)
282 pnode = pnode->GetPrevious();
283
284 } // end of while
285 }
286
287 // Work with the sector legs vector to identify and mark "Leading Lights"
288 // Sectors with CATLIT "Leading" or "Directional" attribute set have already
289 // been marked
290 for (unsigned int i = 0; i < sectorlegs.size(); i++) {
291 if (((sectorlegs[i].sector2 - sectorlegs[i].sector1) < 15)) {
292 if (sectorlegs[i].iswhite && bhas_red_green)
293 sectorlegs[i].isleading = true;
294 }
295 }
296
297 return newSectorsNeedDrawing;
298}
299
300void s57_DrawExtendedLightSectors(ocpnDC &dc, ViewPort &viewport,
301 std::vector<s57Sector_t> &sectorlegs) {
302 float rangeScale = 0.0;
303
304 if (sectorlegs.size() > 0) {
305 std::vector<int> sectorangles;
306 for (unsigned int i = 0; i < sectorlegs.size(); i++) {
307 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3) continue;
308
309 double endx, endy;
310 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
311 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
312 &endx);
313
314 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
315
316 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
317 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
318 &endx);
319
320 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
321
322 wxPoint lightPos =
323 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
324
325 // Make sure arcs are well inside viewport.
326 float rangePx = sqrtf(powf((float)(lightPos.x - end1.x), 2) +
327 powf((float)(lightPos.y - end1.y), 2));
328 rangePx /= 3.0;
329 if (rangeScale == 0.0) {
330 rangeScale = 1.0;
331 if (rangePx > viewport.pix_height / 3) {
332 rangeScale *= (viewport.pix_height / 3) / rangePx;
333 }
334 }
335
336 rangePx = rangePx * rangeScale;
337
338 int penWidth = rangePx / 8;
339 penWidth = wxMin(20, penWidth);
340 penWidth = wxMax(5, penWidth);
341
342 int legOpacity;
343 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
344 penWidth, wxPENSTYLE_SOLID);
345 arcpen->SetCap(wxCAP_BUTT);
346 dc.SetPen(*arcpen);
347
348 float angle1, angle2;
349 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
350 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
351 if (angle1 > angle2) {
352 angle2 += 360.0;
353 }
354 int lpx = lightPos.x;
355 int lpy = lightPos.y;
356 int npoints = 0;
357 wxPoint arcpoints[150]; // Size relates to "step" below.
358
359 float step = 3.0;
360 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
361 step += 2.0; // less points on small arcs
362
363 // Make sure we start and stop exactly on the leg lines.
364 int narc = (angle2 - angle1) / step;
365 narc++;
366 step = (angle2 - angle1) / (float)narc;
367
368 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
369 wxPoint yellowCone[3];
370 yellowCone[0] = lightPos;
371 yellowCone[1] = end1;
372 yellowCone[2] = end2;
373 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
374 wxPENSTYLE_SOLID);
375 dc.SetPen(*arcpen);
376 wxColor c = sectorlegs[i].color;
377 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
378 dc.SetBrush(wxBrush(c));
379 dc.StrokePolygon(3, yellowCone, 0, 0);
380 legOpacity = 50;
381 } else {
382 for (float a = angle1; a <= angle2 + 0.1; a += step) {
383 int x = lpx + (int)(rangePx * cos(a * PI / 180.));
384 int y = lpy - (int)(rangePx * sin(a * PI / 180.));
385 arcpoints[npoints].x = x;
386 arcpoints[npoints].y = y;
387 npoints++;
388 }
389 dc.StrokeLines(npoints, arcpoints);
390 legOpacity = 128;
391 }
392
393 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
394 wxPENSTYLE_SOLID);
395 dc.SetPen(*arcpen);
396
397 // Only draw each leg line once.
398
399 bool haveAngle1 = false;
400 bool haveAngle2 = false;
401 int sec1 = (int)sectorlegs[i].sector1;
402 int sec2 = (int)sectorlegs[i].sector2;
403 if (sec1 > 360) sec1 -= 360;
404 if (sec2 > 360) sec2 -= 360;
405
406 if ((sec2 == 360) && (sec1 == 0)) // FS#1437
407 continue;
408
409 for (unsigned int j = 0; j < sectorangles.size(); j++) {
410 if (sectorangles[j] == sec1) haveAngle1 = true;
411 if (sectorangles[j] == sec2) haveAngle2 = true;
412 }
413
414 if (!haveAngle1) {
415 dc.StrokeLine(lightPos, end1);
416 sectorangles.push_back(sec1);
417 }
418
419 if (!haveAngle2) {
420 dc.StrokeLine(lightPos, end2);
421 sectorangles.push_back(sec2);
422 }
423 }
424 }
425}
426
427#ifdef ocpnUSE_GL
428void s57_DrawExtendedLightSectorsGL(ocpnDC &dc, ViewPort &viewport,
429 std::vector<s57Sector_t> &sectorlegs) {
430 float rangeScale = 0.0;
431
432 if (sectorlegs.size() > 0) {
433 std::vector<int> sectorangles;
434 for (unsigned int i = 0; i < sectorlegs.size(); i++) {
435 if (fabs(sectorlegs[i].sector1 - sectorlegs[i].sector2) < 0.3) continue;
436
437 double endx, endy;
438 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
439 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
440 &endx);
441
442 wxPoint end1 = viewport.GetPixFromLL(endy, endx);
443
444 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
445 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
446 &endx);
447
448 wxPoint end2 = viewport.GetPixFromLL(endy, endx);
449
450 wxPoint lightPos =
451 viewport.GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
452
453 // Make sure arcs are well inside viewport.
454 float rangePx = sqrtf(powf((float)(lightPos.x - end1.x), 2) +
455 powf((float)(lightPos.y - end1.y), 2));
456 rangePx /= 3.0;
457 if (rangeScale == 0.0) {
458 rangeScale = 1.0;
459 if (rangePx > viewport.pix_height / 3) {
460 rangeScale *= (viewport.pix_height / 3) / rangePx;
461 }
462 }
463
464 rangePx = rangePx * rangeScale;
465
466 float arcw = rangePx / 10;
467 arcw = wxMin(20, arcw);
468 arcw = wxMax(5, arcw);
469
470 int legOpacity;
471
472 float angle1, angle2;
473 angle1 = -(sectorlegs[i].sector2 + 90.0) - viewport.rotation * 180.0 / PI;
474 angle2 = -(sectorlegs[i].sector1 + 90.0) - viewport.rotation * 180.0 / PI;
475 if (angle1 > angle2) {
476 angle2 += 360.0;
477 }
478 int lpx = lightPos.x;
479 int lpy = lightPos.y;
480
481 if (sectorlegs[i].isleading && (angle2 - angle1 < 60)) {
482 wxPoint yellowCone[3];
483 yellowCone[0] = lightPos;
484 yellowCone[1] = end1;
485 yellowCone[2] = end2;
486 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 0), 1,
487 wxPENSTYLE_SOLID);
488 dc.SetPen(*arcpen);
489 wxColor c = sectorlegs[i].color;
490 c.Set(c.Red(), c.Green(), c.Blue(), 0.6 * c.Alpha());
491 dc.SetBrush(wxBrush(c));
492 dc.StrokePolygon(3, yellowCone, 0, 0);
493 legOpacity = 50;
494 } else {
495 // Center point
496 wxPoint r(lpx, lpy);
497
498 // radius scaled to display
499 float rad = rangePx;
500
501 // float arcw = arc_width * canvas_pix_per_mm;
502 // On larger screens, make the arc_width 1.0 mm
503 // if ( m_display_size_mm > 200) //200 mm, about 8 inches
504 // arcw = canvas_pix_per_mm;
505
506 // Enable anti-aliased lines, at best quality
507 glEnable(GL_BLEND);
508
509 float coords[8];
510 coords[0] = -rad;
511 coords[1] = rad;
512 coords[2] = rad;
513 coords[3] = rad;
514 coords[4] = -rad;
515 coords[5] = -rad;
516 coords[6] = rad;
517 coords[7] = -rad;
518
519 GLShaderProgram *shader = pring_shader_program[0 /*GetCanvasIndex()*/];
520 shader->Bind();
521
522 // Get pointers to the attributes in the program.
523 GLint mPosAttrib = glGetAttribLocation(shader->programId(), "aPos");
524
525 // Disable VBO's (vertex buffer objects) for attributes.
526 glBindBuffer(GL_ARRAY_BUFFER, 0);
527 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
528
529 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
530 glEnableVertexAttribArray(mPosAttrib);
531
532 // Circle radius
533 GLint radiusloc =
534 glGetUniformLocation(shader->programId(), "circle_radius");
535 glUniform1f(radiusloc, rad);
536
537 // Circle center point, physical
538 GLint centerloc =
539 glGetUniformLocation(shader->programId(), "circle_center");
540 float ctrv[2];
541 ctrv[0] = r.x;
542 ctrv[1] = viewport.pix_height - r.y;
543 glUniform2fv(centerloc, 1, ctrv);
544
545 // Circle color
546 wxColour colorb = sectorlegs[i].color;
547 float colorv[4];
548 colorv[0] = colorb.Red() / float(256);
549 colorv[1] = colorb.Green() / float(256);
550 colorv[2] = colorb.Blue() / float(256);
551 colorv[3] = colorb.Alpha() / float(256);
552
553 GLint colloc =
554 glGetUniformLocation(shader->programId(), "circle_color");
555 glUniform4fv(colloc, 1, colorv);
556
557 // Border color
558 float bcolorv[4];
559 bcolorv[0] = 0;
560 bcolorv[1] = 0;
561 bcolorv[2] = 0;
562 bcolorv[3] = 0;
563
564 GLint bcolloc =
565 glGetUniformLocation(shader->programId(), "border_color");
566 glUniform4fv(bcolloc, 1, bcolorv);
567
568 // Border Width
569 GLint borderWidthloc =
570 glGetUniformLocation(shader->programId(), "border_width");
571 glUniform1f(borderWidthloc, 2);
572
573 // Ring width
574 GLint ringWidthloc =
575 glGetUniformLocation(shader->programId(), "ring_width");
576 glUniform1f(ringWidthloc, arcw);
577
578 // Visible sectors, rotated to vp orientation
579 float sr1 =
580 sectorlegs[i].sector1 + (viewport.rotation * 180 / PI) + 180;
581 if (sr1 > 360.) sr1 -= 360.;
582 float sr2 =
583 sectorlegs[i].sector2 + (viewport.rotation * 180 / PI) + 180;
584 if (sr2 > 360.) sr2 -= 360.;
585
586 float sb, se;
587 if (sr2 > sr1) {
588 sb = sr1;
589 se = sr2;
590 } else {
591 sb = sr1;
592 se = sr2 + 360;
593 }
594
595 // Shader can handle angles > 360.
596 if ((sb < 0) || (se < 0)) {
597 sb += 360.;
598 se += 360.;
599 }
600
601 GLint sector1loc =
602 glGetUniformLocation(shader->programId(), "sector_1");
603 glUniform1f(sector1loc, (sb * PI / 180.));
604 GLint sector2loc =
605 glGetUniformLocation(shader->programId(), "sector_2");
606 glUniform1f(sector2loc, (se * PI / 180.));
607
608 // Rotate and translate
609 mat4x4 I;
610 mat4x4_identity(I);
611 mat4x4_translate_in_place(I, r.x, r.y, 0);
612
613 GLint matloc =
614 glGetUniformLocation(shader->programId(), "TransformMatrix");
615 glUniformMatrix4fv(matloc, 1, GL_FALSE, (const GLfloat *)I);
616
617 // Perform the actual drawing.
618 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
619
620 // Restore the per-object transform to Identity Matrix
621 mat4x4 IM;
622 mat4x4_identity(IM);
623 GLint matlocf =
624 glGetUniformLocation(shader->programId(), "TransformMatrix");
625 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (const GLfloat *)IM);
626
627 glDisableVertexAttribArray(mPosAttrib);
628 shader->UnBind();
629 }
630
631 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
632 wxPENSTYLE_SOLID);
633 dc.SetPen(*arcpen);
634
635 // Only draw each leg line once.
636 bool haveAngle1 = false;
637 bool haveAngle2 = false;
638 int sec1 = (int)sectorlegs[i].sector1;
639 int sec2 = (int)sectorlegs[i].sector2;
640 if (sec1 > 360) sec1 -= 360;
641 if (sec2 > 360) sec2 -= 360;
642
643 if ((sec2 == 360) && (sec1 == 0)) // FS#1437
644 continue;
645
646 for (unsigned int j = 0; j < sectorangles.size(); j++) {
647 if (sectorangles[j] == sec1) haveAngle1 = true;
648 if (sectorangles[j] == sec2) haveAngle2 = true;
649 }
650
651 if (!haveAngle1) {
652 dc.StrokeLine(lightPos, end1);
653 sectorangles.push_back(sec1);
654 }
655
656 if (!haveAngle2) {
657 dc.StrokeLine(lightPos, end2);
658 sectorangles.push_back(sec2);
659 }
660 }
661 }
662}
663
664#endif // ocpnUSE_GL
665
666bool s57_CheckExtendedLightSectors(ChartCanvas *cc, int mx, int my,
667 ViewPort &viewport,
668 std::vector<s57Sector_t> &sectorlegs) {
669 if (!cc) return false;
670
671 double cursor_lat, cursor_lon;
672 static float lastLat, lastLon;
673
674 if (!ps52plib || !ps52plib->m_bExtendLightSectors) return false;
675
676 ChartPlugInWrapper *target_plugin_chart = NULL;
677 s57chart *Chs57 = NULL;
678
679 ChartBase *target_chart = cc->GetChartAtCursor();
680 if (target_chart) {
681 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
682 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
683 target_plugin_chart = dynamic_cast<ChartPlugInWrapper *>(target_chart);
684 else
685 Chs57 = dynamic_cast<s57chart *>(target_chart);
686 }
687
688 cc->GetCanvasPixPoint(mx, my, cursor_lat, cursor_lon);
689
690 if (lastLat == cursor_lat && lastLon == cursor_lon) return false;
691
692 lastLat = cursor_lat;
693 lastLon = cursor_lon;
694 bool newSectorsNeedDrawing = false;
695
696 if (target_plugin_chart || Chs57) {
697 ListOfObjRazRules *rule_list = NULL;
698 ListOfPI_S57Obj *pi_rule_list = NULL;
699
700 // Go get the array of all objects at the cursor lat/lon
701 float selectRadius = 16 / (viewport.view_scale_ppm * 1852 * 60);
702
703 if (Chs57)
704 rule_list = Chs57->GetObjRuleListAtLatLon(
705 cursor_lat, cursor_lon, selectRadius, &viewport, MASK_POINT);
706 else if (target_plugin_chart)
707 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
708 target_plugin_chart, cursor_lat, cursor_lon, selectRadius, viewport);
709
710 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
711 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
712
713 if (rule_list) {
714 rule_list->Clear();
715 delete rule_list;
716 }
717
718 if (pi_rule_list) {
719 pi_rule_list->Clear();
720 delete pi_rule_list;
721 }
722 }
723
724 return newSectorsNeedDrawing;
725}
Base class for all chart types.
Definition chartbase.h:119
Chart display canvas.
Definition chcanv.h:135
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4543
Wrapper class for plugin-based charts.
Definition chartimg.h:392
Wrapper class for OpenGL shader programs.
Definition shaders.h:57
Represents the view port for chart display in OpenCPN.
Definition viewport.h:84
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
Definition viewport.h:199
int pix_height
Height of the viewport in physical pixels.
Definition viewport.h:221
double rotation
Rotation angle of the viewport in radians.
Definition viewport.h:209
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
Definition viewport.cpp:136
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:64
Represents an S57 format electronic navigational chart in OpenCPN.
Definition s57chart.h:120
PlugIn Object Definition/API.
Represents a sector of a light in an S57 chart.
Definition S57Sector.h:36