23#include "s57_ocpn_utils.h"
28#include "pluginmanager.h"
33extern s52plib *ps52plib;
35bool s57_GetVisibleLightSectors(
ChartCanvas *cc,
double lat,
double lon,
37 std::vector<s57Sector_t> §orlegs) {
38 if (!cc)
return false;
40 static float lastLat, lastLon;
42 if (!ps52plib)
return false;
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);
59 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
60 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
63 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
66 bool newSectorsNeedDrawing =
false;
68 if (target_plugin_chart || Chs57) {
69 ListOfObjRazRules *rule_list = NULL;
70 ListOfPI_S57Obj *pi_rule_list = NULL;
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);
82 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
83 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
91 pi_rule_list->Clear();
96 return newSectorsNeedDrawing;
99bool s57_ProcessExtendedLightSectors(
ChartCanvas *cc,
102 ListOfObjRazRules *rule_list,
103 ListOfPI_S57Obj *pi_rule_list,
104 std::vector<s57Sector_t> §orlegs) {
105 bool newSectorsNeedDrawing =
false;
107 bool bhas_red_green =
false;
108 bool bleading_attribute =
false;
111 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_DUSK) opacity = 50;
112 if (cc->GetColorScheme() == GLOBAL_COLOR_SCHEME_NIGHT) opacity = 20;
114 int yOpacity = (float)opacity *
117 if (target_plugin_chart || Chs57) {
120 wxPoint2DDouble objPos;
122 char *curr_att = NULL;
124 wxArrayOfS57attVal *attValArray = NULL;
126 ListOfObjRazRules::Node *snode = NULL;
127 ListOfPI_S57Obj::Node *pnode = NULL;
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();
135 wxPoint2DDouble lightPosD(0, 0);
136 bool is_light =
false;
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;
149 }
else if (target_plugin_chart) {
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;
166 wxString curAttrName;
169 if (lightPosD.m_x == 0 && lightPosD.m_y == 0.0) lightPosD = objPos;
171 if (is_light && (lightPosD == objPos)) {
179 bleading_attribute =
false;
181 while (attrCounter < n_attr) {
182 curAttrName = wxString(curr_att, wxConvUTF8, 6);
185 S57attVal *pAttrVal = NULL;
188 pAttrVal = attValArray->Item(attrCounter);
189 else if (target_plugin_chart)
190 pAttrVal = attValArray->Item(attrCounter);
194 s57chart::GetAttributeValueAsString(pAttrVal, curAttrName);
196 if (curAttrName == _T(
"LITVIS")) {
197 if (value.StartsWith(_T(
"obsc"))) bviz =
false;
199 if (curAttrName == _T(
"SECTR1")) value.ToDouble(§r1);
200 if (curAttrName == _T(
"SECTR2")) value.ToDouble(§r2);
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;
209 if (value == _T(
"green(4)")) {
210 color = wxColor(0, 255, 0, opacity);
211 sector.iswhite =
false;
212 bhas_red_green =
true;
216 if (curAttrName == _T(
"EXCLIT")) {
217 if (value.Find(_T(
"(3)"))) valnmr = 1.0;
220 if (curAttrName == _T(
"CATLIT")) {
221 if (value.Upper().StartsWith(_T(
"DIRECT")) ||
222 value.Upper().StartsWith(_T(
"LEAD")))
223 bleading_attribute =
true;
230 if ((sectr1 >= 0) && (sectr2 >= 0)) {
231 if (sectr1 > sectr2) {
235 sector.pos.m_x = objPos.m_y;
236 sector.pos.m_y = objPos.m_x;
239 (valnmr > 0.0) ? valnmr : 2.5;
240 sector.sector1 = sectr1;
241 sector.sector2 = sectr2;
244 color = wxColor(255, 255, 0, yOpacity);
245 sector.iswhite =
true;
247 sector.color = color;
248 sector.isleading =
false;
250 if (bleading_attribute) sector.isleading =
true;
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) {
262 sectorlegs[i].range = wxMax(sectorlegs[i].range, sector.range);
266 if (!bviz) newsector =
false;
268 if ((sector.sector2 == 360) && (sector.sector1 == 0))
272 sectorlegs.push_back(sector);
273 newSectorsNeedDrawing =
true;
280 snode = snode->GetPrevious();
281 else if (target_plugin_chart)
282 pnode = pnode->GetPrevious();
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;
297 return newSectorsNeedDrawing;
301 std::vector<s57Sector_t> §orlegs) {
302 float rangeScale = 0.0;
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;
310 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
311 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
316 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
317 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
323 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
326 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
327 powf((
float)(lightPos.y - end1.y), 2));
329 if (rangeScale == 0.0) {
332 rangeScale *= (viewport.
pix_height / 3) / rangePx;
336 rangePx = rangePx * rangeScale;
338 int penWidth = rangePx / 8;
339 penWidth = wxMin(20, penWidth);
340 penWidth = wxMax(5, penWidth);
343 wxPen *arcpen = wxThePenList->FindOrCreatePen(sectorlegs[i].color,
344 penWidth, wxPENSTYLE_SOLID);
345 arcpen->SetCap(wxCAP_BUTT);
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) {
354 int lpx = lightPos.x;
355 int lpy = lightPos.y;
357 wxPoint arcpoints[150];
360 while ((step < 15) && ((rangePx * sin(step * PI / 180.)) < 10))
364 int narc = (angle2 - angle1) / step;
366 step = (angle2 - angle1) / (
float)narc;
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,
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);
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;
389 dc.StrokeLines(npoints, arcpoints);
393 arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, legOpacity), 1,
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;
406 if ((sec2 == 360) && (sec1 == 0))
409 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
410 if (sectorangles[j] == sec1) haveAngle1 =
true;
411 if (sectorangles[j] == sec2) haveAngle2 =
true;
415 dc.StrokeLine(lightPos, end1);
416 sectorangles.push_back(sec1);
420 dc.StrokeLine(lightPos, end2);
421 sectorangles.push_back(sec2);
428void s57_DrawExtendedLightSectorsGL(
ocpnDC &dc,
ViewPort &viewport,
429 std::vector<s57Sector_t> §orlegs) {
430 float rangeScale = 0.0;
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;
438 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
439 sectorlegs[i].sector1 + 180.0, sectorlegs[i].range, &endy,
444 ll_gc_ll(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x,
445 sectorlegs[i].sector2 + 180.0, sectorlegs[i].range, &endy,
451 viewport.
GetPixFromLL(sectorlegs[i].pos.m_y, sectorlegs[i].pos.m_x);
454 float rangePx = sqrtf(powf((
float)(lightPos.x - end1.x), 2) +
455 powf((
float)(lightPos.y - end1.y), 2));
457 if (rangeScale == 0.0) {
460 rangeScale *= (viewport.
pix_height / 3) / rangePx;
464 rangePx = rangePx * rangeScale;
466 float arcw = rangePx / 10;
467 arcw = wxMin(20, arcw);
468 arcw = wxMax(5, arcw);
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) {
478 int lpx = lightPos.x;
479 int lpy = lightPos.y;
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,
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);
523 GLint mPosAttrib = glGetAttribLocation(shader->programId(),
"aPos");
526 glBindBuffer(GL_ARRAY_BUFFER, 0);
527 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
529 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
530 glEnableVertexAttribArray(mPosAttrib);
534 glGetUniformLocation(shader->programId(),
"circle_radius");
535 glUniform1f(radiusloc, rad);
539 glGetUniformLocation(shader->programId(),
"circle_center");
543 glUniform2fv(centerloc, 1, ctrv);
546 wxColour colorb = sectorlegs[i].color;
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);
554 glGetUniformLocation(shader->programId(),
"circle_color");
555 glUniform4fv(colloc, 1, colorv);
565 glGetUniformLocation(shader->programId(),
"border_color");
566 glUniform4fv(bcolloc, 1, bcolorv);
569 GLint borderWidthloc =
570 glGetUniformLocation(shader->programId(),
"border_width");
571 glUniform1f(borderWidthloc, 2);
575 glGetUniformLocation(shader->programId(),
"ring_width");
576 glUniform1f(ringWidthloc, arcw);
580 sectorlegs[i].sector1 + (viewport.
rotation * 180 / PI) + 180;
581 if (sr1 > 360.) sr1 -= 360.;
583 sectorlegs[i].sector2 + (viewport.
rotation * 180 / PI) + 180;
584 if (sr2 > 360.) sr2 -= 360.;
596 if ((sb < 0) || (se < 0)) {
602 glGetUniformLocation(shader->programId(),
"sector_1");
603 glUniform1f(sector1loc, (sb * PI / 180.));
605 glGetUniformLocation(shader->programId(),
"sector_2");
606 glUniform1f(sector2loc, (se * PI / 180.));
611 mat4x4_translate_in_place(I, r.x, r.y, 0);
614 glGetUniformLocation(shader->programId(),
"TransformMatrix");
615 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
618 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
624 glGetUniformLocation(shader->programId(),
"TransformMatrix");
625 glUniformMatrix4fv(matlocf, 1, GL_FALSE, (
const GLfloat *)IM);
627 glDisableVertexAttribArray(mPosAttrib);
631 wxPen *arcpen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 128), 1,
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;
643 if ((sec2 == 360) && (sec1 == 0))
646 for (
unsigned int j = 0; j < sectorangles.size(); j++) {
647 if (sectorangles[j] == sec1) haveAngle1 =
true;
648 if (sectorangles[j] == sec2) haveAngle2 =
true;
652 dc.StrokeLine(lightPos, end1);
653 sectorangles.push_back(sec1);
657 dc.StrokeLine(lightPos, end2);
658 sectorangles.push_back(sec2);
666bool s57_CheckExtendedLightSectors(
ChartCanvas *cc,
int mx,
int my,
668 std::vector<s57Sector_t> §orlegs) {
669 if (!cc)
return false;
671 double cursor_lat, cursor_lon;
672 static float lastLat, lastLon;
674 if (!ps52plib || !ps52plib->m_bExtendLightSectors)
return false;
679 ChartBase *target_chart = cc->GetChartAtCursor();
681 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
682 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
685 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
690 if (lastLat == cursor_lat && lastLon == cursor_lon)
return false;
692 lastLat = cursor_lat;
693 lastLon = cursor_lon;
694 bool newSectorsNeedDrawing =
false;
696 if (target_plugin_chart || Chs57) {
697 ListOfObjRazRules *rule_list = NULL;
698 ListOfPI_S57Obj *pi_rule_list = NULL;
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);
710 newSectorsNeedDrawing = s57_ProcessExtendedLightSectors(
711 cc, target_plugin_chart, Chs57, rule_list, pi_rule_list, sectorlegs);
719 pi_rule_list->Clear();
724 return newSectorsNeedDrawing;
Base class for all chart types.
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.
Represents the view port for chart display in OpenCPN.
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.
Represents a sector of a light in an S57 chart.