25#include "s57_ocpn_utils.h"
34bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
36 std::vector<s57Sector_t> §orlegs) {
37 if (!cc)
return false;
39 static float lastLat, lastLon;
41 if (!ps52plib)
return false;
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);
58 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
59 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
62 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
65 bool newSectorsNeedDrawing =
false;
67 if (target_plugin_chart || Chs57) {
68 ListOfObjRazRules *rule_list = NULL;
69 ListOfPI_S57Obj *pi_rule_list = NULL;
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);
81 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
82 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
90 pi_rule_list->Clear();
95 return newSectorsNeedDrawing;
98bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
101 ListOfObjRazRules *rule_list,
102 ListOfPI_S57Obj *pi_rule_list,
103 std::vector<s57Sector_t> §orlegs) {
104 bool newSectorsNeedDrawing =
false;
106 bool bhas_red_green =
false;
107 bool bleading_attribute =
false;
110 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
111 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
113 int yOpacity = (float)opacity *
116 if (target_plugin_chart || Chs57) {
119 wxPoint2DDouble objPos;
121 char *curr_att = NULL;
123 wxArrayOfS57attVal *attValArray = NULL;
125 ListOfObjRazRules::Node *snode = NULL;
126 ListOfPI_S57Obj::Node *pnode = NULL;
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();
134 wxPoint2DDouble lightPosD(0, 0);
135 bool is_light =
false;
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;
148 }
else if (target_plugin_chart) {
152 objPos = wxPoint2DDouble(light->
m_lat, light->
m_lon);
155 attValArray = light->
attVal;
165 wxString curAttrName;
168 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
170 if (is_light && (lightPosD == objPos)) {
178 bleading_attribute =
false;
180 while (attrCounter < n_attr) {
181 curAttrName = wxString(curr_att, wxConvUTF8, 6);
184 S57attVal *pAttrVal = NULL;
187 pAttrVal = attValArray->Item(attrCounter);
188 else if (target_plugin_chart)
189 pAttrVal = attValArray->Item(attrCounter);
193 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
195 if (curAttrName ==
"LITVIS") {
196 if (value.StartsWith(
"obsc")) bviz =
false;
198 if (curAttrName ==
"SECTR1") value.ToDouble(§r1);
199 if (curAttrName ==
"SECTR2") value.ToDouble(§r2);
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;
208 if (value ==
"green(4)") {
209 color = wxColor(0, 255, 0, opacity);
210 sector.iswhite =
false;
211 bhas_red_green =
true;
215 if (curAttrName ==
"EXCLIT") {
216 if (value.Find(
"(3)")) valnmr = 1.0;
219 if (curAttrName ==
"CATLIT") {
220 if (value.Upper().StartsWith(
"DIRECT") ||
221 value.Upper().StartsWith(
"LEAD"))
222 bleading_attribute =
true;
229 if ((sectr1 >= 0) && (sectr2 >= 0)) {
230 if (sectr1 > sectr2) {
234 sector.pos.m_x = objPos.m_y;
235 sector.pos.m_y = objPos.m_x;
238 (valnmr > 0.0) ? valnmr : 2.5;
239 sector.sector1 = sectr1;
240 sector.sector2 = sectr2;
243 color = wxColor(255, 255, 0, yOpacity);
244 sector.iswhite =
true;
246 sector.color = color;
247 sector.isleading =
false;
249 if (bleading_attribute) sector.isleading =
true;
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) {
261 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
265 if (!bviz) newsector =
false;
267 if ((sector.sector2 == 360) && (sector.sector1 == 0))
271 sectorlegs.push_back(sector);
272 newSectorsNeedDrawing =
true;
279 snode = snode->GetPrevious();
280 else if (target_plugin_chart)
281 pnode = pnode->GetPrevious();
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;
296 return newSectorsNeedDrawing;
300 std::vector<s57Sector_t> §orlegs) {
301 float rangeScale = 0.0;
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;
309 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
310 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
315 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
316 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
322 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
325 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
326 powf((
float)(lightPos.y - end1.y), 2));
328 if (rangeScale == 0.0) {
331 rangeScale *= (viewport.
pix_height / 3) / rangePx;
335 rangePx = rangePx * rangeScale;
337 int penWidth = rangePx / 8;
338 penWidth = wxMin(20, penWidth);
339 penWidth = wxMax(5, penWidth);
342 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
343 penWidth, wxPENSTYLE_SOLID);
344 arcpen->SetCap(wxCAP_BUTT);
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) {
353 int lpx = lightPos.x;
354 int lpy = lightPos.y;
356 wxPoint arcpoints[150];
359 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
363 int narc = (angle2 - angle1) / step;
365 step = (angle2 - angle1) / (
float)narc;
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,
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);
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;
388 dc.StrokeLines(npoints, arcpoints);
392 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
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;
405 if ((sec2 == 360) && (sec1 == 0))
408 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
409 if (sectorangles[j] == sec1) haveAngle1 =
true;
410 if (sectorangles[j] == sec2) haveAngle2 =
true;
414 dc.StrokeLine(lightPos, end1);
415 sectorangles.push_back(sec1);
419 dc.StrokeLine(lightPos, end2);
420 sectorangles.push_back(sec2);
427void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
428 std::vector<s57Sector_t> §orlegs) {
429 float rangeScale = 0.0;
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;
437 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
438 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
443 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
444 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
450 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
453 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
454 powf((
float)(lightPos.y - end1.y), 2));
456 if (rangeScale == 0.0) {
459 rangeScale *= (viewport.
pix_height / 3) / rangePx;
463 rangePx = rangePx * rangeScale;
465 float arcw = rangePx / 10;
466 arcw = wxMin(20, arcw);
467 arcw = wxMax(5, arcw);
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) {
477 int lpx = lightPos.x;
478 int lpy = lightPos.y;
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,
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);
522 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
525 glBindBuffer(GL_ARRAY_BUFFER, 0);
526 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
528 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
529 glEnableVertexAttribArray(mPosAttrib);
533 glGetUniformLocation(shader->programId(),
"circle_radius");
534 glUniform1f(radiusloc, rad);
538 glGetUniformLocation(shader->programId(),
"circle_center");
542 glUniform2fv(centerloc, 1, ctrv);
545 wxColour colorb = sectorlegs[i].color;
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);
553 glGetUniformLocation(shader->programId(),
"circle_color");
554 glUniform4fv(colloc, 1, colorv);
564 glGetUniformLocation(shader->programId(),
"border_color");
565 glUniform4fv(bcolloc, 1, bcolorv);
568 GLint borderWidthloc =
569 glGetUniformLocation(shader->programId(),
"border_width");
570 glUniform1f(borderWidthloc, 2);
574 glGetUniformLocation(shader->programId(),
"ring_width");
575 glUniform1f(ringWidthloc, arcw);
579 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
580 if (sr1 > 360.) sr1 -= 360.;
582 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
583 if (sr2 > 360.) sr2 -= 360.;
595 if ((sb < 0) || (se < 0)) {
601 glGetUniformLocation(shader->programId(),
"sector_1");
602 glUniform1f(sector1loc, (sb * PI / 180.));
604 glGetUniformLocation(shader->programId(),
"sector_2");
605 glUniform1f(sector2loc, (se * PI / 180.));
610 mat4x4_translate_in_place(I, r.x, r.y, 0);
613 glGetUniformLocation(shader->programId(),
"TransformMatrix");
614 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
617 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
623 glGetUniformLocation(shader->programId(),
"TransformMatrix");
624 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
626 glDisableVertexAttribArray(mPosAttrib);
630 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
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;
642 if ((sec2 == 360) && (sec1 == 0))
645 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
646 if (sectorangles[j] == sec1) haveAngle1 =
true;
647 if (sectorangles[j] == sec2) haveAngle2 =
true;
651 dc.StrokeLine(lightPos, end1);
652 sectorangles.push_back(sec1);
656 dc.StrokeLine(lightPos, end2);
657 sectorangles.push_back(sec2);
665bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
667 std::vector<s57Sector_t> §orlegs) {
668 if (!cc)
return false;
670 double cursor_lat, cursor_lon;
671 static float lastLat, lastLon;
673 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
678 ChartBase *target_chart = cc->GetChartAtCursor();
680 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
681 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
684 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
689 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
691 lastLat = cursor_lat;
692 lastLon = cursor_lon;
693 bool newSectorsNeedDrawing =
false;
695 if (target_plugin_chart || Chs57) {
696 ListOfObjRazRules *rule_list = NULL;
697 ListOfPI_S57Obj *pi_rule_list = NULL;
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);
709 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
710 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
718 pi_rule_list->Clear();
723 return newSectorsNeedDrawing;
Generic Chart canvas base.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Wrapper class for plugin-based charts.
Wrapper class for OpenGL shader programs.
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.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
Device context class that can use either wxDC or OpenGL for drawing.
Represents an S57 format electronic navigational chart in OpenCPN.
PlugIn Object Definition/API.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents a sector of a light in an S57 chart.