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