1 /******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: S52 Conditional Symbology Library
5 * Author: David Register, Sylvain Duclos
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 *
10 * Copyright (C) 2000-2001 Sylvain Duclos
11 * sylvain_duclos@yahoo.com
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the *
25 * Free Software Foundation, Inc., *
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
27 ***************************************************************************
28 *
29 */
30
31 #include "wx/wxprec.h"
32
33 #ifndef WX_PRECOMP
34 #include "wx/wx.h"
35 #endif //precompiled headers
36
37 #include "wx/tokenzr.h"
38
39 #include "s57chart.h"
40 #include "s52plib.h"
41 #include "s52utils.h"
42 #include "dychart.h"
43 #include "cutil.h"
44
45 bool GetDoubleAttr(S57Obj *obj, const char *AttrName, double &val);
46
47 #define UNKNOWN 1e6 //HUGE_VAL // INFINITY/NAN
48
49 #ifndef chk_snprintf
50 #define chk_snprintf(buf, len, fmt, ...) \
51 { \
52 int r = snprintf(buf, len, fmt, ##__VA_ARGS__); \
53 if (r == -1 || r >= len) wxLogWarning("snprint overrun"); \
54 }
55 #endif
56
57 WX_DEFINE_ARRAY_DOUBLE(double, ArrayOfSortedDoubles);
58
59
60 // size of attributes value list buffer
61 #define LISTSIZE 32 // list size
62
63 extern s52plib *ps52plib;
64
65 wxString *CSQUAPNT01(S57Obj *obj);
66 wxString *CSQUALIN01(S57Obj *obj);
67
68
69
GetChartFloatingATONArray(ObjRazRules * rzRules)70 wxArrayPtrVoid *GetChartFloatingATONArray( ObjRazRules *rzRules )
71 {
72 S57Obj *obj = rzRules->obj;
73 if( obj->m_chart_context->chart )
74 return obj->m_chart_context->chart->pFloatingATONArray;
75 else
76 return obj->m_chart_context->pFloatingATONArray;
77
78 }
79
GetChartRigidATONArray(ObjRazRules * rzRules)80 wxArrayPtrVoid *GetChartRigidATONArray( ObjRazRules *rzRules )
81 {
82 S57Obj *obj = rzRules->obj;
83 if( obj->m_chart_context->chart )
84 return obj->m_chart_context->chart->pRigidATONArray;
85 else
86 return obj->m_chart_context->pRigidATONArray;
87 }
88
CLRLIN01(void * param)89 static void *CLRLIN01(void *param)
90 {
91 ObjRazRules *rzRules = (ObjRazRules *)param;
92 // S57Obj *obj = rzRules->obj;
93
94 printf("s52csny : CLRLIN01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
95 return NULL;
96 }
97
DATCVR01(void * param)98 static void *DATCVR01(void *param)
99 {
100
101 // Remarks: This conditional symbology procedure describes procedures for:
102 // - symbolizing the limit of ENC coverage;
103 // - symbolizing navigational purpose boundaries ("scale boundarie"); and
104 // - indicating overscale display.
105 //
106 // Note that the mandatory meta object CATQUA is symbolized by the look-up table.
107 //
108 // Because the methods adopted by an ECDIS to meet the IMO and IHO requirements
109 // listed on the next page will depend on the manufacturer's software, and cannot be
110 // described in terms of a flow chart in the same way as other conditional procedures,
111 // this procedure is in the form of written notes.
112
113 // ObjRazRules *rzRules = (ObjRazRules *)param;
114 // S57Obj *obj = rzRules->obj;
115
116 wxString rule_str;
117 ///////////////////////
118 // 1- REQUIREMENT
119 // (IMO/IHO specs. explenation)
120
121 ///////////////////////
122 // 2- ENC COVERAGE
123 //
124 // 2.1- Limit of ENC coverage
125 //datcvr01 = g_string_new(";OP(3OD11060);LC(HODATA01)");
126 rule_str.Append(_T("LC(HODATA01)"));
127 // rule_str.Append("AC(DEPDW)");
128 // FIXME: get cell extend
129
130 // 2.2- No data areas
131 // This can be done outside of CS (ie when clearing the screen in Mesa)
132 // FIXME: ";OP(0---);AC(NODATA)"
133 // FIXME: set geo to cover earth (!)
134
135 //////////////////////
136 // 3- SCALE BOUNDARIES
137 //
138 // 3.1- Chart scale boundaties
139 // FIXME;
140 //g_string_append(datcvr01, ";LS(SOLD,1,CHGRD)");
141 // -OR- LC(SCLBDYnn) (?)
142 //
143 // ;OP(3OS21030)
144
145 // 3.2- Graphical index of navigational purpose
146 // FIXME: draw extent of available SENC in DB
147
148 //////////////////////
149 // 4- OVERSCALE
150 //
151 // FIXME: get meta date CSCL of DSPM field
152 // FIXME: get object M_CSCL or CSCALE
153 //
154 // 4.1- Overscale indication
155 // FIXME: compute, scale = [denominator of the compilation scale] /
156 // [denominator of the display scale]
157 // FIXME: draw overscale indication (ie TX("X%3.1f",scale))
158 //
159 // 4.2- Ovescale area at a chart scale boundary
160 // FIXME: test if next chart is over scale (ie going from large scale chart
161 // to a small scale chart)
162 // FIXME: draw AP(OVERSC01) on overscale part of display
163 //g_string(";OP(3OS21030)");
164
165 //
166 // 4.3- Larger scale data available
167 // FIXME: display indication of better scale available (?)
168
169
170
171
172 wxString datcvr01;
173 datcvr01.Append(rule_str);
174 datcvr01.Append('\037');
175
176 char *r = (char *)malloc(datcvr01.Len() + 1);
177 strcpy(r, datcvr01.mb_str());
178
179 return r;
180
181 }
182
183
GetIntAttr(S57Obj * obj,const char * AttrName,int & val)184 bool GetIntAttr(S57Obj *obj, const char *AttrName, int &val)
185 {
186 int idx = obj->GetAttributeIndex(AttrName);
187
188 if(idx >= 0) {
189 // using idx to get the attribute value
190 S57attVal *v = obj->attVal->Item(idx);
191
192 assert(v->valType == OGR_INT);
193 val = *(int*)(v->value);
194
195 return true;
196 }
197 else
198 return false;
199
200 }
201 #if 0
202 bool GetIntAttr(S57Obj *obj, const char *AttrName, int &val)
203 {
204 char *attList = (char *)calloc(obj->attList->Len()+1, 1);
205 strncpy(attList, obj->attList->mb_str(), obj->attList->Len());
206
207 char *patl = attList;
208 char *patr;
209 int idx = 0;
210 while(*patl)
211 {
212 patr = patl;
213 while(*patr != '\037')
214 patr++;
215
216 if(!strncmp(patl, AttrName, 6))
217 break;
218
219 patl = patr + 1;
220 idx++;
221 }
222
223 if(!*patl) // Requested Attribute not found
224 {
225 free(attList);
226 return false; // so don't return a value
227 }
228
229 // using idx to get the attribute value
230 wxArrayOfS57attVal *pattrVal = obj->attVal;
231
232 S57attVal *v = pattrVal->Item(idx);
233 val = *(int*)(v->value);
234
235 free(attList);
236 return true;
237 }
238 #endif
239 /*
240 bool GetFloatAttr(S57Obj *obj, char *AttrName, float &val)
241 {
242 char *attList = (char *)(obj->attList->mb_str()); //attList is wxString
243
244 char *patl = attList;
245 char *patr;
246 int idx = 0;
247 while(*patl)
248 {
249 patr = patl;
250 while(*patr != '\037')
251 patr++;
252
253 if(!strncmp(patl, AttrName, 6))
254 break;
255
256 patl = patr + 1;
257 idx++;
258 }
259
260 if(!*patl) // Requested Attribute not found
261 {
262 free(attList);
263 return false; // so don't return a value
264 }
265
266 // using idx to get the attribute value
267 wxArrayOfS57attVal *pattrVal = obj->attVal;
268
269 S57attVal *v = pattrVal->Item(idx);
270 val = *(float*)(v->value);
271
272 free(attList);
273 return true;
274 }
275
276 */
GetDoubleAttr(S57Obj * obj,const char * AttrName,double & val)277 bool GetDoubleAttr(S57Obj *obj, const char *AttrName, double &val)
278 {
279 int idx = obj->GetAttributeIndex(AttrName);
280
281 if(idx >= 0) {
282 // using idx to get the attribute value
283
284 S57attVal *v = obj->attVal->Item(idx);
285 assert(v->valType == OGR_REAL);
286 val = *(double*)(v->value);
287
288 return true;
289 }
290 else
291 return false;
292 }
293
294
GetStringAttr(S57Obj * obj,const char * AttrName,char * pval,int nc)295 bool GetStringAttr(S57Obj *obj, const char *AttrName, char *pval, int nc)
296 {
297 int idx = obj->GetAttributeIndex(AttrName);
298
299 if(idx >= 0) {
300 // using idx to get the attribute value
301 S57attVal *v = obj->attVal->Item(idx);
302
303 assert(v->valType == OGR_STR);
304 char *val = (char *)(v->value);
305
306 strncpy(pval, val, nc);
307
308 return true;
309 }
310 else
311 return false;
312 }
313
GetStringAttrWXS(S57Obj * obj,const char * AttrName)314 wxString *GetStringAttrWXS(S57Obj *obj, const char *AttrName)
315 {
316 int idx = obj->GetAttributeIndex(AttrName);
317
318 if(idx >= 0) {
319 // using idx to get the attribute value
320 S57attVal *v = obj->attVal->Item(idx);
321
322 assert(v->valType == OGR_STR);
323 char *val = (char *)(v->value);
324
325 return new wxString(val, wxConvUTF8);
326 }
327 else
328 return NULL;
329 }
330
_parseList(const char * str_in,char * buf,int buf_size)331 static int _parseList(const char *str_in, char *buf, int buf_size)
332 // Put a string of comma delimited number in an array (buf).
333 // Return: the number of value in buf.
334 // Assume: - number < 256,
335 // - list size less than buf_size .
336 // Note: buf is \0 terminated for strpbrk().
337 {
338 char *str = (char *)str_in;
339 int i = 0;
340
341 if (NULL != str && *str != '\0') {
342 do {
343 if ( i>= LISTSIZE-1) {
344 printf("OVERFLOW --value in list lost!!\n");
345 break;
346 }
347
348 /*
349 if (255 < (unsigned char) atoi(str)) {
350 PRINTF("value overflow (>255)\n");
351 exit(0);
352 }
353 */
354
355 buf[i++] = (unsigned char) atoi(str);
356
357 while(isdigit(*str))
358 str++; // next
359
360 } while(*str++ != '\0'); // skip ',' or exit
361 }
362
363 buf[i] = '\0';
364
365 return i;
366 }
367
368
_atPtPos(S57Obj * objNew,wxArrayPtrVoid * curntList,int bSectorCheck)369 static int _atPtPos(S57Obj *objNew, wxArrayPtrVoid *curntList, int bSectorCheck)
370 // return TRUE if there is a light at this position
371 // or if its an extended arc radius else FALSE
372 {
373 unsigned int i;
374
375 if(NULL == curntList)
376 return false;
377
378 for (i=0; i<curntList->GetCount(); i++) {
379 S57Obj *objOld = (S57Obj *)curntList->Item(i);
380
381 if ((objOld->x == objNew->x) && (objOld->y == objNew->y)) {
382
383 if (!bSectorCheck)
384 return TRUE;
385 /*
386 else {
387 // check for extend arc radius
388 GString *Asectr1str = S57_getAttVal(geoOld, "SECTR1");
389 GString *Asectr2str = S57_getAttVal(geoOld, "SECTR2");
390 GString *Bsectr1str = S57_getAttVal(geoNew, "SECTR1");
391 GString *Bsectr2str = S57_getAttVal(geoNew, "SECTR2");
392
393 // check present
394 if (NULL == Asectr1str ||
395 NULL == Asectr1str ||
396 NULL == Asectr1str ||
397 NULL == Asectr1str)
398 return FALSE;
399
400 {
401 double Asectr1 = atof(Asectr1str->str);
402 double Asectr2 = atof(Asectr2str->str);
403 double Bsectr1 = atof(Bsectr1str->str);
404 double Bsectr2 = atof(Bsectr2str->str);
405 double Asweep = (Asectr1 > Asectr2) ?
406 Asectr2-Asectr1+360 : Asectr2-Asectr1;
407 double Bsweep = (Bsectr1 > Bsectr2) ?
408 Bsectr2-Bsectr1+360 : Bsectr2-Bsectr1;
409
410 // check sector overlap
411 if (Asectr2<=Bsectr1 || Asectr1>=Bsectr2) {
412 if (Asweep == Bsweep) {
413 g_string_truncate(Bsectr2str, 0);
414 g_string_sprintf(Bsectr2str, "%f",Bsectr2-1);
415 S57_setAtt(geoNew, "SECTR2", Bsectr2str->str);
416 }
417
418 return FALSE;
419 }
420
421 // check if other sector larger
422 if (Asweep >= Bsweep)
423 return TRUE;
424 }
425 }
426 */
427 }
428 }
429
430 return FALSE;
431 }
432
_selSYcol(char * buf,bool bsectr,double valnmr)433 wxString _selSYcol(char *buf, bool bsectr, double valnmr)
434 {
435 wxString sym;
436
437 if(!bsectr)
438 {
439
440 sym = _T(";SY(LITDEF11"); // default
441
442 // max 1 color
443 if ('\0' == buf[1])
444 {
445 if (strpbrk(buf, "\003"))
446 sym = _T(";SY(LIGHTS11");
447 else if (strpbrk(buf, "\004"))
448 sym = _T(";SY(LIGHTS12");
449 else if (strpbrk(buf, "\001\006\011"))
450 sym = _T(";SY(LIGHTS13");
451 }
452 else
453 {
454 // max 2 color
455 if ('\0' == buf[2]) {
456 if (strpbrk(buf, "\001") && strpbrk(buf, "\003"))
457 sym = _T(";SY(LIGHTS11");
458 else if (strpbrk(buf, "\001") && strpbrk(buf, "\004"))
459 sym = _T(";SY(LIGHTS12");
460 }
461 }
462 }
463
464 else // all-round fixed light symbolized as a circle, radius depends on color
465 // This treatment is seen on SeeMyDenc by SevenCs
466 // This may not be S-52 compliant....
467 {
468 // Another non-standard extension....
469 // All round light circle diameter is scaled if the light has a reasonable VALNMR attribute
470 int radius = 3;
471 if(valnmr > 0)
472 {
473 if(valnmr < 7.0)
474 radius = 3;
475 else if(valnmr < 15.0)
476 radius = 10;
477 else if(valnmr < 30.0)
478 radius = 15;
479 else
480 radius = 20;
481 }
482
483 // max 1 color
484 if ('\0' == buf[1])
485 {
486 if (strpbrk(buf, "\003"))
487 sym.Printf(_T(",LITRD, 2,0,360,%d,0"), radius + 1);
488 else if (strpbrk(buf, "\004"))
489 sym.Printf(_T(",LITGN, 2,0,360,%d,0"), radius);
490 else if (strpbrk(buf, "\001\006\011"))
491 sym.Printf(_T(",LITYW, 2,0,360,%d,0"), radius + 2);
492 else if (strpbrk(buf, "\014"))
493 sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 3);
494 else
495 sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5); // default
496
497 }
498 else if ('\0' == buf[2]) // or 2 color
499 {
500 if (strpbrk(buf, "\001") && strpbrk(buf, "\003"))
501 sym.Printf(_T(",LITRD, 2,0,360,%d,0"), radius + 1);
502 else if (strpbrk(buf, "\001") && strpbrk(buf, "\004"))
503 sym.Printf(_T(",LITGN, 2,0,360,%d,0"), radius);
504 else
505 sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5); // default
506
507 }
508 else
509 sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5);
510
511
512 if(sym.Len())
513 sym.Prepend(_T(";CA(OUTLW, 4"));
514 }
515
516
517 return sym;
518 }
519
_DEPVAL01(S57Obj * obj,double least_depth)520 static double _DEPVAL01(S57Obj *obj, double least_depth)
521 // Remarks: S-57 Appendix B1 Annex A requires in Section 6 that areas of rocks be
522 // encoded as area obstruction, and that area OBSTRNs and area WRECKS
523 // be covered by either group 1 object DEPARE or group 1 object UNSARE.
524 // If the value of the attribute VALSOU for an area OBSTRN or WRECKS
525 // is missing, the DRVAL1 of an underlying DEPARE is the preferred default
526 // for establishing a depth value. This procedure either finds the shallowest
527 // DRVAL1 of the one or more underlying DEPAREs, or returns an
528 // "unknown"" depth value to the main procedure for the next default
529 // procedure.
530
531 // NOTE: UNSARE test is useless since least_depth is already UNKNOWN
532 {
533 least_depth = UNKNOWN;
534
535 /*
536 S57_geo *geoTmp = geo;
537
538 // NOTE: the geo list is unchange (_UDWHAZ03 will unlink geo)
539 while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
540 GString *objlstr = S57_getAttVal(geoTmp, "OBJL");
541 int objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
542
543 // get area DEPARE that intersect this area
544 if (DEPARE==objl && LINES_T==S57_getObjtype(geo)) {
545 GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
546 double drval1 = (NULL == drval1str) ? 9.0 : atof(drval1str->str);
547
548 if (NULL != drval1str) {
549 if (UNKNOWN==least_depth || least_depth<drval1)
550 least_depth = drval1;
551 }
552
553 }
554 }
555 */
556 return least_depth;
557 }
558
_UDWHAZ03(S57Obj * obj,double depth_value,ObjRazRules * rzRules,bool * promote_return)559 static wxString *_UDWHAZ03(S57Obj *obj, double depth_value, ObjRazRules *rzRules, bool *promote_return)
560 // Remarks: Obstructions or isolated underwater dangers of depths less than the safety
561 // contour which lie within the safe waters defined by the safety contour are
562 // to be presented by a specific isolated danger symbol as hazardous objects
563 // and put in IMO category DISPLAYBASE (see (3), App.2, 1.3). This task
564 // is performed by this conditional symbology procedure.
565 {
566 wxString udwhaz03str;
567 int danger = FALSE;
568 int expsou = 0;
569 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
570 bool b_promote = false;
571
572 if(depth_value == UNKNOWN) {
573 GetIntAttr(obj, "EXPSOU", expsou);
574 if (expsou != 1)
575 danger = TRUE;
576 }
577 if (danger == FALSE && (expsou == 1 || depth_value <= safety_contour)) {
578 // that intersect this point/line/area for OBSTRN04
579 // that intersect this point/area for WRECKS02
580
581 // get area DEPARE & DRGARE that intersect this point/line/area
582
583 ListOfS57Obj *pobj_list = NULL;
584
585
586 if( obj->m_chart_context->chart )
587 pobj_list = obj->m_chart_context->chart->GetAssociatedObjects(obj);
588 else{
589 danger = false;
590 // wxString *ret_str = new wxString(udwhaz03str);
591 // return ret_str;
592 }
593
594
595 if( pobj_list ){
596 wxListOfS57ObjNode *node = pobj_list->GetFirst();
597 while(node)
598 {
599 S57Obj *ptest_obj = node->GetData();
600 if(GEO_LINE == ptest_obj->Primitive_type)
601 {
602 double drval2 = 0.0;
603 GetDoubleAttr(ptest_obj, "DRVAL2", drval2);
604
605 if(drval2 < safety_contour)
606 {
607 danger = TRUE;
608 break;
609 }
610 }
611 else
612 {
613 double drval1 = 0.0;
614 GetDoubleAttr(ptest_obj, "DRVAL1", drval1);
615
616 #if 0
617 double drval2 = 0.0;
618 GetDoubleAttr(ptest_obj, "DRVAL2", drval2);
619
620 if(expsou == 1 || depth_value < drval2 )
621 b_promote = true;
622 #endif
623
624 if(drval1 >= safety_contour && expsou != 1)
625 {
626 danger = TRUE;
627 break;
628 }
629 }
630 node = node->GetNext();
631 }
632
633 delete pobj_list;
634 }
635 }
636
637 if (TRUE == danger)
638 {
639 int watlev = 0; // Enum 0 invalid
640 GetIntAttr(obj, "WATLEV", watlev);
641
642 if((1 == watlev) || (2 == watlev))
643 {
644 // dry
645 // udwhaz03str = _T(";OP(--D14050)");
646 }
647 else
648 {
649 udwhaz03str = _T(";SY(ISODGR51)"); //_T(";OP(8OD14010);SY(ISODGR51)");
650 // S57_setAtt(geo, "SCAMIN", "INFINITE");
651 }
652
653 // Move this object to DisplayBase category
654 rzRules->obj->m_DisplayCat = DISPLAYBASE;
655
656 /*
657 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
658 if (NULL != watlevstr && ('1' == *watlevstr->str || '2' == *watlevstr->str))
659 udwhaz03str = g_string_new(";OP(--D14050");
660 else {
661 udwhaz03str = g_string_new(";OP(8OD14010);SY(ISODGR01)");
662 S57_setAtt(geo, "SCAMIN", "INFINITE");
663 }
664 */
665 }
666
667
668 if(promote_return)
669 *promote_return = b_promote;
670
671 wxString *ret_str = new wxString(udwhaz03str);
672 return ret_str;
673
674 }
675
676
677
678
679
680 // Remarks: An object of the class "depth area" is coloured and covered with fill patterns
681 // according to the mariners selections of shallow contour, safety contour and
682 // deep contour. This requires a decision making process based on DRVAL1 and DRVAL2.
683 // Objects of the class "dredged area" are handled by this routine as well to
684 // ensure a consistent symbolization of areas that represent the surface of the
685 // seabed.
686
DEPARE01(void * param)687 static void *DEPARE01(void *param)
688 {
689
690 ObjRazRules *rzRules = (ObjRazRules *)param;
691 S57Obj *obj = rzRules->obj;
692
693
694 double drval1, drval2;
695 bool drval1_found;
696
697 // Determine the color based on mariner selections
698
699
700 drval1 = -1.0; // default values
701 drval1_found = GetDoubleAttr(obj, "DRVAL1", drval1);
702 drval2 = drval1 + 0.01;
703 GetDoubleAttr(obj, "DRVAL2", drval2);
704
705
706
707
708 // Create a string of the proper color reference
709
710 wxString rule_str =_T("AC(DEPIT)");
711
712
713 if (drval1 >= 0.0 && drval2 > 0.0)
714 rule_str = _T("AC(DEPVS)");
715
716 if (TRUE == S52_getMarinerParam(S52_MAR_TWO_SHADES))
717 {
718 if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
719 drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
720 {
721 rule_str = _T("AC(DEPDW)");
722 }
723 }
724 else
725 {
726 if (drval1 >= S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) &&
727 drval2 > S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR))
728 rule_str = _T("AC(DEPMS)");
729
730 if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
731 drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
732 {
733 rule_str = _T("AC(DEPMD)");
734 }
735
736 if (drval1 >= S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) &&
737 drval2 > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR))
738 {
739 rule_str = _T("AC(DEPDW)");
740 }
741
742 }
743
744
745 // If object is DRGARE....
746
747 if(!strncmp(rzRules->LUP->OBCL, "DRGARE", 6))
748 {
749 if (!drval1_found) //If DRVAL1 was not defined...
750 {
751 rule_str = _T("AC(DEPMD)");
752 }
753 rule_str.Append(_T(";AP(DRGARE01)"));
754 rule_str.Append(_T(";LS(DASH,1,CHGRF)"));
755
756 // Todo Restrictions
757 /*
758 char pval[30];
759 if(true == GetStringAttr(obj, "RESTRN", pval, 20))
760 {
761 GString *rescsp01 = _RESCSP01(geo);
762 if (NULL != rescsp01)
763 {
764 g_string_append(depare01, rescsp01->str);
765 g_string_free(rescsp01, TRUE);
766 }
767 }
768 */
769 }
770
771
772 rule_str.Append('\037');
773
774 char *r = (char *)malloc(rule_str.Len() + 1);
775 strcpy(r, rule_str.mb_str());
776 return r;
777
778 }
779 /*
780 static void *DEPCNT02A(void *param)
781 {
782 // ObjRazRules *rzRules = (ObjRazRules *)param;
783 // S57Obj *obj = rzRules->obj;
784
785 // Add another rule onto the ruleList
786
787 Rules *r = NULL;
788
789 r = (Rules*)calloc(1, sizeof(Rules));
790 r->ruleType = RUL_SIM_LN;
791 r->INSTstr = "SOLD,1,DEPCN"; // points into the plib data space
792
793 return NULL;
794
795 }
796 */
797
DEPCNT02(void * param)798 static void *DEPCNT02 (void *param)
799 // Remarks: An object of the class "depth contour" or "line depth area" is highlighted and must
800 // be shown under all circumstances if it matches the safety contour depth value
801 // entered by the mariner (see IMO PS 3.6). But, while the mariner is free to enter any
802 // safety contour depth value that he thinks is suitable for the safety of his ship, the
803 // SENC only contains a limited choice of depth contours. This symbology procedure
804 // determines whether a contour matches the selected safety contour. If the selected
805 // safety contour does not exist in the data, the procedure will default to the next deeper
806 // contour. The contour selected is highlighted as the safety contour and put in
807 // DISPLAYBASE. The procedure also identifies any line segment of the spatial
808 // component of the object that has a "QUAPOS" value indicating unreliable
809 // positioning, and symbolizes it with a double dashed line.
810 //
811 // Note: Depth contours are not normally labeled. The ECDIS may provide labels, on demand
812 // only as with other text, or provide the depth value on cursor picking
813 {
814 // GString *depcnt02 = NULL;
815 // int safe = FALSE; // initialy not a safety contour
816 // GString *objlstr = NULL;
817 // int objl = 0;
818 // GString *quaposstr = NULL;
819 // int quapos = 0;
820 double drval1, drval2;
821 bool safe = FALSE;
822 wxString rule_str;
823 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
824
825 // objlstr = S57_getAttVal(geo, "OBJL");
826 // objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
827
828 ObjRazRules *rzRules = (ObjRazRules *)param;
829 S57Obj *obj = rzRules->obj;
830 // Debug
831 // if(obj->Index == 812)
832 // int tty = 5;
833
834 if ((!strncmp(obj->FeatureName, "DEPARE", 6)) && GEO_LINE==obj->Primitive_type)
835 {
836 drval1 = 0.0; // default values
837 GetDoubleAttr(obj, "DRVAL1", drval1);
838 drval2 = drval1;
839 GetDoubleAttr(obj, "DRVAL2", drval2);
840
841 // GString *drval1str = S57_getAttVal(geo, "DRVAL1");
842 // double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
843 // GString *drval2str = S57_getAttVal(geo, "DRVAL2");
844 // double drval2 = (NULL == drval2str) ? drval1 : atof(drval2str->str);
845
846 if (drval1 <= safety_contour)
847 {
848 if (drval2 >= safety_contour)
849 safe = TRUE;
850 }
851 else
852 {
853 double next_safe_contour = 1e6;
854 if( obj->m_chart_context->chart ){
855 next_safe_contour = obj->m_chart_context->chart->GetCalculatedSafetyContour();
856 if (drval1 == next_safe_contour)
857 safe = TRUE;
858 }
859 else {
860 next_safe_contour = obj->m_chart_context->safety_contour;
861
862 if (fabs(drval1 - next_safe_contour) < 1e-4)
863 safe = true;
864 }
865
866 // safe = FALSE; //for debug
867 /*
868 if (1 == S52_state)
869 return NULL;
870 else
871 {
872 S57_geo *geoTmp = geo;
873
874 // get area DEPARE & DRGARE that intersect this line
875 while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
876 drval1str = S57_getAttVal(geoTmp, "DRVAL1");
877 drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
878
879 if (NULL == drval1str) {
880 safe = TRUE;
881 break;
882 }
883
884 if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
885 safe = TRUE;
886 break;
887 }
888 }
889 // debug trace
890 //if (safe) PRINTF("** DEPARE: SAFE FOUND**\n");
891 }
892 */
893 }
894
895 }
896 else
897 {
898 // continuation A (DEPCNT)
899 double valdco = 0;
900 GetDoubleAttr(obj, "VALDCO", valdco);
901 // GString *valdcostr = S57_getAttVal(geo, "VALDCO");
902 // double valdco = (NULL == valdcostr) ? 0.0 : atof(valdcostr->str);
903
904 if (valdco == safety_contour)
905 safe = TRUE; // this is useless !?!?
906 else
907 {
908 double next_safe_contour = 1e6;
909 if( obj->m_chart_context->chart ){
910 next_safe_contour = obj->m_chart_context->chart->GetCalculatedSafetyContour();
911 if (valdco == next_safe_contour)
912 safe = TRUE;
913 }
914 else{
915 next_safe_contour = obj->m_chart_context->safety_contour;
916
917 if (fabs(valdco - next_safe_contour) < 1e-4)
918 safe = true;
919 }
920
921
922 /*
923 if (valdco > safety_contour)
924 {
925 safe = FALSE;
926 if (1 == S52_state)
927 return NULL;
928 else {
929 S57_geo *geoTmp = geo;
930
931 // get area DEPARE & DRGARE that intersect this line
932 while (NULL != (geoTmp = S57_nextObj(geoTmp))){
933 GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
934 double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
935
936 if (NULL == drval1str) {
937 safe = TRUE;
938 break;
939 }
940
941 if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
942 safe = TRUE;
943 break;
944 }
945 }
946 // debug trace
947 //if (safe) PRINTF("** DEPCN: SAFE FOUND**\n");
948 }
949
950 */
951 }
952 }
953
954 // Continuation B
955 int quapos = 0;
956 GetIntAttr(obj, "QUAPOS", quapos); // QUAPOS is an E (Enumerated) type attribute
957
958 if (0 != quapos) {
959 if ( 2 <= quapos && quapos < 10) {
960 if (safe) {
961 wxString safeCntr = _T("LS(DASH,2,DEPSC)");
962 S57Obj tempObj;
963 LUPrec* safelup = ps52plib->S52_LUPLookup( PLAIN_BOUNDARIES, "SAFECD", &tempObj, false );
964 if( safelup )
965 safeCntr = *safelup->INST;
966 rule_str = _T(";") + safeCntr;
967 }
968 else
969 rule_str = _T(";LS(DASH,1,DEPCN)");
970 }
971 } else {
972 if (safe) {
973 wxString safeCntr = _T("LS(SOLD,2,DEPSC)");
974 S57Obj tempObj;
975 LUPrec* safelup = ps52plib->S52_LUPLookup( PLAIN_BOUNDARIES, "SAFECN", &tempObj, false );
976 if( safelup )
977 safeCntr = *safelup->INST;
978 rule_str = _T(";") + safeCntr;
979 }
980 else
981 rule_str = _T(";LS(SOLD,1,DEPCN)");
982 }
983
984 if (safe) {
985 // S57_setAtt(geo, "SCAMIN", "INFINITE");
986 // rule_str.Prepend(_T(";OP(8OD13010)")); //depcnt02 = g_string_prepend(depcnt02, ";OP(8OD13010)");
987 // Move this object to DisplayBase category
988 rzRules->obj->m_DisplayCat = DISPLAYBASE;
989 rzRules->obj->Scamin = 1e8; // effectively no SCAMIN
990 // rzRules->LUP->DPRI = PRIO_HAZARDS;
991
992 } else {
993 // rule_str.Prepend(_T(";OP(---33020)")); //depcnt02 = g_string_prepend(depcnt02, ";OP(---33020)");
994 }
995 // facultative in S-52
996 //if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
997 // GString *sndfrm02 = _SNDFRM02(geo, depth_value);
998 // depcnt02 = g_string_append(depcnt02, sndfrm02->str);
999 // g_string_free(sndfrm02, TRUE);
1000 //}
1001
1002 // debug
1003 //PRINTF("depth= %f\n", depth_value);
1004
1005 // S57_unlinkObj(geo);
1006
1007 rule_str.Append('\037');
1008
1009 char *r = (char *)malloc(rule_str.Len() + 1);
1010 strcpy(r, rule_str.mb_str());
1011 return r;
1012
1013 // return depcnt02;
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
DEPVAL01(void * param)1026 static void *DEPVAL01(void *param)
1027 {
1028 ObjRazRules *rzRules = (ObjRazRules *)param;
1029 // S57Obj *obj = rzRules->obj;
1030
1031 printf("s52csny : DEPVAL01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
1032 return NULL;
1033 }
1034
LEGLIN02(void * param)1035 static void *LEGLIN02(void *param)
1036 {
1037 ObjRazRules *rzRules = (ObjRazRules *)param;
1038 // S57Obj *obj = rzRules->obj;
1039
1040 printf("s52csny : LEGLIN02 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
1041 return NULL;
1042 }
1043
1044 /*
1045 static void *LIGHTS04A(void *param)
1046 {
1047 ObjRazRules *rzRules = (ObjRazRules *)param;
1048 S57Obj *obj = rzRules->obj;
1049
1050 wxString rule_str;
1051
1052 char col_str[2];
1053 GetStringAttr(obj, "COLOUR", col_str, 1);
1054
1055 double height_val = 0;
1056 GetDoubleAttr(obj, "HEIGHT", height_val);
1057
1058 // if(obj->attList->Contains(wxString("HEIGHT")))
1059 // int uupr = 5;
1060
1061 // Different symbology depending upon Paper or Simplified Mariner Selection
1062
1063
1064 if(ps52plib->m_nSymbolStyle == PAPER_CHART)
1065 {
1066 if(col_str[0] == '3')
1067 { // red
1068 if(height_val)
1069 rule_str = _T("SY(LIGHTS93)"); // all round
1070 else
1071 rule_str = _T("SY(LIGHTS01)"); // flare
1072 }
1073
1074 else if(col_str[0] == '4') // green
1075 {
1076 if(height_val)
1077 rule_str = _T("SY(LIGHTS92)");
1078 else
1079 rule_str = _T("SY(LIGHTS02)");
1080 }
1081
1082 else // Generic, shows as yellow
1083 {
1084 if(height_val)
1085 rule_str = _T("SY(LIGHTS91)");
1086 else
1087 rule_str = _T("SY(LIGHTS03)");
1088 }
1089 }
1090
1091 else // must be Simplified
1092 {
1093 if(col_str[0] == '3')
1094 { // red
1095 if(height_val)
1096 rule_str = _T("SY(LIGHTS93)"); // all round
1097 else
1098 rule_str = _T("SY(LIGHTS01)"); // flare
1099 }
1100
1101 else if(col_str[0] == '4') // green
1102 {
1103 if(height_val)
1104 rule_str = _T("SY(LIGHTS92)");
1105 else
1106 rule_str = _T("SY(LIGHTS02)");
1107 }
1108
1109 else // Generic, shows as yellow
1110 {
1111 if(height_val)
1112 rule_str = _T("SY(LIGHTS91)");
1113 else
1114 rule_str = _T("SY(LIGHTS03)");
1115 }
1116 }
1117
1118
1119
1120 rule_str.Append('\037');
1121
1122 char *r = (char *)malloc(rule_str.Len() + 1);
1123 strcpy(r, rule_str.mb_str());
1124 return r;
1125 }
1126
1127 // A simple placeholder for Conditional Symbology method LIGHTS05
1128 static void *LIGHTS05A(void *param)
1129 {
1130 ObjRazRules *rzRules = (ObjRazRules *)param;
1131 S57Obj *obj = rzRules->obj;
1132
1133 wxString rule_str;
1134
1135 char col_str[2];
1136 GetStringAttr(obj, "COLOUR", col_str, 1);
1137
1138 double height_val = 0;
1139 GetDoubleAttr(obj, "HEIGHT", height_val);
1140
1141 if(col_str[0] == '3')
1142 { // red
1143 rule_str = _T("SY(LIGHTS11)"); // flare
1144 }
1145
1146 else if(col_str[0] == '4') // green
1147 rule_str = _T("SY(LIGHTS12)");
1148
1149 else // Generic, shows as yellow
1150 rule_str = _T("SY(LIGHTS13)");
1151
1152
1153
1154 rule_str.Append('\037');
1155
1156 char *r = (char *)malloc(rule_str.Len() + 1);
1157 strcpy(r, rule_str.mb_str());
1158 return r;
1159 }
1160 */
1161
1162 static wxString _LITDSN01(S57Obj *obj);
1163 static void *LIGHTS06 (void *param);
1164
LIGHTS05(void * param)1165 static void *LIGHTS05 (void *param)
1166 // Remarks: A light is one of the most complex S-57 objects. Its presentation depends on
1167 // whether it is a light on a floating or fixed platform, its range, it's colour and
1168 // so on. This conditional symbology procedure derives the correct
1169 // presentation from these parameters and also generates an area that shows the
1170 // coverage of the light.
1171 //
1172 // Notes on light sectors:
1173 // 1.) The radial leg-lines defining the light sectors are normally drawn to only 25mm
1174 // from the light to avoid clutter (see Part C). However, the mariner should be able to
1175 // select "full light-sector lines" and have the leg-lines extended to the nominal range
1176 // of the light (VALMAR).
1177 //
1178 // 2.) Part C of this procedure symbolizes the sectors at the light itself. In addition,
1179 // it should be possible, upon request, for the mariner to be capable of identifying
1180 // the colour and sector limit lines of the sectors affecting the ship even if the light
1181 // itself is off the display.
1182 // [ed. last sentence in bold]
1183
1184
1185 {
1186 // As transition, we use the PLIB 4.0 LIGHTS06 Procedure
1187 return LIGHTS06(param);
1188
1189
1190 #define UNKNOWN_DOUBLE -9;
1191 wxString lights05;
1192
1193 ObjRazRules *rzRules = (ObjRazRules *)param;
1194 S57Obj *obj = rzRules->obj;
1195
1196 double valnmr = UNKNOWN_DOUBLE;
1197 GetDoubleAttr(obj, "VALNMR", valnmr);
1198
1199
1200 char catlitstr[20] = {'\0'};
1201 GetStringAttr(obj, "CATLIT", catlitstr, 19);
1202
1203 char litvisstr[20] = {'\0'};;
1204 GetStringAttr(obj, "LITVIS", litvisstr, 19);
1205
1206
1207 char catlit[LISTSIZE] = {'\0'};
1208 char litvis[LISTSIZE] = {'\0'};
1209 char col_str[20] = {'\0'};
1210
1211 bool flare_at_45 = false;
1212 double sectr1 = UNKNOWN_DOUBLE;
1213 double sectr2 = UNKNOWN_DOUBLE;
1214 double sweep = 0.;
1215 char colist[LISTSIZE] = {'\0'}; // colour list
1216 bool b_isflare = false;
1217
1218 wxString orientstr;
1219
1220 if ( strlen(catlitstr))
1221 {
1222 _parseList(catlitstr, catlit, sizeof(colist));
1223
1224 // FIXME: OR vs AND/OR
1225 if (strpbrk(catlit, "\010\013")) {
1226 lights05.Append(_T(";SY(LIGHTS82)"));
1227 goto l05_end;
1228 }
1229
1230 if (strpbrk(catlit, "\011")) {
1231 lights05.Append(_T(";SY(LIGHTS81)"));
1232 goto l05_end;
1233 }
1234
1235 /*
1236 if (strpbrk(catlit, "\001\020")) {
1237 orientstr = S57_getAttVal(geo, "ORIENT");
1238 if (NULL != orientstr) {
1239 // FIXME: create a geo object (!?) LINE of lenght VALNMR
1240 // using ORIENT (from seaward) & POINT_T position
1241 g_string_append(lights05, ";LS(DASH,1,CHBLK)");
1242 }
1243 }
1244 */
1245 }
1246
1247 // Continuation A
1248
1249 GetStringAttr(obj, "COLOUR", col_str, 19);
1250
1251 if (strlen(col_str))
1252 _parseList(col_str, colist, sizeof(colist));
1253 else
1254 {
1255 colist[0] = '\014'; // magenta (12)
1256 colist[1] = '\000';
1257 }
1258
1259 GetDoubleAttr(obj, "SECTR1", sectr1);
1260 GetDoubleAttr(obj, "SECTR2", sectr2);
1261
1262
1263 if ((-9 == sectr1) || (-9 == sectr2))
1264 {
1265 // This is not a sector light
1266
1267 // What follows is one interpretation of the modern (3_3 +)
1268 // Presentation Library CS flow chart, which I(dsr) have never seen verbatim.
1269 // We will use flare light symbols for floating aids, and
1270 // all round sector lights for fixed aids.
1271
1272 wxString ssym;
1273
1274 if(_atPtPos(obj, GetChartFloatingATONArray( rzRules ), false)) // Is this LIGHTS feature colocated with ...ANY... floating aid?
1275 {
1276 flare_at_45 = false;
1277
1278 //TODO create LightArray in s57chart.
1279 // Then, if another LIGHT object is colocated here, set flare_at_45
1280 /* if(_atPtPos(obj, rzRules->chart->pLIGHTSArray, false)) // Is this LIGHTS feature colocated with another LIGHTS?
1281
1282
1283 // If the light is white, yellow, or orange, make it a flare at 45 degrees
1284 if(strpbrk(colist, "\001\005\011"))
1285 flare_at_45 = true;
1286 */
1287 ssym = _selSYcol(colist, 0, valnmr); // flare
1288 b_isflare = true;
1289 }
1290 else
1291 {
1292 ssym = _selSYcol(colist, 1, valnmr); // all round light
1293 b_isflare = false;
1294 }
1295
1296
1297 // Is the light a directional or moire?
1298 if (strpbrk(catlit, "\001\016"))
1299 {
1300 if (orientstr.Len())
1301 {
1302 lights05.Append(ssym);
1303 lights05.Append(orientstr);
1304 lights05.Append(_T(";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" ));
1305 }
1306 else
1307 lights05.Append(_T(";SY(QUESMRK1)"));
1308 }
1309 else
1310 {
1311 lights05.Append(ssym);
1312 if(b_isflare)
1313 {
1314 if (flare_at_45)
1315 lights05.Append(_T(",45)"));
1316 else
1317 lights05.Append(_T(",135)"));
1318 }
1319 }
1320
1321
1322 goto l05_end;
1323 }
1324
1325 // Continuation B --sector light
1326 if (-9 == sectr1)
1327 {
1328 sectr1 = 0.0;
1329 sectr2 = 0.0;
1330 }
1331 else
1332 sweep = (sectr1 > sectr2) ? sectr2-sectr1+360 : sectr2-sectr1;
1333
1334
1335 if (sweep<1.0 || sweep==360.0)
1336 {
1337 // handle all round light
1338 wxString ssym = _selSYcol(colist, 1, valnmr); // all round light
1339 lights05.Append(ssym);
1340
1341
1342 /*
1343 if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
1344 GString *litdsn01 = _LITDSN01(geo);
1345 if (NULL != litdsn01) {
1346 g_string_append(lights05, ";TX('");
1347 g_string_append(lights05, litdsn01->str);
1348 g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
1349 g_string_free(litdsn01, TRUE);
1350 }
1351
1352 }
1353 */
1354 goto l05_end;
1355 }
1356
1357 /*
1358 // scan for other lights with sector overlap at this position
1359 // compute light sector radius according to other sector
1360 if (1 == S52_state)
1361 {
1362 _setPtPos(geo, SECTRLIST);
1363 g_string_free(lights05, TRUE);
1364 return NULL;
1365 }
1366 else
1367 {
1368 extend_arc_radius = _atPtPos(geo, SECTRLIST);
1369
1370 // passe value via attribs to _renderAC
1371 if (extend_arc_radius)
1372 // FIXME: draw radius 25 mm
1373 S57_setAtt(geo, "extend_arc_radius", "Y");
1374 else
1375 // FIXME: draw radius 20 mm
1376 S57_setAtt(geo, "extend_arc_radius", "N");
1377 }
1378 */
1379 // setup sector
1380 {
1381 // Build the (opencpn private) command string like this:
1382 // e.g. ";CA(OUTLW, 4,LITRD, 2, sectr1, sectr2, radius)"
1383
1384
1385 double arc_radius = 20.; // mm
1386 double sector_radius = 25.;
1387
1388 // Another non-standard extension....
1389 // Sector light arc radius is scaled if the light has a reasonable VALNMR attribute
1390 if(valnmr > 0)
1391 {
1392 if(valnmr < 15.0)
1393 arc_radius = 10.;
1394 else if(valnmr < 30.0)
1395 arc_radius = 15.;
1396 else
1397 arc_radius = 20.;
1398 }
1399
1400 char sym[80];
1401 strcpy(sym,";CA(OUTLW, 4");
1402
1403
1404 // max 1 color
1405 if ('\0' == colist[1])
1406 {
1407 if (strpbrk(colist, "\003"))
1408 strcat(sym, ",LITRD, 2");
1409 else if (strpbrk(colist, "\004"))
1410 strcat(sym, ",LITGN, 2");
1411 else if (strpbrk(colist, "\001\006\013"))
1412 strcat(sym, ",LITYW, 2");
1413 else
1414 strcat(sym, ",CHMGD, 2"); // default is magenta
1415
1416 }
1417 else if ('\0' == colist[2])
1418 {
1419 if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
1420 strcat(sym, ",LITRD, 2");
1421 else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
1422 strcat(sym, ",LITGN, 2");
1423 else
1424 strcat(sym, ",CHMGD, 2"); // default is magenta
1425 }
1426 else
1427 strcat(sym, ",CHMGD, 2"); // default is magenta
1428
1429
1430 if ( strlen(litvisstr)) // Obscured/faint sector?
1431 {
1432 _parseList(litvisstr, litvis, sizeof(litvis));
1433
1434 if (strpbrk(litvis, "\003\007\010"))
1435 strcpy(sym, ";CA(CHBLK, 4,CHBRN, 1");
1436 }
1437
1438 if(sectr2 <= sectr1)
1439 sectr2 += 360;
1440
1441 // Sectors are defined from seaward
1442 if(sectr1 > 180)
1443 sectr1 -= 180;
1444 else
1445 sectr1 += 180;
1446
1447 if(sectr2 > 180)
1448 sectr2 -= 180;
1449 else
1450 sectr2 += 180;
1451
1452 char arc_data[80];
1453 sprintf(arc_data, ",%5.1f, %5.1f, %5.1f, %5.1f", sectr1, sectr2, arc_radius, sector_radius);
1454
1455 strcat(sym, arc_data);
1456
1457 wxString ssym(sym, wxConvUTF8);
1458 lights05 = ssym;
1459
1460 goto l05_end;
1461
1462
1463 }
1464
1465
1466 l05_end:
1467
1468 // if( ps52plib->m_bShowLdisText )
1469 {
1470 // Only show Light in certain position once. Otherwise there will be clutter.
1471 static double lastLat, lastLon;
1472 static wxString lastDescription;
1473 bool isFirstSector = true;
1474
1475 if( lastLat == obj->m_lat && lastLon == obj->m_lon ) isFirstSector = false;
1476 lastLat = obj->m_lat;
1477 lastLon = obj->m_lon;
1478
1479 wxString litdsn01 = _LITDSN01( obj );
1480
1481 if( litdsn01.Len() && isFirstSector ) {
1482 lastDescription = litdsn01;
1483 lights05.Append( _T(";TX('") );
1484 lights05.Append( litdsn01 );
1485
1486 if( flare_at_45 )
1487 lights05.Append( _T("',3,3,3,'15110',2,-1,CHBLK,23)" ) );
1488 else
1489 lights05.Append( _T("',3,2,3,'15110',2,0,CHBLK,23)" ) );
1490 }
1491
1492 if( !isFirstSector && lastDescription != litdsn01 ) {
1493 lastDescription = litdsn01;
1494 lights05.Append( _T(";TX('") );
1495 lights05.Append( litdsn01 );
1496 lights05.Append( _T("',3,2,3,'15110',2,1,CHBLK,23)" ) );
1497 }
1498 }
1499
1500 lights05.Append( '\037' );
1501
1502 char *r = (char *) malloc( lights05.Len() + 1 );
1503 strcpy( r, lights05.mb_str() );
1504
1505 return r;
1506 }
1507
1508
1509
LIGHTS06(void * param)1510 static void *LIGHTS06 (void *param)
1511 // Remarks: A light is one of the most complex S-57 objects. Its presentation depends on
1512 // whether it is a light on a floating or fixed platform, its range, it's colour and
1513 // so on. This conditional symbology procedure derives the correct
1514 // presentation from these parameters and also generates an area that shows the
1515 // coverage of the light.
1516 //
1517 // Notes on light sectors:
1518 // 1.) The radial leg-lines defining the light sectors are normally drawn to only 25mm
1519 // from the light to avoid clutter (see Part C). However, the mariner should be able to
1520 // select "full light-sector lines" and have the leg-lines extended to the nominal range
1521 // of the light (VALMAR).
1522 //
1523 // 2.) Part C of this procedure symbolizes the sectors at the light itself. In addition,
1524 // it should be possible, upon request, for the mariner to be capable of identifying
1525 // the colour and sector limit lines of the sectors affecting the ship even if the light
1526 // itself is off the display.
1527 // [ed. last sentence in bold]
1528
1529
1530 {
1531 #define UNKNOWN_DOUBLE -9;
1532 wxString lights06;
1533
1534 ObjRazRules *rzRules = (ObjRazRules *)param;
1535 S57Obj *obj = rzRules->obj;
1536
1537 double valnmr = 9.0;
1538 GetDoubleAttr(obj, "VALNMR", valnmr);
1539
1540
1541 char catlitstr[20] = {'\0'};
1542 GetStringAttr(obj, "CATLIT", catlitstr, 19);
1543
1544 char litvisstr[20] = {'\0'};;
1545 GetStringAttr(obj, "LITVIS", litvisstr, 19);
1546
1547
1548 char catlit[LISTSIZE] = {'\0'};
1549 char litvis[LISTSIZE] = {'\0'};
1550 char col_str[20] = {'\0'};
1551
1552 bool flare_at_45 = false;
1553 double sectr1 = UNKNOWN_DOUBLE;
1554 double sectr2 = UNKNOWN_DOUBLE;
1555 double sweep = 0.;
1556 char colist[LISTSIZE] = {'\0'}; // colour list
1557 bool b_isflare = false;
1558
1559 wxString orientstr;
1560
1561 if ( strlen(catlitstr))
1562 {
1563 _parseList(catlitstr, catlit, sizeof(colist));
1564
1565 if (strpbrk(catlit, "\010\013")) {
1566 lights06.Append(_T(";SY(LIGHTS82)"));
1567 goto l06_end;
1568 }
1569
1570 if (strpbrk(catlit, "\011")) {
1571 lights06.Append(_T(";SY(LIGHTS81)"));
1572 goto l06_end;
1573 }
1574
1575 /*
1576 * if (strpbrk(catlit, "\001\020")) {
1577 * orientstr = S57_getAttVal(geo, "ORIENT");
1578 * if (NULL != orientstr) {
1579 * // FIXME: create a geo object (!?) LINE of lenght VALNMR
1580 * // using ORIENT (from seaward) & POINT_T position
1581 * g_string_append(lights05, ";LS(DASH,1,CHBLK)");
1582 }
1583 }
1584 */
1585 }
1586
1587 // Continuation A
1588
1589 GetStringAttr(obj, "COLOUR", col_str, 19);
1590
1591 if (strlen(col_str))
1592 _parseList(col_str, colist, sizeof(colist));
1593 else
1594 {
1595 colist[0] = '\014'; // magenta (12)
1596 colist[1] = '\000';
1597 }
1598
1599 GetDoubleAttr(obj, "SECTR1", sectr1);
1600 GetDoubleAttr(obj, "SECTR2", sectr2);
1601
1602
1603 if ((-9 == sectr1) || (-9 == sectr2))
1604 {
1605 // This is not a sector light
1606
1607
1608 wxString ssym;
1609
1610 if(valnmr < 10.0){
1611
1612 //TODO create LightArray in s57chart.
1613 // Then, if another LIGHT object is colocated here, set flare_at_45
1614 /* if(_atPtPos(obj, rzRules->chart->pLIGHTSArray, false)) // Is this LIGHTS feature colocated with another LIGHTS?
1615 *
1616 *
1617 * // If the light is white, yellow, or orange, make it a flare at 45 degrees
1618 * if(strpbrk(colist, "\001\005\011"))
1619 * flare_at_45 = true;
1620 */
1621 ssym = _selSYcol(colist, 0, valnmr); // flare
1622 b_isflare = true;
1623 flare_at_45 = false;
1624 }
1625 else
1626 {
1627 ssym = _selSYcol(colist, 1, valnmr); // all round light
1628 b_isflare = false;
1629 }
1630
1631
1632 // Is the light a directional or moire?
1633 if (strpbrk(catlit, "\001\016"))
1634 {
1635 if (orientstr.Len())
1636 {
1637 lights06.Append(ssym);
1638 lights06.Append(orientstr);
1639 lights06.Append(_T(";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" ));
1640 }
1641 else
1642 lights06.Append(_T(";SY(QUESMRK1)"));
1643 }
1644 else
1645 {
1646 lights06.Append(ssym);
1647
1648 if(b_isflare)
1649 {
1650 if (flare_at_45)
1651 lights06.Append(_T(",45)"));
1652 else
1653 lights06.Append(_T(",135)"));
1654 }
1655 }
1656
1657
1658 goto l06_end;
1659 }
1660
1661 // Continuation B --sector light
1662 if (-9 == sectr1)
1663 {
1664 sectr1 = 0.0;
1665 sectr2 = 0.0;
1666 }
1667 else
1668 sweep = (sectr1 > sectr2) ? sectr2-sectr1+360 : sectr2-sectr1;
1669
1670
1671 if (sweep<1.0 || sweep==360.0)
1672 {
1673 // handle all round light
1674 wxString ssym = _selSYcol(colist, 1, valnmr); // all round light
1675 lights06.Append(ssym);
1676
1677
1678 /*
1679 * if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
1680 * GString *litdsn01 = _LITDSN01(geo);
1681 * if (NULL != litdsn01) {
1682 * g_string_append(lights05, ";TX('");
1683 * g_string_append(lights05, litdsn01->str);
1684 * g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
1685 * g_string_free(litdsn01, TRUE);
1686 }
1687
1688 }
1689 */
1690 goto l06_end;
1691 }
1692
1693 /*
1694 * // scan for other lights with sector overlap at this position
1695 * // compute light sector radius according to other sector
1696 * if (1 == S52_state)
1697 * {
1698 * _setPtPos(geo, SECTRLIST);
1699 * g_string_free(lights05, TRUE);
1700 * return NULL;
1701 }
1702 else
1703 {
1704 extend_arc_radius = _atPtPos(geo, SECTRLIST);
1705
1706 // passe value via attribs to _renderAC
1707 if (extend_arc_radius)
1708 // FIXME: draw radius 25 mm
1709 S57_setAtt(geo, "extend_arc_radius", "Y");
1710 else
1711 // FIXME: draw radius 20 mm
1712 S57_setAtt(geo, "extend_arc_radius", "N");
1713 }
1714 */
1715 // setup sector
1716 {
1717 // Build the (opencpn private) command string like this:
1718 // e.g. ";CA(OUTLW, 4,LITRD, 2, sectr1, sectr2, radius)"
1719
1720
1721 double arc_radius = 20.; // mm
1722 double sector_radius = 25.;
1723
1724 // Another non-standard extension....
1725 // Sector light arc radius is scaled if the light has a reasonable VALNMR attribute
1726 if(valnmr > 0)
1727 {
1728 if(valnmr < 15.0)
1729 arc_radius = 10.;
1730 else if(valnmr < 30.0)
1731 arc_radius = 15.;
1732 else
1733 arc_radius = 20.;
1734 }
1735
1736 char sym[80];
1737 strcpy(sym,";CA(OUTLW, 4");
1738
1739
1740 // max 1 color
1741 if ('\0' == colist[1])
1742 {
1743 if (strpbrk(colist, "\003"))
1744 strcat(sym, ",LITRD, 2");
1745 else if (strpbrk(colist, "\004"))
1746 strcat(sym, ",LITGN, 2");
1747 else if (strpbrk(colist, "\001\006\013"))
1748 strcat(sym, ",LITYW, 2");
1749 else
1750 strcat(sym, ",CHMGD, 2"); // default is magenta
1751
1752 }
1753 else if ('\0' == colist[2])
1754 {
1755 if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
1756 strcat(sym, ",LITRD, 2");
1757 else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
1758 strcat(sym, ",LITGN, 2");
1759 else
1760 strcat(sym, ",CHMGD, 2"); // default is magenta
1761 }
1762 else
1763 strcat(sym, ",CHMGD, 2"); // default is magenta
1764
1765
1766 if ( strlen(litvisstr)) // Obscured/faint sector?
1767 {
1768 _parseList(litvisstr, litvis, sizeof(litvis));
1769
1770 if (strpbrk(litvis, "\003\007\010"))
1771 strcpy(sym, ";CA(CHBLK, 4,CHBRN, 1");
1772 }
1773
1774 if(sectr2 <= sectr1)
1775 sectr2 += 360;
1776
1777 // Sectors are defined from seaward
1778 if(sectr1 > 180)
1779 sectr1 -= 180;
1780 else
1781 sectr1 += 180;
1782
1783 if(sectr2 > 180)
1784 sectr2 -= 180;
1785 else
1786 sectr2 += 180;
1787
1788 char arc_data[80];
1789 sprintf(arc_data, ",%5.1f, %5.1f, %5.1f, %5.1f", sectr1, sectr2, arc_radius, sector_radius);
1790
1791 strcat(sym, arc_data);
1792
1793 wxString ssym(sym, wxConvUTF8);
1794 lights06 = ssym;
1795
1796 goto l06_end;
1797
1798
1799 }
1800
1801
1802 l06_end:
1803
1804 // if( ps52plib->m_bShowLdisText )
1805 {
1806 // Only show Light in certain position once. Otherwise there will be clutter.
1807 static double lastLat, lastLon;
1808 static wxString lastDescription;
1809 bool isFirstSector = true;
1810
1811 if( lastLat == obj->m_lat && lastLon == obj->m_lon ) isFirstSector = false;
1812 lastLat = obj->m_lat;
1813 lastLon = obj->m_lon;
1814
1815 wxString litdsn01 = _LITDSN01( obj );
1816
1817 if( litdsn01.Len() && isFirstSector ) {
1818 lastDescription = litdsn01;
1819 lights06.Append( _T(";TX('") );
1820 lights06.Append( litdsn01 );
1821
1822 if( flare_at_45 )
1823 lights06.Append( _T("',3,3,3,'15110',2,-1,CHBLK,23)" ) );
1824 else
1825 lights06.Append( _T("',3,2,3,'15110',2,0,CHBLK,23)" ) );
1826 }
1827
1828 if( !isFirstSector && lastDescription != litdsn01 ) {
1829 lastDescription = litdsn01;
1830 lights06.Append( _T(";TX('") );
1831 lights06.Append( litdsn01 );
1832 lights06.Append( _T("',3,2,3,'15110',2,1,CHBLK,23)" ) );
1833 }
1834 }
1835
1836 lights06.Append( '\037' );
1837
1838 char *r = (char *) malloc( lights06.Len() + 1 );
1839 strcpy( r, lights06.mb_str() );
1840
1841 return r;
1842 }
1843
1844
1845
1846
LITDSN01(void * param)1847 static void *LITDSN01(void *param)
1848 {
1849 ObjRazRules *rzRules = (ObjRazRules *)param;
1850 // S57Obj *obj = rzRules->obj;
1851
1852 printf("s52csny : LITDSN01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
1853 return NULL;
1854 }
1855
1856 /*
1857 static void *OBSTRN04a(void *param)
1858 {
1859 ObjRazRules *rzRules = (ObjRazRules *)param;
1860 // S57Obj *obj = rzRules->obj;
1861
1862 static int f03;
1863 if(!f03)
1864 printf("s52csny : OBSTRN04 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
1865 f03++;
1866 return NULL;
1867 }
1868 */
1869
1870 wxString SNDFRM02(S57Obj *obj, double depth_value);
1871
OBSTRN04(void * param)1872 static void *OBSTRN04 (void *param)
1873 // Remarks: Obstructions or isolated underwater dangers of depths less than the safety
1874 // contour which lie within the safe waters defined by the safety contour are
1875 // to be presented by a specific isolated danger symbol and put in IMO
1876 // category DISPLAYBASE (see (3), App.2, 1.3). This task is performed
1877 // by the sub-procedure "UDWHAZ03" which is called by this symbology
1878 // procedure. Objects of the class "under water rock" are handled by this
1879 // routine as well to ensure a consistent symbolization of isolated dangers on
1880 // the seabed.
1881 {
1882 wxString obstrn04str;
1883 // GString *sndfrm02str = NULL;
1884 wxString *udwhaz03str = NULL;
1885 // GString *valsoustr = S57_getAttVal(geo, "VALSOU");
1886 bool b_promote = false;
1887
1888 ObjRazRules *rzRules = (ObjRazRules *)param;
1889 S57Obj *obj = rzRules->obj;
1890
1891 //TODO Debug Hook
1892 // if(obj->Index == 534)
1893 // int yyp = 5;
1894
1895 double valsou = UNKNOWN;
1896 double depth_value = UNKNOWN;
1897 double least_depth = UNKNOWN;
1898
1899
1900 wxString sndfrm02str;
1901 wxString *quapnt01str = NULL;
1902
1903 GetDoubleAttr(obj, "VALSOU", valsou);
1904 wxString *objName = GetStringAttrWXS(obj, "OBJNAM");
1905
1906 if (valsou != UNKNOWN)
1907 {
1908 depth_value = valsou;
1909 sndfrm02str = SNDFRM02(obj, valsou);
1910 }
1911 else
1912 {
1913 if (GEO_AREA == obj->Primitive_type)
1914 least_depth = _DEPVAL01(obj, least_depth);
1915
1916 if (UNKNOWN == least_depth)
1917 {
1918 int catobs = 0;
1919 GetIntAttr(obj, "CATOBS", catobs);
1920 int watlev = 0;
1921 GetIntAttr(obj, "WATLEV", watlev);
1922 int expsou = 0;
1923 GetIntAttr(obj, "EXPSOU", expsou);
1924 if (expsou != 1) {
1925 if (6 == catobs)
1926 depth_value = 0.01;
1927 else if (0 == watlev) // default
1928 depth_value = -15.0;
1929 else
1930 {
1931 switch (watlev){
1932 case 5: depth_value = 0.0 ; break;
1933 case 3: depth_value = 0.01; break;
1934 case 4:
1935 case 1:
1936 case 2:
1937 default : depth_value = -15.0 ; break;
1938 }
1939 }
1940 }
1941 }
1942 else
1943 depth_value = least_depth;
1944 }
1945
1946 udwhaz03str = _UDWHAZ03(obj, depth_value, rzRules, &b_promote);
1947
1948
1949 if (GEO_POINT == obj->Primitive_type)
1950 {
1951 // Continuation A
1952 int sounding = FALSE;
1953 quapnt01str = CSQUAPNT01(obj);
1954
1955 if (0 != udwhaz03str->Len())
1956 {
1957 obstrn04str.Append(*udwhaz03str);
1958 obstrn04str.Append(*quapnt01str);
1959
1960 goto end;
1961 }
1962
1963 if (UNKNOWN != valsou)
1964 {
1965 if (valsou <= 20.0)
1966 {
1967 int watlev = -9;
1968 GetIntAttr(obj, "WATLEV", watlev);
1969
1970 if (!strncmp(obj->FeatureName, "UWTROC", 6))
1971 {
1972 if (-9 == watlev) { // default
1973 obstrn04str.Append(_T(";SY(DANGER51)"));
1974 sounding = TRUE;
1975 } else {
1976 switch (watlev){
1977 case 3: obstrn04str.Append(_T(";SY(DANGER51)")); sounding = TRUE ; break;
1978 case 4:
1979 case 5: obstrn04str.Append(_T(";SY(UWTROC04)")); sounding = FALSE; break;
1980 default : obstrn04str.Append(_T(";SY(DANGER51)")); sounding = TRUE ; break;
1981 }
1982 }
1983 if(b_promote){
1984 // Move this UWTROC object to DisplayBase category
1985 rzRules->obj->m_DisplayCat = DISPLAYBASE;
1986 }
1987 }
1988 else
1989 { // OBSTRN
1990 if (-9 == watlev) { // default
1991 obstrn04str.Append(_T(";SY(DANGER01)"));
1992 sounding = TRUE;
1993 } else {
1994 switch (watlev) {
1995 case 1:
1996 case 2: obstrn04str.Append(_T(";SY(LNDARE01)")); sounding = FALSE; break;
1997 case 3: obstrn04str.Append(_T(";SY(DANGER52)")); sounding = TRUE; break;
1998 case 4:
1999 case 5: obstrn04str.Append(_T(";SY(DANGER53)")); sounding = TRUE; break;
2000 default : obstrn04str.Append(_T(";SY(DANGER51)")); sounding = TRUE; break;
2001 }
2002 }
2003 }
2004 }
2005 else
2006 { // valsou > 20.0
2007 obstrn04str.Append(_T(";SY(DANGER52)"));
2008 sounding = TRUE;
2009 }
2010 }
2011 else
2012 { // NO valsou
2013 // GString *objlstr = S57_getAttVal(geo, "OBJL");
2014 // int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
2015 int watlev = -9;
2016 GetIntAttr(obj, "WATLEV", watlev);
2017 // GString *watlevstr = S57_getAttVal(geo, "WATLEV");
2018
2019 if (!strncmp(obj->FeatureName, "UWTROC", 6))
2020 {
2021 if (watlev == -9) // default
2022 obstrn04str.Append(_T(";SY(UWTROC04)"));
2023 else {
2024 switch (watlev) {
2025 case 2: obstrn04str.Append(_T(";SY(LNDARE01)")); break;
2026 case 3: obstrn04str.Append(_T(";SY(UWTROC03)")); break;
2027 default: obstrn04str.Append(_T(";SY(UWTROC04)")); break;
2028 }
2029 }
2030
2031 if(b_promote){
2032 // Move this UWTROC object to DisplayBase category
2033 rzRules->obj->m_DisplayCat = DISPLAYBASE;
2034 }
2035 }
2036 else
2037 { // OBSTRN
2038 if ( -9 == watlev) // default
2039 obstrn04str = _T(";SY(OBSTRN01)");
2040 else
2041 {
2042 switch (watlev) {
2043 case 1: obstrn04str.Append(_T(";SY(OBSTRN11)")); break;
2044 case 2: obstrn04str.Append(_T(";SY(OBSTRN11)")); break;
2045 case 3: obstrn04str.Append(_T(";SY(OBSTRN01)")); break;
2046 case 4: obstrn04str.Append(_T(";SY(OBSTRN03)")); break;
2047 case 5: obstrn04str.Append(_T(";SY(OBSTRN03)")); break;
2048 default : obstrn04str.Append(_T(";SY(OBSTRN01)")); break;
2049 }
2050 }
2051 }
2052 }
2053
2054 if (sounding)
2055 obstrn04str.Append(sndfrm02str);
2056
2057 obstrn04str.Append(*quapnt01str);
2058
2059 goto end;
2060
2061 } // if geopoint
2062 else
2063 {
2064 if (GEO_LINE == obj->Primitive_type)
2065 {
2066 // Continuation B
2067
2068 quapnt01str = CSQUAPNT01(obj);
2069
2070 if( quapnt01str->Len() > 1 ) {
2071 long quapos;
2072 quapnt01str->ToLong(&quapos);
2073 if ( 2 <= quapos && quapos < 10){
2074 if (udwhaz03str->Len())
2075 obstrn04str.Append(_T(";LC(LOWACC41)"));
2076 else
2077 obstrn04str.Append(_T(";LC(LOWACC31)"));
2078 }
2079 goto end;
2080 }
2081
2082 if ( udwhaz03str->Len() )
2083 {
2084 obstrn04str.Append( _T("LS(DOTT,2,CHBLK)") );
2085 goto end;
2086 }
2087
2088 if (UNKNOWN != valsou){
2089 if (valsou <= 20.0)
2090 obstrn04str.Append( _T(";LS(DOTT,2,CHBLK)") );
2091 else
2092 obstrn04str.Append( _T(";LS(DASH,2,CHBLK)") );
2093 }
2094 else
2095 obstrn04str.Append( _T(";LS(DOTT,2,CHBLK)") );
2096
2097
2098 if (udwhaz03str->Len()){
2099 // Show the isolated danger symbol at the midpoint of the line
2100 }
2101 else {
2102 if (UNKNOWN != valsou)
2103 if (valsou <= 20.0)
2104 obstrn04str.Append(sndfrm02str);
2105 }
2106 }
2107
2108 else // Area feature
2109 {
2110 quapnt01str = CSQUAPNT01(obj);
2111
2112 if (0 != udwhaz03str->Len())
2113 {
2114 obstrn04str.Append(_T(";AC(DEPVS);AP(FOULAR01)"));
2115 obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
2116 obstrn04str.Append(*udwhaz03str);
2117 obstrn04str.Append(*quapnt01str);
2118
2119 goto end;
2120 }
2121
2122 if (UNKNOWN != valsou) {
2123 // BUG in CA49995B.000 if we get here because there is no color
2124 // beside NODATA (ie there is a hole in group 1 area!)
2125 //g_string_append(obstrn04, ";AC(UINFR)");
2126
2127 if (valsou <= 20.0)
2128 obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
2129 else
2130 obstrn04str.Append(_T(";LS(DASH,2,CHBLK)"));
2131
2132 obstrn04str.Append(sndfrm02str);
2133
2134 } else {
2135 int watlev = -9;
2136 GetIntAttr(obj, "WATLEV", watlev);
2137 // GString *watlevstr = S57_getAttVal(geo, "WATLEV");
2138
2139 if (watlev == -9) // default
2140 obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)"));
2141 else {
2142 switch (watlev) {
2143 case 1:
2144 case 2: obstrn04str.Append(_T(";AC(CHBRN);LS(SOLD,2,CSTLN)")); break;
2145 case 4: obstrn04str.Append(_T(";AC(DEPIT);LS(DASH,2,CSTLN)")); break;
2146 case 5:
2147 case 3:
2148 {
2149 int catobs = -9;
2150 GetIntAttr(obj, "CATOBS", catobs);
2151 if (6 == catobs)
2152 obstrn04str.Append(_T(";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)"));
2153 else
2154 obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)"));
2155 }
2156 break;
2157 default: obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)")); break;
2158 }
2159 }
2160 }
2161 obstrn04str.Append(*quapnt01str);
2162 goto end;
2163
2164 /*
2165 // Continuation C (AREAS_T)
2166 GString *quapnt01str = CSQUAPNT01(geo);
2167 if (NULL != udwhaz03str) {
2168 g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01)");
2169 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
2170 g_string_append(obstrn04str, udwhaz03str->str);
2171 if (NULL != quapnt01str)
2172 g_string_append(obstrn04str, quapnt01str->str);
2173
2174 return obstrn04str;
2175 }
2176
2177 if (UNKNOWN != valsou) {
2178 // BUG in CA49995B.000 if we get here because there is no color
2179 // beside NODATA (ie there is a hole in group 1 area!)
2180 //g_string_append(obstrn04, ";AC(UINFR)");
2181
2182 if (valsou <= 20.0)
2183 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
2184 else
2185 g_string_append(obstrn04str, ";LS(DASH,2,CHBLK)");
2186
2187 g_string_append(obstrn04str, sndfrm02str->str);
2188
2189 } else {
2190 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
2191
2192 if (NULL == watlevstr) // default
2193 g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)");
2194 else {
2195 if ('3' == *watlevstr->str) {
2196 GString *catobsstr = S57_getAttVal(geo, "CATOBS");
2197 if (NULL != catobsstr && '6' == *catobsstr->str)
2198 g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)");
2199 } else {
2200 switch (*watlevstr->str) {
2201 case '1':
2202 case '2': g_string_append(obstrn04str, ";AC(CHBRN);LS(SOLD,2,CSTLN)"); break;
2203 case '4': g_string_append(obstrn04str, ";AC(DEPIT);LS(DASH,2,CSTLN)"); break;
2204 case '5':
2205 case '3':
2206 default : g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)"); break;
2207 }
2208 }
2209 }
2210 }
2211
2212 g_string_append(obstrn04str, quapnt01str->str);
2213
2214 return obstrn04str;
2215 */
2216 } // area
2217 }
2218
2219 end:
2220
2221 // This is a specialization, to print OBJNAM for obstructions, if available
2222 // Seen in NZ ENCs, e.g. "Horn Rock"
2223 if(objName)
2224 obstrn04str.Append(_T(";TX(OBJNAM,1,2,3,'15118',-1,-1,CHBLK,26)"));
2225
2226 obstrn04str.Append('\037');
2227
2228 char *r = (char *)malloc(obstrn04str.Len() + 1);
2229 strcpy(r, obstrn04str.mb_str());
2230
2231 delete udwhaz03str;
2232 delete quapnt01str;
2233
2234 return r;
2235 }
2236
2237
2238
OWNSHP02(void * param)2239 static void *OWNSHP02(void *param)
2240 {
2241 ObjRazRules *rzRules = (ObjRazRules *)param;
2242 // S57Obj *obj = rzRules->obj;
2243
2244 printf("s52csny : OWNSHP02 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
2245 return NULL;
2246 }
2247
PASTRK01(void * param)2248 static void *PASTRK01(void *param)
2249 {
2250 ObjRazRules *rzRules = (ObjRazRules *)param;
2251 // S57Obj *obj = rzRules->obj;
2252
2253 printf("s52csny : PASTRK01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
2254 return NULL;
2255 }
2256
2257 static void *QUALIN01(void *param);
2258 static void *QUAPNT01(void *param);
2259
QUAPOS01(void * param)2260 static void *QUAPOS01(void *param)
2261 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
2262 // to the spatial object, not the feature object.
2263 // In OpenCPN implementation, QUAPOS of Point Objects has been converted to
2264 // QUALTY attribute of object.
2265 //
2266 // This procedure passes the object to procedure QUALIN01 or QUAPNT01,
2267 // which traces back to the spatial object, retrieves any QUAPOS attributes,
2268 // and returns the appropriate symbolization to QUAPOS01.
2269 {
2270 ObjRazRules *rzRules = (ObjRazRules *)param;
2271 S57Obj *obj = rzRules->obj;
2272
2273 wxString *q = NULL;
2274
2275 if (GEO_LINE == obj->Primitive_type)
2276 q = CSQUALIN01(obj);
2277
2278 else
2279 q = CSQUAPNT01(obj);
2280
2281 char *r = (char *)malloc(q->Len() + 1);
2282 strcpy(r, q->mb_str());
2283
2284 delete q;
2285
2286 return r;
2287
2288 }
2289
QUALIN01(void * param)2290 static void *QUALIN01(void *param)
2291 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
2292 // only to the spatial component(s) of an object.
2293 //
2294 // A line object may be composed of more than one spatial object.
2295 //
2296 // This procedure looks at each of the spatial
2297 // objects, and symbolizes the line according to the positional accuracy.
2298 {
2299 ObjRazRules *rzRules = (ObjRazRules *)param;
2300 S57Obj *obj = rzRules->obj;
2301
2302 wxString *q = CSQUALIN01(obj);
2303 char *r = (char *)malloc(q->Len() + 1);
2304 strcpy(r, q->mb_str());
2305
2306 delete q;
2307 return r;
2308 }
2309
CSQUALIN01(S57Obj * obj)2310 wxString *CSQUALIN01(S57Obj *obj)
2311 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
2312 // only to the spatial component(s) of an object.
2313 //
2314 // A line object may be composed of more than one spatial object.
2315 //
2316 // This procedure looks at each of the spatial
2317 // objects, and symbolizes the line according to the positional accuracy.
2318 {
2319 wxString qualino1;
2320 int quapos = 0;
2321 bool bquapos = GetIntAttr(obj, "QUAPOS", quapos);
2322 const char *line = NULL;
2323
2324 if (bquapos) {
2325 if ( 2 <= quapos && quapos < 10)
2326 line = "LC(LOWACC21)";
2327 } else {
2328 if (!strncmp("COALNE", obj->FeatureName, 6)) {
2329 int conrad;
2330 bool bconrad = GetIntAttr(obj, "CONRAD", conrad);
2331
2332 if (bconrad) {
2333 if (1 == conrad)
2334 line = "LS(SOLD,3,CHMGF);LS(SOLD,1,CSTLN)";
2335 else
2336 line = "LS(SOLD,1,CSTLN)";
2337 } else
2338 line = "LS(SOLD,1,CSTLN)";
2339
2340 } else //LNDARE
2341 line = "LS(SOLD,1,CSTLN)";
2342 }
2343
2344 if (NULL != line)
2345 qualino1.Append(wxString(line, wxConvUTF8));
2346
2347 qualino1.Append('\037');
2348
2349 wxString *r = new wxString(qualino1);
2350
2351 /* char *r = (char *)malloc(qualino1.Len() + 1);
2352 strcpy(r, qualino1.mb_str());
2353 */
2354 return r;
2355 }
2356
2357
2358
QUAPNT01(void * param)2359 static void *QUAPNT01(void *param)
2360 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
2361 // only to the spatial component(s) of an object.
2362 //
2363 // This procedure retrieves any QUALTY (ne QUAPOS) attributes, and returns the
2364 // appropriate symbols to the calling procedure.
2365
2366 {
2367 ObjRazRules *rzRules = (ObjRazRules *)param;
2368 S57Obj *obj = rzRules->obj;
2369
2370 wxString *q = CSQUAPNT01(obj);
2371
2372 char *r = (char *)malloc(q->Len() + 1);
2373 strcpy(r, q->mb_str());
2374
2375 return r;
2376 }
2377
CSQUAPNT01(S57Obj * obj)2378 wxString *CSQUAPNT01(S57Obj *obj)
2379 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
2380 // only to the spatial component(s) of an object.
2381 //
2382 // This procedure retrieves any QUALTY (ne QUAPOS) attributes, and returns the
2383 // appropriate symbols to the calling procedure.
2384
2385 {
2386 wxString quapnt01;
2387 int accurate = TRUE;
2388 int qualty = 10;
2389 bool bquapos = GetIntAttr(obj, "QUAPOS", qualty);
2390
2391 if (bquapos) {
2392 if ( 2 <= qualty && qualty < 10)
2393 accurate = FALSE;
2394 }
2395
2396 if (!accurate)
2397 {
2398 switch(qualty)
2399 {
2400 case 4:
2401 quapnt01.Append(_T(";SY(QUAPOS01)")); break; // "PA"
2402 case 5:
2403 quapnt01.Append(_T(";SY(QUAPOS02)")); break; // "PD"
2404 case 7:
2405 case 8:
2406 quapnt01.Append(_T(";SY(QUAPOS03)")); break; // "REP"
2407 default:
2408 quapnt01.Append(_T(";SY(LOWACC03)")); break; // "?"
2409 }
2410 }
2411
2412 quapnt01.Append('\037');
2413
2414 wxString *r = new wxString;
2415
2416 *r = quapnt01;
2417
2418 /* char *r = (char *)malloc(quapnt01.Len() + 1);
2419 strcpy(r, quapnt01.mb_str());
2420 */
2421 return r;
2422 }
2423
SLCONS03(void * param)2424 static void *SLCONS03(void *param)
2425
2426 // Remarks: Shoreline construction objects which have a QUAPOS attribute on their
2427 // spatial component indicating that their position is unreliable are symbolized
2428 // by a special linestyle in the place of the varied linestyles normally used.
2429 // Otherwise this procedure applies the normal symbolization.
2430 {
2431 ObjRazRules *rzRules = (ObjRazRules *)param;
2432 S57Obj *obj = rzRules->obj;
2433
2434
2435 wxString slcons03;
2436
2437 bool bvalstr;
2438 int ival;
2439
2440 const char *cmdw = NULL; // command word
2441
2442 int quapos;
2443 bool bquapos = GetIntAttr(obj, "QUAPOS", quapos);
2444
2445
2446 if (GEO_POINT == obj->Primitive_type) {
2447 if (bquapos) {
2448 if (2 <= quapos && quapos < 10)
2449 cmdw ="SY(LOWACC01)";
2450 }
2451 } else {
2452
2453 // This instruction not found in PLIB 3.4, but seems to appear in later PLIB implementations
2454 // by commercial ECDIS providers, so.....
2455 if (GEO_AREA == obj->Primitive_type) {
2456 slcons03 = _T("AP(CROSSX01);");
2457 }
2458
2459 // GEO_LINE and GEO_AREA are the same
2460 if (bquapos) {
2461 if (2 <= quapos && quapos < 10)
2462 cmdw ="LC(LOWACC01)";
2463 } else {
2464 bvalstr = GetIntAttr(obj, "CONDTN", ival);
2465
2466 if (bvalstr && ( 1 == ival || 2 == ival))
2467 cmdw = "LS(DASH,1,CSTLN)";
2468 else {
2469 ival = 0;
2470 bvalstr = GetIntAttr(obj, "CATSLC", ival);
2471
2472 if (bvalstr && ( 6 == ival || 15 == ival || 16 == ival )) // Some sort of wharf
2473 cmdw = "LS(SOLD,4,CSTLN)";
2474 else {
2475 bvalstr = GetIntAttr(obj, "WATLEV", ival);
2476
2477 if (bvalstr && 2 == ival)
2478 cmdw = "LS(SOLD,2,CSTLN)";
2479 else
2480 if (bvalstr && (3 == ival || 4 == ival))
2481 cmdw = "LS(DASH,2,CSTLN)";
2482 else
2483 cmdw = "LS(SOLD,2,CSTLN)"; // default
2484
2485 }
2486 }
2487 }
2488 }
2489
2490
2491
2492 // WARNING: not explicitly specified in S-52 !!
2493 // FIXME:this is to put AC(DEPIT) --intertidal area
2494 // Could this be bug in OGR ?
2495 /*
2496 if (AREAS_T == S57_getObjtype(geo)) {
2497 GString *seabed01 = NULL;
2498 GString *drval1str = S57_getAttVal(geo, "DRVAL1");
2499 double drval1 = (NULL == drval1str)? -UNKNOWN : atof(drval1str->str);
2500 GString *drval2str = S57_getAttVal(geo, "DRVAL2");
2501 double drval2 = (NULL == drval2str)? -UNKNOWN : atof(drval2str->str);
2502 // NOTE: change sign of infinity (minus) to get out of bound in seabed01
2503
2504
2505 PRINTF("***********drval1=%f drval2=%f \n", drval1, drval2);
2506 seabed01 = _SEABED01(drval1, drval2);
2507 slcons03 = g_string_new(seabed01->str);
2508 g_string_free(seabed01, TRUE);
2509
2510 }
2511 */
2512
2513 if (NULL != cmdw)
2514 slcons03.Append(wxString(cmdw, wxConvUTF8));
2515
2516 // Match CM93 CMAPECS presentation?
2517 /*
2518 if (GEO_AREA == obj->Primitive_type)
2519 slcons03.Append(_T(";AC(LANDA)"));
2520 */
2521
2522 slcons03.Append('\037');
2523
2524 char *r = (char *)malloc(slcons03.Len() + 1);
2525 strcpy(r, slcons03.mb_str());
2526
2527
2528 return r;
2529
2530
2531 }
2532
RESARE02(void * param)2533 static void *RESARE02(void *param)
2534 // Remarks: A list-type attribute is used because an area of the object class RESARE may
2535 // have more than one category (CATREA). For example an inshore traffic
2536 // zone might also have fishing and anchoring prohibition and a prohibited
2537 // area might also be a bird sanctuary or a mine field.
2538 //
2539 // This conditional procedure is set up to ensure that the categories of most
2540 // importance to safe navigation are prominently symbolized, and to pass on
2541 // all given information with minimum clutter. Only the most significant
2542 // restriction is symbolized, and an indication of further limitations is given by
2543 // a subscript "!" or "I". Further details are given under conditional
2544 // symbology procedure RESTRN01
2545 //
2546 // Other object classes affected by attribute RESTRN are handled by
2547 // conditional symbology procedure RESTRN01.
2548 {
2549 ObjRazRules *rzRules = (ObjRazRules *)param;
2550 S57Obj *obj = rzRules->obj;
2551
2552
2553 wxString resare02;
2554
2555 wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
2556 // GString *restrnstr = S57_getAttVal(geo, "RESTRN");
2557
2558
2559 char restrn[LISTSIZE] = {'\0'};
2560 // GString *catreastr = S57_getAttVal(geo, "CATREA");
2561 wxString *catreastr = GetStringAttrWXS(obj, "CATREA");
2562
2563 char catrea[LISTSIZE] = {'\0'};
2564 wxString symb;
2565 wxString line;
2566 wxString prio;
2567
2568 if (NULL != catreastr)
2569 _parseList(catreastr->mb_str(), catrea, sizeof(catrea));
2570
2571 if ( NULL != restrnstr) {
2572 _parseList(restrnstr->mb_str(), restrn, sizeof(restrn));
2573
2574
2575 if (strpbrk(restrn, "\007\010\016")) { // entry restrictions
2576 // Continuation A
2577 if (strpbrk(restrn, "\001\002\003\004\005\006")) // anchoring, fishing, trawling
2578 symb = _T(";SY(ENTRES61)");
2579 else {
2580 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
2581 symb = _T(";SY(ENTRES61)");
2582 else {
2583 if (strpbrk(restrn, "\011\012\013\014\015"))
2584 symb = _T(";SY(ENTRES71)");
2585 else {
2586 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
2587 symb = _T(";SY(ENTRES71)");
2588 else
2589 symb = _T(";SY(ENTRES51)");
2590 }
2591 }
2592 }
2593
2594 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
2595 line = _T(";LC(RESARE51)");
2596 else
2597 line =_T( ";LS(DASH,2,CHMGD)");
2598
2599 prio = _T(";OP(6---)"); // display prio set to 6
2600
2601 } else {
2602 if (strpbrk(restrn, "\001\002")) { // anchoring
2603 // Continuation B
2604 if (strpbrk(restrn, "\003\004\005\006"))
2605 symb = _T(";SY(ACHRES61)");
2606 else {
2607 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
2608 symb = _T(";SY(ACHRES61)");
2609 else {
2610 if (strpbrk(restrn, "\011\012\013\014\015"))
2611 symb = _T(";SY(ACHRES71)");
2612 else {
2613 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
2614 symb =_T( ";SY(ACHRES71)");
2615 else
2616 symb = _T(";SY(RESTRN51)");
2617 }
2618 }
2619 }
2620
2621 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
2622 line = _T(";LC(RESARE51)"); // could be ACHRES51 when _drawLC is implemented fully
2623 else
2624 line = _T(";LS(DASH,2,CHMGD)");
2625
2626 prio = _T(";OP(6---)"); // display prio set to 6
2627
2628 } else {
2629 if (strpbrk(restrn, "\003\004\005\006")) { // fishing/trawling
2630 // Continuation C
2631 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
2632 symb = _T(";SY(FSHRES51)");
2633 else {
2634 if (strpbrk(restrn, "\011\012\013\014\015"))
2635 symb = _T(";SY(FSHRES71)");
2636 else{
2637 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
2638 symb = _T(";SY(FSHRES71)");
2639 else
2640 symb = _T(";SY(FSHRES51)");
2641 }
2642 }
2643
2644 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
2645 line = _T(";LC(FSHRES51)");
2646 else
2647 line = _T(";LS(DASH,2,CHMGD)");
2648
2649 prio = _T(";OP(6---)"); // display prio set to 6
2650
2651 } else {
2652 if (strpbrk(restrn, "\011\012\013\014\015")) // diving, dredging, waking...
2653 symb = _T(";SY(INFARE51)");
2654 else
2655 symb = _T(";SY(RSRDEF51)");
2656
2657 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
2658 line = _T(";LC(CTYARE51)");
2659 else
2660 line = _T(";LS(DASH,2,CHMGD)");
2661
2662 }
2663 // Todo more for s57 3.1 Look at caris catalog ATTR::RESARE
2664
2665 }
2666 }
2667
2668 } else {
2669 // Continuation D
2670 if (NULL != catreastr) {
2671 if (strpbrk(catrea, "\001\010\011\014\016\023\025\031")) {
2672 if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
2673 symb = _T(";SY(CTYARE71)");
2674 else
2675 symb = _T(";SY(CTYARE51)");
2676 } else {
2677 if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
2678 symb = _T(";SY(INFARE51)");
2679 else
2680 symb = _T(";SY(RSRDEF51)");
2681 }
2682 } else
2683 symb = _T(";SY(RSRDEF51)");
2684
2685 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
2686 line = _T(";LC(CTYARE51)");
2687 else
2688 line = _T(";LS(DASH,2,CHMGD)");
2689 }
2690
2691 // create command word
2692 if (prio.Len())
2693 resare02.Append(prio);
2694 resare02.Append(line);
2695 resare02.Append(symb);
2696
2697 resare02.Append('\037');
2698
2699 char *r = (char *)malloc(resare02.Len() + 1);
2700 strcpy(r, resare02.mb_str());
2701
2702 delete restrnstr;
2703 delete catreastr;
2704
2705 return r;
2706 }
2707
2708
2709
2710
2711
2712
2713
2714
2715 static void *_RESCSP01(void *param);
RESTRN01(void * param)2716 static void *RESTRN01 (void *param)
2717 // Remarks: Objects subject to RESTRN01 are actually symbolised in sub-process
2718 // RESCSP01, since the latter can also be accessed from other conditional
2719 // symbology procedures. RESTRN01 merely acts as a "signpost" for
2720 // RESCSP01.
2721 //
2722 // Object class RESARE is symbolised for the effect of attribute RESTRN in a separate
2723 // conditional symbology procedure called RESARE02.
2724 //
2725 // Since many of the areas concerned cover shipping channels, the number of symbols used
2726 // is minimised to reduce clutter. To do this, values of RESTRN are ranked for significance
2727 // as follows:
2728 // "Traffic Restriction" values of RESTRN:
2729 // (1) RESTRN 7,8: entry prohibited or restricted
2730 // RESTRN 14: IMO designated "area to be avoided" part of a TSS
2731 // (2) RESTRN 1,2: anchoring prohibited or restricted
2732 // (3) RESTRN 3,4,5,6: fishing or trawling prohibited or restricted
2733 // (4) "Other Restriction" values of RESTRN are:
2734 // RESTRN 9, 10: dredging prohibited or restricted,
2735 // RESTRN 11,12: diving prohibited or restricted,
2736 // RESTRN 13 : no wake area.
2737 {
2738 ObjRazRules *rzRules = (ObjRazRules *)param;
2739 S57Obj *obj = rzRules->obj;
2740
2741 wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
2742
2743 // GString *restrn01str = S57_getAttVal(geo, "RESTRN");
2744 char *restrn01 = NULL;
2745
2746 if (NULL != restrnstr)
2747 restrn01 = (char *)_RESCSP01(param);
2748 else
2749 restrn01 = NULL;
2750
2751 delete restrnstr;
2752 return restrn01;
2753 }
2754
_RESCSP01(void * param)2755 static void *_RESCSP01(void *param)
2756 // Remarks: See procedure RESTRN01
2757 {
2758 ObjRazRules *rzRules = (ObjRazRules *)param;
2759 S57Obj *obj = rzRules->obj;
2760
2761 wxString rescsp01;
2762 // char *rescsp01 = NULL;
2763 wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
2764 // GString *restrnstr = S57_getAttVal(geo, "RESTRN");
2765 char restrn[LISTSIZE] = {'\0'}; // restriction list
2766 wxString symb;
2767 char *r = NULL;
2768
2769 if ( restrnstr->Len()) {
2770 _parseList(restrnstr->mb_str(), restrn, sizeof(restrn));
2771
2772 if (strpbrk(restrn, "\007\010\016")) {
2773 // continuation A
2774 if (strpbrk(restrn, "\001\002\003\004\005\006"))
2775 symb = _T(";SY(ENTRES61)");
2776 else {
2777 if (strpbrk(restrn, "\011\012\013\014\015"))
2778 symb = _T(";SY(ENTRES71)");
2779 else
2780 symb = _T(";SY(ENTRES51)");
2781
2782 }
2783 } else {
2784 if (strpbrk(restrn, "\001\002")) {
2785 // continuation B
2786 if (strpbrk(restrn, "\003\004\005\006"))
2787 symb = _T(";SY(ACHRES61)");
2788 else {
2789 if (strpbrk(restrn, "\011\012\013\014\015"))
2790 symb =_T( ";SY(ACHRES71)");
2791 else
2792 symb = _T(";SY(ACHRES51)");
2793 }
2794
2795
2796 } else {
2797 if (strpbrk(restrn, "\003\004\005\006")) {
2798 // continuation C
2799 if (strpbrk(restrn, "\011\012\013\014\015"))
2800 symb = _T(";SY(FSHRES71)");
2801 else
2802 symb = _T(";SY(FSHRES51)");
2803
2804
2805 } else {
2806 if (strpbrk(restrn, "\011\012\013\014\015"))
2807 symb = _T(";SY(INFARE51)");
2808 else
2809 symb = _T(";SY(RSRDEF51)");
2810
2811 }
2812 }
2813 }
2814
2815 rescsp01.Append(symb);
2816 rescsp01.Append('\037');
2817
2818 r = (char *)malloc(rescsp01.Len() + 1);
2819 strcpy(r, rescsp01.mb_str());
2820
2821 delete restrnstr;
2822 }
2823
2824 return r;
2825 }
2826
SEABED01(void * param)2827 static void *SEABED01(void *param)
2828 {
2829 ObjRazRules *rzRules = (ObjRazRules *)param;
2830 // S57Obj *obj = rzRules->obj;
2831
2832 CPLError((CPLErr)0, 0,"s52csny : SEABED01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
2833 return NULL;
2834 }
2835
2836 /*
2837 static void *SNDFRM02(void *param)
2838 {
2839 ObjRazRules *rzRules = (ObjRazRules *)param;
2840 // S57Obj *obj = rzRules->obj;
2841
2842 CPLError((CPLErr)0, 0,"s52csny : SNDFRM02 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
2843 return NULL;
2844 }
2845 */
2846
2847 wxString SNDFRM02(S57Obj *obj, double depth_value);
2848
SOUNDG02(void * param)2849 static void *SOUNDG02(void *param)
2850 // Remarks: In S-57 soundings are elements of sounding arrays rather than individual
2851 // objects. Thus the conditional symbology methodology must examine each
2852 // sounding of a sounding array one by one. To symbolize the depth values it
2853 // calls the procedure SNDFRM02 which in turn translates the depth values
2854 // into a set of symbols to be shown at the soundings position.
2855 {
2856 // Shortcut. This CS method causes a branch to an S52plib method
2857 // which splits multi-point soundings into separate point objects,
2858 // and then calls CS(SOUNDG03) on successive points below.
2859 char *r = (char *)malloc(6);
2860 strcpy(r, "MP();");
2861
2862 return r;
2863
2864 }
2865
2866
SOUNDG03(void * param)2867 static void *SOUNDG03(void *param)
2868 // Remarks: SOUNDG03 is a private conditional symbology,
2869 // called to render individual points of a multi-point sounding set.
2870 {
2871 ObjRazRules *rzRules = (ObjRazRules *)param;
2872 S57Obj *obj = rzRules->obj;
2873
2874 wxString s = SNDFRM02(obj, obj->z);
2875
2876 char *r = (char *)malloc(s.Len() + 1);
2877 strcpy(r, s.mb_str());
2878
2879 return r;
2880 }
2881
SNDFRM02(S57Obj * obj,double depth_value_in)2882 wxString SNDFRM02(S57Obj *obj, double depth_value_in)
2883 // Remarks: Soundings differ from plain text because they have to be readable under all
2884 // circumstances and their digits are placed according to special rules. This
2885 // conditional symbology procedure accesses a set of carefully designed
2886 // sounding symbols provided by the symbol library and composes them to
2887 // sounding labels. It symbolizes swept depth and it also symbolizes for low
2888 // reliability as indicated by attributes QUASOU and QUAPOS.
2889 {
2890 wxString sndfrm02;
2891 char temp_str[LISTSIZE] = {'\0'};
2892 wxString symbol_prefix;
2893
2894 char symbol_prefix_a[200];
2895
2896 wxString *tecsoustr = GetStringAttrWXS(obj, "TECSOU");
2897 char tecsou[LISTSIZE] = {'\0'};
2898
2899 wxString *quasoustr = GetStringAttrWXS(obj, "QUASOU");
2900 char quasou[LISTSIZE] = {'\0'};
2901
2902
2903 wxString *statusstr = GetStringAttrWXS(obj, "STATUS");
2904 char status[LISTSIZE] = {'\0'};
2905
2906 double leading_digit = 0.0;
2907
2908 double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
2909
2910 // Do the math to convert soundings to ft/metres/fathoms on request
2911 double depth_value = depth_value_in;
2912
2913 // If the sounding value from the ENC (or SENC) is bogus, so state
2914 if(depth_value_in > 40000.)
2915 depth_value = 99999.;
2916 if(depth_value_in < -1000.)
2917 depth_value = 0.;
2918
2919 switch(ps52plib->m_nDepthUnitDisplay)
2920 {
2921 case 0:
2922 depth_value = depth_value * 3 * 39.37 / 36; // feet
2923 safety_depth = safety_depth * 3 * 39.37 / 36;
2924 break;
2925 case 2:
2926 depth_value = depth_value * 3 * 39.37 / (36 * 6); // fathoms
2927 safety_depth = safety_depth * 3 * 39.37 / (36 * 6);
2928 break;
2929 default:
2930 break;
2931 }
2932
2933
2934 // FIXME: test to fix the rounding error (!?)
2935 depth_value += (depth_value > 0.0)? 0.01: -0.01;
2936 leading_digit = (int) fabs(depth_value);
2937
2938 if (depth_value <= safety_depth) //S52_getMarinerParam(S52_MAR_SAFETY_DEPTH)
2939 symbol_prefix = _T("SOUNDS");
2940 else
2941 symbol_prefix = _T("SOUNDG");
2942
2943 strcpy(symbol_prefix_a,symbol_prefix.mb_str());
2944
2945 if (NULL != tecsoustr)
2946 {
2947 _parseList(tecsoustr->mb_str(), tecsou, sizeof(tecsou));
2948 if (strpbrk(tecsou, "\006"))
2949 {
2950 chk_snprintf(temp_str, LISTSIZE, ";SY(%sB1)", symbol_prefix_a);
2951 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
2952 }
2953 }
2954
2955 if (NULL != quasoustr) _parseList(quasoustr->mb_str(), quasou, sizeof(quasou));
2956 if (NULL != statusstr) _parseList(statusstr->mb_str(), status, sizeof(status));
2957
2958 if (strpbrk(quasou, "\003\004\005\010\011") || strpbrk(status, "\022"))
2959 {
2960 chk_snprintf(temp_str, LISTSIZE, ";SY(%sC2)", symbol_prefix_a);
2961 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
2962 }
2963 else
2964 {
2965 int quapos = 0;
2966 GetIntAttr(obj, "QUAPOS", quapos);
2967 if (0 != quapos)
2968 {
2969 if (2 <= quapos && quapos < 10)
2970 {
2971 chk_snprintf(temp_str, LISTSIZE,
2972 ";SY(%sC2)", symbol_prefix_a);
2973 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
2974 }
2975 }
2976 }
2977
2978 // Continuation A
2979 if (fabs(depth_value) < 10.0) {
2980
2981 // If showing as "feet", round off to one digit only
2982 if( (ps52plib->m_nDepthUnitDisplay == 0) && (depth_value > 0) ){
2983 double r1 = depth_value ;
2984 depth_value = wxRound( r1 ) ;
2985 leading_digit = (int) depth_value;
2986 }
2987
2988 if (depth_value < 10.0) {
2989 // can be above water (negative)
2990 int fraction = (int)ABS((fabs(depth_value) - leading_digit)*10);
2991
2992
2993 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
2994 symbol_prefix_a, (int)ABS(leading_digit));
2995 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
2996 if(fraction > 0) {
2997 chk_snprintf(temp_str, LISTSIZE,
2998 ";SY(%s5%1i)", symbol_prefix_a, fraction);
2999 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3000 }
3001
3002 // above sea level (negative)
3003 if (depth_value < 0.0)
3004 {
3005 chk_snprintf(temp_str, LISTSIZE,
3006 ";SY(%sA1)", symbol_prefix_a);
3007 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3008 }
3009 goto return_point;
3010 }
3011 }
3012
3013 if (fabs(depth_value) < 31.0) {
3014 bool b_2digit = false;
3015 double depth_value_pos = fabs(depth_value);
3016
3017 // If showing as "feet", round off to two digits only
3018 if( (ps52plib->m_nDepthUnitDisplay == 0) && (depth_value_pos > 0) ){
3019 double r1 = depth_value ;
3020 depth_value = wxRound( r1 ) ;
3021 leading_digit = (int) depth_value_pos;
3022 b_2digit = true;
3023 }
3024
3025
3026 double fraction = fabs(depth_value_pos - floor(leading_digit));
3027
3028 if (fraction != 0.0) {
3029 fraction = fraction * 10;
3030 if (leading_digit >= 10.0)
3031 {
3032 chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)",
3033 symbol_prefix_a, (int)leading_digit/10);
3034 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3035 }
3036
3037 double first_digit = floor(leading_digit / 10);
3038 int secnd_digit = (int)(floor(leading_digit - (first_digit * 10)));
3039 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3040 symbol_prefix_a, secnd_digit/*(int)leading_digit*/);
3041 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3042
3043 if(!b_2digit){
3044 if((int)fraction > 0) {
3045 chk_snprintf(temp_str, LISTSIZE, ";SY(%s5%1i)",
3046 symbol_prefix_a, (int)fraction);
3047 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3048 }
3049 }
3050
3051 if (depth_value < 0.0)
3052 {
3053 chk_snprintf(temp_str, LISTSIZE, ";SY(%sA1)", symbol_prefix_a);
3054 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3055 }
3056
3057 goto return_point;
3058 }
3059 }
3060
3061 // Continuation B
3062 if (fabs(depth_value) < 100.0)
3063 {
3064 leading_digit = fabs(leading_digit);
3065
3066 double first_digit = floor(leading_digit / 10);
3067 double secnd_digit = floor(leading_digit - (first_digit * 10));
3068
3069 if (depth_value < 0.0)
3070 {
3071 chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)",
3072 symbol_prefix_a, (int)first_digit);
3073 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3074 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3075 symbol_prefix_a, (int)secnd_digit);
3076 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3077 chk_snprintf(temp_str, LISTSIZE, ";SY(%sA1)", symbol_prefix_a);
3078 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3079 }
3080 else{
3081 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3082 symbol_prefix_a, (int)first_digit);
3083 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3084 chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)",
3085 symbol_prefix_a, (int)secnd_digit);
3086 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3087 }
3088 goto return_point;
3089 }
3090
3091 if (depth_value < 1000.0)
3092 {
3093 double first_digit = floor(leading_digit / 100);
3094 double secnd_digit = floor((leading_digit - (first_digit * 100)) / 10);
3095 double third_digit = floor(leading_digit - (first_digit * 100) - (secnd_digit * 10));
3096
3097 chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)",
3098 symbol_prefix_a, (int)first_digit);
3099 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3100 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3101 symbol_prefix_a, (int)secnd_digit);
3102 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3103 chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)",
3104 symbol_prefix_a, (int)third_digit);
3105 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3106
3107 goto return_point;
3108 }
3109
3110 if (depth_value < 10000.0)
3111 {
3112 double first_digit = floor(leading_digit / 1000);
3113 double secnd_digit = floor((leading_digit - (first_digit * 1000)) / 100);
3114 double third_digit = floor((leading_digit - (first_digit * 1000) - (secnd_digit * 100)) / 10);
3115 double last_digit = floor(leading_digit - (first_digit * 1000) - (secnd_digit * 100) - (third_digit * 10)) ;
3116
3117 chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)",
3118 symbol_prefix_a, (int)first_digit);
3119 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3120 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3121 symbol_prefix_a, (int)secnd_digit);
3122 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3123 chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)",
3124 symbol_prefix_a, (int)third_digit);
3125 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3126 chk_snprintf(temp_str, LISTSIZE, ";SY(%s4%1i)",
3127 symbol_prefix_a, (int)last_digit);
3128 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3129
3130 goto return_point;
3131 }
3132
3133 // Continuation C
3134 {
3135 double first_digit = floor(leading_digit / 10000);
3136 double secnd_digit = floor((leading_digit - (first_digit * 10000)) / 1000);
3137 double third_digit = floor((leading_digit - (first_digit * 10000) - (secnd_digit * 1000)) / 100 );
3138 double fourth_digit = floor((leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100)) / 10 ) ;
3139 double last_digit = floor(leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100) - (fourth_digit * 10)) ;
3140
3141 chk_snprintf(temp_str, LISTSIZE, ";SY(%s3%1i)",
3142 symbol_prefix_a, (int)first_digit);
3143 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3144 chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)",
3145 symbol_prefix_a, (int)secnd_digit);
3146 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3147 chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)",
3148 symbol_prefix_a, (int)third_digit);
3149 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3150 chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)",
3151 symbol_prefix_a, (int)fourth_digit);
3152 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3153 chk_snprintf(temp_str, LISTSIZE, ";SY(%s4%1i)",
3154 symbol_prefix_a, (int)last_digit);
3155 sndfrm02.Append(wxString(temp_str, wxConvUTF8));
3156
3157 goto return_point;
3158 }
3159
3160 return_point:
3161 sndfrm02.Append('\037');
3162
3163 delete tecsoustr;
3164 delete quasoustr;
3165 delete statusstr;
3166
3167 return sndfrm02;
3168 }
3169
3170
TOPMAR01(void * param)3171 static void *TOPMAR01 (void *param)
3172 // Remarks: Topmark objects are to be symbolized through consideration of their
3173 // platforms e.g. a buoy. Therefore this conditional symbology procedure
3174 // searches for platforms by looking for other objects that are located at the
3175 // same position.. Based on the finding whether the platform is rigid or
3176 // floating, the respective upright or sloping symbol is selected and presented
3177 // at the objects location. Buoyf symbols and topmark symbols have been
3178 // carefully designed to fit to each other when combined at the same position.
3179 // The result is a composed symbol that looks like the traditional symbols the
3180 // mariner is used to.
3181 {
3182 ObjRazRules *rzRules = (ObjRazRules *)param;
3183 S57Obj *obj = rzRules->obj;
3184
3185 int top_int = 0;
3186 bool battr = GetIntAttr(obj, "TOPSHP", top_int);
3187
3188 wxString sy;
3189
3190 if (!battr)
3191 sy = _T(";SY(QUESMRK1)");
3192 else {
3193 int floating = FALSE; // not a floating platform
3194 int topshp = (!battr) ? 0 : top_int;
3195
3196
3197 if (TRUE == _atPtPos(obj, GetChartFloatingATONArray( rzRules ), false))
3198 floating = TRUE;
3199 else
3200 // FIXME: this test is wierd since it doesn't affect 'floating'
3201 if (TRUE == _atPtPos(obj, GetChartRigidATONArray( rzRules ), false))
3202 floating = FALSE;
3203
3204
3205 if (floating) {
3206 // floating platform
3207 switch (topshp) {
3208 case 1 : sy = _T(";SY(TOPMAR02)"); break;
3209 case 2 : sy = _T(";SY(TOPMAR04)"); break;
3210 case 3 : sy = _T(";SY(TOPMAR10)"); break;
3211 case 4 : sy = _T(";SY(TOPMAR12)"); break;
3212
3213 case 5 : sy = _T(";SY(TOPMAR13)"); break;
3214 case 6 : sy = _T(";SY(TOPMAR14)"); break;
3215 case 7 : sy = _T(";SY(TOPMAR65)"); break;
3216 case 8 : sy = _T(";SY(TOPMAR17)"); break;
3217
3218 case 9 : sy = _T(";SY(TOPMAR16)"); break;
3219 case 10: sy = _T(";SY(TOPMAR08)"); break;
3220 case 11: sy = _T(";SY(TOPMAR07)"); break;
3221 case 12: sy = _T(";SY(TOPMAR14)"); break;
3222
3223 case 13: sy = _T(";SY(TOPMAR05)"); break;
3224 case 14: sy = _T(";SY(TOPMAR06)"); break;
3225 case 17: sy = _T(";SY(TMARDEF2)"); break;
3226 case 18: sy = _T(";SY(TOPMAR10)"); break;
3227
3228 case 19: sy = _T(";SY(TOPMAR13)"); break;
3229 case 20: sy = _T(";SY(TOPMAR14)"); break;
3230 case 21: sy = _T(";SY(TOPMAR13)"); break;
3231 case 22: sy = _T(";SY(TOPMAR14)"); break;
3232
3233 case 23: sy = _T(";SY(TOPMAR14)"); break;
3234 case 24: sy = _T(";SY(TOPMAR02)"); break;
3235 case 25: sy = _T(";SY(TOPMAR04)"); break;
3236 case 26: sy = _T(";SY(TOPMAR10)"); break;
3237
3238 case 27: sy = _T(";SY(TOPMAR17)"); break;
3239 case 28: sy = _T(";SY(TOPMAR18)"); break;
3240 case 29: sy = _T(";SY(TOPMAR02)"); break;
3241 case 30: sy = _T(";SY(TOPMAR17)"); break;
3242
3243 case 31: sy = _T(";SY(TOPMAR14)"); break;
3244 case 32: sy = _T(";SY(TOPMAR10)"); break;
3245 case 33: sy = _T(";SY(TMARDEF2)"); break;
3246 default: sy = _T(";SY(TMARDEF2)"); break;
3247 }
3248 } else {
3249 // not a floating platform
3250 switch (topshp) {
3251 case 1 : sy = _T(";SY(TOPMAR22)"); break;
3252 case 2 : sy = _T(";SY(TOPMAR24)"); break;
3253 case 3 : sy = _T(";SY(TOPMAR30)"); break;
3254 case 4 : sy = _T(";SY(TOPMAR32)"); break;
3255
3256 case 5 : sy = _T(";SY(TOPMAR33)"); break;
3257 case 6 : sy = _T(";SY(TOPMAR34)"); break;
3258 case 7 : sy = _T(";SY(TOPMAR85)"); break;
3259 case 8 : sy = _T(";SY(TOPMAR86)"); break;
3260
3261 case 9 : sy = _T(";SY(TOPMAR36)"); break;
3262 case 10: sy = _T(";SY(TOPMAR28)"); break;
3263 case 11: sy = _T(";SY(TOPMAR27)"); break;
3264 case 12: sy = _T(";SY(TOPMAR14)"); break;
3265
3266 case 13: sy = _T(";SY(TOPMAR25)"); break;
3267 case 14: sy = _T(";SY(TOPMAR26)"); break;
3268 case 15: sy = _T(";SY(TOPMAR88)"); break;
3269 case 16: sy = _T(";SY(TOPMAR87)"); break;
3270
3271 case 17: sy = _T(";SY(TMARDEF1)"); break;
3272 case 18: sy = _T(";SY(TOPMAR30)"); break;
3273 case 19: sy = _T(";SY(TOPMAR33)"); break;
3274 case 20: sy = _T(";SY(TOPMAR34)"); break;
3275
3276 case 21: sy = _T(";SY(TOPMAR33)"); break;
3277 case 22: sy = _T(";SY(TOPMAR34)"); break;
3278 case 23: sy = _T(";SY(TOPMAR34)"); break;
3279 case 24: sy = _T(";SY(TOPMAR22)"); break;
3280
3281 case 25: sy = _T(";SY(TOPMAR24)"); break;
3282 case 26: sy = _T(";SY(TOPMAR30)"); break;
3283 case 27: sy = _T(";SY(TOPMAR86)"); break;
3284 case 28: sy = _T(";SY(TOPMAR89)"); break;
3285
3286 case 29: sy = _T(";SY(TOPMAR22)"); break;
3287 case 30: sy = _T(";SY(TOPMAR86)"); break;
3288 case 31: sy = _T(";SY(TOPMAR14)"); break;
3289 case 32: sy = _T(";SY(TOPMAR30)"); break;
3290 case 33: sy = _T(";SY(TMARDEF1)"); break;
3291 default: sy = _T(";SY(TMARDEF1)"); break;
3292 }
3293 }
3294
3295 }
3296
3297 wxString topmar;
3298 topmar.Append(sy);
3299 topmar.Append('\037');
3300
3301 char *r = (char *)malloc(topmar.Len() + 1);
3302 strcpy(r, topmar.mb_str());
3303
3304 return r;
3305 }
3306
3307
UDWHAZ03(void * param)3308 static void *UDWHAZ03(void *param)
3309 {
3310 ObjRazRules *rzRules = (ObjRazRules *)param;
3311 // S57Obj *obj = rzRules->obj;
3312
3313 CPLError((CPLErr)0, 0,"s52csny : UDWHAZ03 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
3314 return NULL;
3315 }
3316
VESSEL01(void * param)3317 static void *VESSEL01(void *param)
3318 {
3319 ObjRazRules *rzRules = (ObjRazRules *)param;
3320 // S57Obj *obj = rzRules->obj;
3321
3322 CPLError((CPLErr)0, 0,"s52csny : VESSEL01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
3323 return NULL;
3324 }
3325
VRMEBL01(void * param)3326 static void *VRMEBL01(void *param)
3327 {
3328 ObjRazRules *rzRules = (ObjRazRules *)param;
3329 // S57Obj *obj = rzRules->obj;
3330
3331 CPLError((CPLErr)0, 0,"s52csny : VRMEBL01 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
3332 return NULL;
3333 }
3334
3335 /*
3336 static void *WRECKS02a(void *param)
3337 {
3338 ObjRazRules *rzRules = (ObjRazRules *)param;
3339 // S57Obj *obj = rzRules->obj;
3340
3341 static int f07;
3342 if(!f07)
3343 CPLError((CPLErr)0, 0,"s52csny : WRECKS02 ERROR no conditional symbology for: %s\n",rzRules->LUP->OBCL);
3344 f07++;
3345 return NULL;
3346 }
3347 */
3348
WRECKS02(void * param)3349 static void *WRECKS02 (void *param)
3350 // Remarks: Wrecks of depths less than the safety contour which lie within the safe waters
3351 // defined by the safety contour are to be presented by a specific isolated
3352 // danger symbol and put in IMO category DISPLAYBASE (see (3), App.2,
3353 // 1.3). This task is performed by the sub-procedure "UDWHAZ03" which is
3354 // called by this symbology procedure.
3355 {
3356 wxString wrecks02str;
3357 wxString sndfrm02str;
3358 wxString *udwhaz03str = NULL;
3359 wxString *quapnt01str = NULL;
3360 double least_depth = UNKNOWN;
3361 double depth_value = UNKNOWN;
3362 // GString *valsoustr = S57_getAttVal(geo, "VALSOU");
3363 double valsou = UNKNOWN;
3364 bool b_promote = false;
3365
3366 ObjRazRules *rzRules = (ObjRazRules *)param;
3367 S57Obj *obj = rzRules->obj;
3368
3369 GetDoubleAttr(obj, "VALSOU", valsou);
3370
3371 int watlev = -9;
3372 GetIntAttr(obj, "WATLEV", watlev);
3373 int catwrk = -9;
3374 GetIntAttr(obj, "CATWRK", catwrk);
3375
3376 int quasou = -9;
3377 // QUASOU is a list ie a string for us
3378 wxString *quasoustr = GetStringAttrWXS(obj, "QUASOU");
3379 char quasouchar[LISTSIZE] = {'\0'};
3380
3381 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3382
3383 if (UNKNOWN != valsou)
3384 {
3385 depth_value = valsou;
3386 sndfrm02str = SNDFRM02(obj, depth_value);
3387 }
3388 else
3389 {
3390 if (GEO_AREA == obj->Primitive_type)
3391 least_depth = _DEPVAL01(obj, least_depth);
3392
3393 if (least_depth == UNKNOWN)
3394 /*
3395 {
3396 // WARNING: ambiguity removed in WRECKS03 (see update)
3397
3398 if (-9 == watlev) // default
3399 depth_value = -15.0;
3400 else
3401 switch (watlev)
3402 { // ambiguous
3403 case 1:
3404 case 2: depth_value = -15.0 ; break;
3405 case 3: depth_value = 0.01; break;
3406 case 4: depth_value = -15.0 ; break;
3407 case 5: depth_value = 0.0 ; break;
3408 case 6: depth_value = -15.0 ; break;
3409 default :
3410 {
3411 if (-9 != catwrk)
3412 {
3413 switch (catwrk)
3414 {
3415 case 1: depth_value = 20.0; break;
3416 case 2: depth_value = 0.0; break;
3417 case 4:
3418 case 5: depth_value = -15.0; break;
3419 }
3420 }
3421 }
3422 }
3423 }
3424 */
3425 ////////////////////////////////////////////////
3426 // DSR New Logic Here (FIXME)
3427 {
3428 if (-9 != catwrk)
3429 {
3430 switch (catwrk)
3431 {
3432 case 1: depth_value = 20.0; break; // safe
3433 case 2: depth_value = 0.0; break; // dangerous
3434 case 4:
3435 case 5: depth_value = -15.0; break;
3436 }
3437 }
3438 else
3439 {
3440 if (-9 == watlev) // default
3441 depth_value = -15.0;
3442 else
3443 switch (watlev)
3444 {
3445 case 1:
3446 case 2: depth_value = -15.0 ; break;
3447 case 3: depth_value = 0.01; break;
3448 case 4: depth_value = -15.0 ; break;
3449 case 5: depth_value = 0.0 ; break;
3450 case 6: depth_value = -15.0 ; break;
3451 }
3452 }
3453
3454 }
3455
3456 else
3457 depth_value = least_depth;
3458
3459
3460 }
3461 if (NULL != quasoustr) _parseList(quasoustr->mb_str(), quasouchar, sizeof(quasouchar));
3462
3463 if (quasouchar[0] == 0 || NULL == strpbrk(quasouchar, "\07"))
3464 {
3465 //Fixes FS 165 XXX where it is?
3466 // 7 is 'least depth unknown, safe clearance at value shown'
3467 udwhaz03str = _UDWHAZ03(obj, depth_value, rzRules, &b_promote);
3468
3469 }
3470 else
3471 {
3472 quasou = 7;
3473 udwhaz03str = new wxString();
3474 }
3475 quapnt01str = CSQUAPNT01(obj);
3476
3477 if (GEO_POINT == obj->Primitive_type) {
3478 if (0 != udwhaz03str->Len()) {
3479 wrecks02str = wxString(*udwhaz03str);
3480
3481 wrecks02str.Append(*quapnt01str);
3482
3483 } else {
3484 // Continuation A (POINT_T)
3485 if (UNKNOWN != valsou) {
3486 ///////////////////////////////////////////
3487 // DSR New logic here, FIXME check s52 specs
3488
3489 /*
3490 if (valsou <= 20.0)
3491 {
3492 wrecks02str = wxString(";SY(DANGER51)");
3493 if (NULL != sndfrm02str)
3494 wrecks02str.Append(sndfrm02str);
3495 }
3496 else
3497 wrecks02str = wxString(";SY(DANGER52)");
3498 */
3499 if((valsou < safety_contour)/* || (2 == catwrk)*/) // maybe redundant, seems like wrecks with valsou < 20
3500 // are always coded as "dangerous wrecks"
3501 // Excluding (2 == catwrk) matches Caris logic
3502 wrecks02str = wxString(_T(";SY(DANGER51)"));
3503 else
3504 wrecks02str = wxString(_T(";SY(DANGER52)"));
3505 wrecks02str.Append(_T(";TX('Wk',2,1,2,'15110',1,0,CHBLK,21)"));
3506 if ( 7 == quasou ) //Fixes FS 165
3507 wrecks02str.Append(_T(";SY(WRECKS07)"));
3508
3509 wrecks02str.Append(sndfrm02str); // always show valsou depth
3510 ///////////////////////////////////////////
3511
3512 wrecks02str.Append(*udwhaz03str);
3513 wrecks02str.Append(*quapnt01str);
3514
3515 } else {
3516 wxString sym;
3517
3518 if (-9 != catwrk && -9 != watlev) {
3519 if (1 == catwrk && 3 == watlev)
3520 sym =_T(";SY(WRECKS04)");
3521 else {
3522 if (2 == catwrk && 3 == watlev)
3523 sym = _T(";SY(WRECKS05)");
3524 else {
3525 if (4 == catwrk || 5 == catwrk)
3526 sym = _T(";SY(WRECKS01)");
3527 else {
3528 if (1 == watlev ||
3529 2 == watlev ||
3530 5 == watlev ||
3531 4 == watlev ){
3532 sym = _T(";SY(WRECKS01)");
3533 } else
3534 sym = _T(";SY(WRECKS05)"); // default
3535
3536 }
3537 }
3538 }
3539 }
3540
3541 wrecks02str = sym;
3542 if (NULL != quapnt01str)
3543 wrecks02str.Append(*quapnt01str);
3544
3545 }
3546
3547 }
3548
3549
3550 } else {
3551 // Continuation B (AREAS_T)
3552 int quapos = 0;
3553 GetIntAttr(obj, "QUAPOS", quapos);
3554
3555 wxString line;
3556
3557 if (2 <= quapos && quapos < 10)
3558 line = _T(";LC(LOWACC41)");
3559 else {
3560 if ( 0 != udwhaz03str->Len())
3561 line = _T(";LS(DOTT,2,CHBLK)");
3562 else {
3563 if (UNKNOWN != valsou){
3564 if (valsou <= 20)
3565 line = _T(";LS(DOTT,2,CHBLK)");
3566 else
3567 line = _T(";LS(DASH,2,CHBLK)");
3568 } else {
3569
3570 if (-9 == watlev)
3571 line = _T(";LS(DOTT,2,CSTLN)");
3572 else {
3573 switch (watlev){
3574 case 1:
3575 case 2: line = _T(";LS(SOLD,2,CSTLN)"); break;
3576 case 4: line = _T(";LS(DASH,2,CSTLN)"); break;
3577 case 3:
3578 case 5:
3579
3580 default : line = _T(";LS(DOTT,2,CSTLN)"); break;
3581 }
3582 }
3583
3584 }
3585 }
3586 }
3587 wrecks02str = wxString(line);
3588
3589 if (UNKNOWN != valsou) {
3590 if (valsou <= 20) {
3591 wrecks02str.Append(*udwhaz03str);
3592 wrecks02str.Append(*quapnt01str);
3593 wrecks02str.Append(sndfrm02str);
3594
3595 } else {
3596 // NOTE: ??? same as above ???
3597 wrecks02str.Append(*udwhaz03str);
3598 wrecks02str.Append(*quapnt01str);
3599 }
3600 } else {
3601 wxString ac;
3602
3603 if (-9 == watlev)
3604 ac = _T(";AC(DEPVS)");
3605 else
3606 switch (watlev) {
3607 case 1:
3608 case 2: ac = _T(";AC(CHBRN)"); break;
3609 case 4: ac = _T(";AC(DEPIT)"); break;
3610 case 5:
3611 case 3:
3612 default : ac = _T(";AC(DEPVS)"); break;
3613 }
3614
3615 wrecks02str.Append(ac);
3616
3617 wrecks02str.Append(*udwhaz03str);
3618 wrecks02str.Append(*quapnt01str);
3619 }
3620 }
3621
3622 wrecks02str.Append('\037');
3623
3624 char *r = (char *)malloc(wrecks02str.Len() + 1);
3625 strcpy(r, wrecks02str.mb_str());
3626
3627 delete udwhaz03str;
3628 delete quapnt01str;
3629 delete quasoustr;
3630 return r;
3631 }
3632
3633
_LITDSN01(S57Obj * obj)3634 static wxString _LITDSN01(S57Obj *obj)
3635 // Remarks: In S-57 the light characteristics are held as a series of attributes values. The
3636 // mariner may wish to see a light description text string displayed on the
3637 // screen similar to the string commonly found on a paper chart. This
3638 // conditional procedure, reads the attribute values from the above list of
3639 // attributes and composes a light description string which can be displayed.
3640 // This procedure is provided as a C function which has as input, the above
3641 // listed attribute values and as output, the light description.
3642 {
3643 // CATLIT, LITCHR, COLOUR, HEIGHT, LITCHR, SIGGRP, SIGPER, STATUS, VALNMR
3644
3645 char colist[20];
3646 wxString return_value;
3647 #if 0
3648 // XXX CATLIT
3649 int catlit = -9;
3650 GetIntAttr(obj, "CATLIT", catlit);
3651
3652 if(-9 != catlit)
3653 {
3654 }
3655 #endif
3656
3657 /*
3658 1: directional function IP 30.1-3; 475.7;
3659 2: rear/upper light
3660 3: front/lower light
3661 4: leading light IP 20.1-3; 475.6;
3662 5: aero light IP 60; 476.1;
3663 6: air obstruction light IP 61; 476.2;
3664 7: fog detector light IP 62; 477;
3665 8: flood light IP 63; 478.2;
3666 9: strip light IP 64; 478.5;
3667 10: subsidiary light IP 42; 471.8;
3668 11: spotlight
3669 12: front
3670 13: rear
3671 14: lower
3672 15: upper
3673 16: moire' effect IP 31; 475.8;
3674 17: emergency
3675 18: bearing light 478.1;
3676 19: horizontally disposed
3677 20: vertically disposed
3678 */
3679
3680 // LITCHR
3681 int litchr = -9;
3682 wxString spost(_T(""));
3683 GetIntAttr(obj, "LITCHR", litchr);
3684
3685 bool b_grp2 = false; // 2 GRP attributes expected
3686 if(-9 != litchr)
3687 {
3688 switch (litchr)
3689 {
3690 /*
3691 case 1: return_value.Append(_T("F")); break;
3692 case 2: return_value.Append(_T("Fl")); break;
3693 case 3: return_value.Append(_T("Fl")); break;
3694 case 4: return_value.Append(_T("Q")); break;
3695 case 7: return_value.Append(_T("Iso")); break;
3696 case 8: return_value.Append(_T("Occ")); break;
3697 case 12: return_value.Append(_T("Mo")); break;
3698 */
3699
3700 case 1: return_value.Append(_T("F")); break; //fixed IP 10.1;
3701 case 2: return_value.Append(_T("Fl")); break; //flashing IP 10.4;
3702 case 3: return_value.Append(_T("LFl")); break; //long-flashing IP 10.5;
3703 case 4: return_value.Append(_T("Q")); break; //quick-flashing IP 10.6;
3704 case 5: return_value.Append(_T("VQ")); break; //very quick-flashing IP 10.7;
3705 case 6: return_value.Append(_T("UQ")); break; //ultra quick-flashing IP 10.8;
3706 case 7: return_value.Append(_T("Iso")); break; //isophased IP 10.3;
3707 case 8: return_value.Append(_T("Occ")); break; //occulting IP 10.2;
3708 case 9: return_value.Append(_T("IQ")); break; //interrupted quick-flashing IP 10.6;
3709 case 10: return_value.Append(_T("IVQ")); break; //interrupted very quick-flashing IP 10.7;
3710 case 11: return_value.Append(_T("IUQ")); break; //interrupted ultra quick-flashing IP 10.8;
3711 case 12: return_value.Append(_T("Mo")); break; //morse IP 10.9;
3712 case 13: return_value.Append(_T("F + Fl")); b_grp2 = true; break; //fixed/flash IP 10.10;
3713 case 14: return_value.Append(_T("Fl + LFl")); b_grp2 = true; break; //flash/long-flash
3714 case 15: return_value.Append(_T("Occ + Fl")); b_grp2 = true; break; //occulting/flash
3715 case 16: return_value.Append(_T("F + LFl")); b_grp2 = true; break; //fixed/long-flash
3716 case 17: return_value.Append(_T("Al Occ")); break; //occulting alternating
3717 case 18: return_value.Append(_T("Al LFl")); break; //long-flash alternating
3718 case 19: return_value.Append(_T("Al Fl")); break; //flash alternating
3719 case 20: return_value.Append(_T("Al Grp")); break; //group alternating
3720 case 21: return_value.Append(_T("F")); spost = _T(" (vert)"); break; //2 fixed (vertical)
3721 case 22: return_value.Append(_T("F")); spost = _T(" (horz)"); break; //2 fixed (horizontal)
3722 case 23: return_value.Append(_T("F")); spost = _T(" (vert)"); break; //3 fixed (vertical)
3723 case 24: return_value.Append(_T("F")); spost = _T(" (horz)"); break; //3 fixed (horizontal)
3724 case 25: return_value.Append(_T("Q + LFl")); b_grp2 = true; break; //quick-flash plus long-flash
3725 case 26: return_value.Append(_T("VQ + LFl")); b_grp2 = true; break; //very quick-flash plus long-flash
3726 case 27: return_value.Append(_T("UQ + LFl")); b_grp2 = true; break; //ultra quick-flash plus long-flash
3727 case 28: return_value.Append(_T("Alt")); break; //alternating
3728 case 29: return_value.Append(_T("F + Alt")); b_grp2 = true; break; //fixed and alternating flashing
3729
3730 default: break;
3731 }
3732 }
3733
3734 int nfirst_grp = -1;
3735 if(b_grp2)
3736 {
3737 wxString ret_new;
3738 nfirst_grp = return_value.Find(_T(" "));
3739 if( wxNOT_FOUND != nfirst_grp)
3740 {
3741 ret_new = return_value.Mid(0, nfirst_grp);
3742 ret_new.Append(_T("(?)"));
3743 ret_new.Append(return_value.Mid(nfirst_grp));
3744 return_value = ret_new;
3745 nfirst_grp += 1;
3746 }
3747 }
3748
3749
3750
3751 // SIGGRP, (c)(c) ...
3752 char grp_str[20] = {'\0'};
3753 GetStringAttr(obj, "SIGGRP", grp_str, 19);
3754 if(strlen(grp_str))
3755 {
3756 wxString ss(grp_str, wxConvUTF8);
3757
3758 if(b_grp2)
3759 {
3760 wxStringTokenizer tkz(ss, _T("()"));
3761
3762 int n_tok = 0;
3763 while ( tkz.HasMoreTokens() && (n_tok <2))
3764 {
3765 wxString s = tkz.GetNextToken();
3766 if(s.Len())
3767 {
3768 if((n_tok == 0) && (nfirst_grp > 0))
3769 {
3770 return_value[nfirst_grp] = s[0];
3771 }
3772 else
3773 {
3774 if(s != _T("1"))
3775 {
3776 return_value.Append(_T("("));
3777 return_value.Append(s);
3778 return_value.Append(_T(")"));
3779 }
3780 }
3781
3782 n_tok++;
3783 }
3784 }
3785 }
3786 else
3787 {
3788 if(ss != _T("(1)"))
3789 return_value.Append(ss);
3790 }
3791 }
3792
3793 // COLOUR,
3794 char col_str[20] = {'\0'};
3795
3796 // Don't show for sectored lights since we are only showing one of the sectors.
3797 double sectrTest;
3798 bool hasSectors = GetDoubleAttr( obj, "SECTR1", sectrTest );
3799
3800 if( ! hasSectors ) {
3801 GetStringAttr(obj, "COLOUR", col_str, 19);
3802
3803 int n_cols = 0;
3804 if (strlen(col_str))
3805 n_cols = _parseList(col_str, colist, sizeof(colist));
3806
3807 if(n_cols)
3808 return_value.Append(_T(" "));
3809
3810 for(int i=0 ; i < n_cols ; i++)
3811 {
3812 switch (colist[i])
3813 {
3814 case 1: return_value.Append(_T("W")); break;
3815 case 3: return_value.Append(_T("R")); break;
3816 case 4: return_value.Append(_T("G")); break;
3817 case 6: return_value.Append(_T("Y")); break;
3818 default: break;
3819 }
3820 }
3821 }
3822
3823
3824
3825 /*
3826 1: white IP 11.1; 450.2-3;
3827 2: black
3828 3: red IP 11.2; 450.2-3;
3829 4: green IP 11.3; 450.2-3;
3830 5: blue IP 11.4; 450.2-3;
3831 6: yellow IP 11.6; 450.2-3;
3832 7: grey
3833 8: brown
3834 9: amber IP 11.8; 450.2-3;
3835 10: violet IP 11.5; 450.2-3;
3836 11: orange IP 11.7; 450.2-3;
3837 12: magenta
3838 13: pink
3839 */
3840
3841 // SIGPER, xx.xx
3842 double sigper = UNKNOWN;
3843 GetDoubleAttr(obj, "SIGPER", sigper);
3844
3845 if(UNKNOWN != sigper)
3846 {
3847 wxString s;
3848 if(fabs(wxRound(sigper) - sigper) > 0.01)
3849 s.Printf(_T("%4.1fs"), sigper);
3850 else
3851 s.Printf(_T("%2.0fs"), sigper);
3852
3853 s.Trim(false); // remove leading spaces
3854 s.Prepend(_T(" "));
3855 return_value.Append(s);
3856 }
3857
3858
3859 // HEIGHT, xxx.x
3860 double height = UNKNOWN;
3861 GetDoubleAttr(obj, "HEIGHT", height);
3862
3863 if(UNKNOWN != height)
3864 {
3865 wxString s;
3866 switch(ps52plib->m_nDepthUnitDisplay)
3867 {
3868 case 0: // feet
3869 case 2: // fathoms
3870 s.Printf(_T("%3.0fft"), height* 3 * 39.37 / 36);
3871 break;
3872 default:
3873 s.Printf(_T("%3.0fm"), height);
3874 break;
3875 }
3876
3877 s.Trim(false); // remove leading spaces
3878 s.Prepend(_T(" "));
3879 return_value.Append(s);
3880 }
3881
3882
3883 // VALNMR, xx.x
3884 double valnmr = UNKNOWN;
3885 GetDoubleAttr(obj, "VALNMR", valnmr);
3886
3887 if( UNKNOWN != valnmr && ! hasSectors )
3888 {
3889 wxString s;
3890 s.Printf(_T("%2.0fNm"), valnmr);
3891 s.Trim(false); // remove leading spaces
3892 s.Prepend(_T(" "));
3893 return_value.Append(s);
3894 }
3895
3896 #if 0
3897
3898 // STATUS,
3899 gstr = S57_getAttVal(geo, "STATUS");
3900 if (NULL != gstr)
3901 g_string_append(litdsn01, gstr->str);
3902
3903 /*
3904 1: permanent
3905 2: occasional IP 50; 473.2;
3906 3: recommended IN 10; 431.1;
3907 4: not in use IL 14, 44; 444.7;
3908 5: periodic/intermittent IC 21; IQ 71; 353.3; 460.5;
3909 6: reserved IN 12.9;
3910 7: temporary IP 54;
3911 8: private IQ 70;
3912 9: mandatory
3913 10: destroyed/ruined
3914 11: extinguished
3915 12: illuminated
3916 13: historic
3917 14: public
3918 15: synchronized
3919 16: watched
3920 17: un-watched
3921 18: existence doubtful
3922 */
3923
3924
3925 #endif
3926
3927 return_value.Append(spost); // add any final modifiers
3928
3929 return return_value;
3930 }
3931
3932
SYMINS01(void * param)3933 static void *SYMINS01(void *param)
3934 {
3935 ObjRazRules *rzRules = (ObjRazRules *)param;
3936 S57Obj *obj = rzRules->obj;
3937 char symins[80] = {'\0'};
3938 GetStringAttr(obj, "SYMINS", symins, 79);
3939
3940 strcat(symins, "\037");
3941 char *r = (char *)malloc(strlen(symins) + 1);
3942 strcpy(r, symins);
3943
3944 return r;
3945 }
3946
3947 //--------------------------------
3948 //
3949 // JUMP TABLE SECTION
3950 //
3951 //--------------------------------
3952 Cond condTable[] = {
3953 {"CLRLIN01",CLRLIN01},
3954 {"DATCVR01",DATCVR01},
3955 {"DATCVR01",DATCVR01},
3956 {"DEPARE01",DEPARE01},
3957 {"DEPARE02",DEPARE01}, // new in PLIB 3_3, opencpn defaults to DEPARE01
3958 {"DEPCNT02",DEPCNT02},
3959 {"DEPVAL01",DEPVAL01},
3960 {"LEGLIN02",LEGLIN02},
3961 {"LIGHTS05",LIGHTS05}, // new in PLIB 3_3, replaces LIGHTS04
3962 {"LITDSN01",LITDSN01},
3963 {"OBSTRN04",OBSTRN04},
3964 {"OWNSHP02",OWNSHP02},
3965 {"PASTRK01",PASTRK01},
3966 {"QUAPOS01",QUAPOS01},
3967 {"QUALIN01",QUALIN01},
3968 {"QUAPNT01",QUAPNT01},
3969 {"SLCONS03",SLCONS03},
3970 {"RESARE02",RESARE02},
3971 {"RESTRN01",RESTRN01},
3972 // {"RESCSP01",RESCSP01},
3973 {"SEABED01",SEABED01},
3974 // {"SNDFRM02",SNDFRM02},
3975 {"SOUNDG02",SOUNDG02},
3976 {"TOPMAR01",TOPMAR01},
3977 {"UDWHAZ03",UDWHAZ03},
3978 {"VESSEL01",VESSEL01},
3979 {"VRMEBL01",VRMEBL01},
3980 {"WRECKS02",WRECKS02},
3981 {"SOUNDG03",SOUNDG03}, // special case for MPS
3982 {"SYMINS01",SYMINS01}, // Container for Virtual AIS ATONS, special case
3983 {"########",NULL}
3984 };
3985
3986 #if 0
3987 // S52CS.c : Conditional Symbologie procedure 3.2 (CS)
3988 //
3989 // Project: OpENCview
3990
3991 /*
3992 This file is part of the OpENCview project, a viewer of ENC
3993 Copyright (C) 2000-2004 Sylvain Duclos sduclos@users.sourceforgue.net
3994
3995 This program is free software; you can redistribute it and/or modify
3996 it under the terms of the GNU General Public License as published by
3997 the Free Software Foundation; either version 2 of the License, or
3998 (at your option) any later version.
3999
4000 This program is distributed in the hope that it will be useful,
4001 but WITHOUT ANY WARRANTY; without even the implied warranty of
4002 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4003 GNU General Public License for more details.
4004
4005 You should have received a copy of the GNU General Public License
4006 along with this program; if not, write to the Free Software
4007 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4008 */
4009
4010 // NOTE: remarks commenting each CS are extracted from pslb03_2.pdf (sec. 12)
4011
4012 // FIXME: DEPCNT02: call DB for area DEPARE & DRGARE that intersect this line
4013 // FIXME:_DEPVAL01: call DB for area DEPARE & UNSARE that intersect this area
4014 // FIXME:_UDWHAZ03: call DB for area DRGARE & DEPARE that intersect this point/area
4015
4016 #include "S52CS.h"
4017
4018 #include "S52utils.h" // PRINTF()
4019
4020 #include <stdlib.h> // atof()
4021 #include <math.h> // fabsf(), HUGE_VAL
4022 #include <ctype.h> // isdigit()
4023
4024 #define UNKNOWN 1e6 //HUGE_VAL // INFINITY/NAN
4025
4026 #define COALNE 30 // Coastline
4027 #define DEPARE 42 // Depth area
4028 #define DEPCNT 43 // Depth contour
4029 #define DRGARE 46 // Dredged area
4030 #define UWTROC 153 // Underwater rock / awash rock
4031 #define WRECKS 159 // Wreck
4032
4033 // point list name
4034 #define LIGHTLIST 0
4035 #define SECTRLIST 1
4036 #define FLOATLIST 2 // floating platform
4037 #define RIGIDLIST 3 // rigid platform
4038 //static GPtrArray *_lightList = NULL;
4039 //static GPtrArray *_sectrList = NULL;
4040 //static GPtrArray *_flaotList = NULL;
4041 static GPtrArray *_ptList[] = {NULL, NULL, NULL, NULL};
4042
4043 int S52_state = 1;
4044
4045 // size of attributes value list buffer
4046 #define LISTSIZE 16 // list size
4047
4048 #define version "3.2.0"
4049 char *S52_CS_version()
4050 {
4051 return version;
4052 }
4053
4054 int S52_CS_init()
4055 {
4056 _ptList[LIGHTLIST] = g_ptr_array_new();
4057 _ptList[SECTRLIST] = g_ptr_array_new();
4058 _ptList[FLOATLIST] = g_ptr_array_new();
4059 _ptList[RIGIDLIST] = g_ptr_array_new();
4060
4061 return 1;
4062 }
4063
4064 int S52_CS_done()
4065 {
4066 g_ptr_array_free(_ptList[LIGHTLIST], TRUE);
4067 g_ptr_array_free(_ptList[SECTRLIST], TRUE);
4068 g_ptr_array_free(_ptList[FLOATLIST], TRUE);
4069 g_ptr_array_free(_ptList[RIGIDLIST], TRUE);
4070
4071 return 1;
4072 }
4073
4074 int S52_CS_setPtPos(S57_geo *geoData, char *name)
4075 {
4076 printf("name = %s\n", name);
4077
4078 if (POINT_T == S57_getObjtype(geoData)) {
4079
4080 // set floating platform
4081 if ((0==strncmp(name, "LITFLT", 6)) ||
4082 (0==strncmp(name, "LITVES", 6)) ||
4083 (0==strncmp(name, "BOY", 3)))
4084 g_ptr_array_add(_ptList[FLOATLIST], (gpointer) geoData);
4085
4086 // set rigid platform
4087 if (0==strncmp(name, "BCN", 3))
4088 g_ptr_array_add(_ptList[RIGIDLIST], (gpointer) geoData);
4089 }
4090
4091 return 1;
4092 }
4093
4094 static int _atPtPos(S57_geo *geoNew, int listNm)
4095 // return TRUE if there is a light at this position
4096 // or if its an extended arc radius else FALSE
4097 {
4098 int i;
4099 GPtrArray *curntList = _ptList[listNm];
4100
4101 for (i=0; i<curntList->len; i++) {
4102 S57_geo *geoOld = g_ptr_array_index(curntList, i);
4103
4104 if (S57_samePtPos(geoNew, geoOld)) {
4105
4106 if (SECTRLIST != listNm)
4107 return TRUE;
4108 else {
4109 // check for extend arc radius
4110 GString *Asectr1str = S57_getAttVal(geoOld, "SECTR1");
4111 GString *Asectr2str = S57_getAttVal(geoOld, "SECTR2");
4112 GString *Bsectr1str = S57_getAttVal(geoNew, "SECTR1");
4113 GString *Bsectr2str = S57_getAttVal(geoNew, "SECTR2");
4114
4115 // check present
4116 if (NULL == Asectr1str ||
4117 NULL == Asectr1str ||
4118 NULL == Asectr1str ||
4119 NULL == Asectr1str)
4120 return FALSE;
4121
4122 {
4123 double Asectr1 = atof(Asectr1str->str);
4124 double Asectr2 = atof(Asectr2str->str);
4125 double Bsectr1 = atof(Bsectr1str->str);
4126 double Bsectr2 = atof(Bsectr2str->str);
4127 double Asweep = (Asectr1 > Asectr2) ?
4128 Asectr2-Asectr1+360 : Asectr2-Asectr1;
4129 double Bsweep = (Bsectr1 > Bsectr2) ?
4130 Bsectr2-Bsectr1+360 : Bsectr2-Bsectr1;
4131
4132 // check sector overlap
4133 if (Asectr2<=Bsectr1 || Asectr1>=Bsectr2) {
4134 if (Asweep == Bsweep) {
4135 g_string_truncate(Bsectr2str, 0);
4136 g_string_sprintf(Bsectr2str, "%f",Bsectr2-1);
4137 S57_setAtt(geoNew, "SECTR2", Bsectr2str->str);
4138 }
4139
4140 return FALSE;
4141 }
4142
4143 // check if other sector larger
4144 if (Asweep >= Bsweep)
4145 return TRUE;
4146 }
4147 }
4148 }
4149 }
4150
4151 return FALSE;
4152 }
4153
4154 static int _setPtPos(S57_geo *geo, int listNm)
4155 // TRUE if set new position of a light
4156 // else FALSE (ie there is a light at this position)
4157 {
4158 GPtrArray *curntList = _ptList[listNm];
4159
4160 if (_atPtPos(geo, listNm))
4161 return 1;
4162 else
4163 g_ptr_array_add(curntList, (gpointer) geo);
4164
4165 return 0;
4166 }
4167
4168 static int _parseList(const char *str, char *buf)
4169 // Put a string of comma delimited number in an array (buf).
4170 // Return: the number of value in buf.
4171 // Assume: - number < 256,
4172 // - list size less then LISTSIZE-1 .
4173 // Note: buf is \0 terminated for strpbrk().
4174 {
4175 int i = 0;
4176
4177 if (NULL != str && *str != '\0') {
4178 do {
4179 if ( i>= LISTSIZE-1) {
4180 PRINTF("OVERFLOW --value in list lost!!\n");
4181 break;
4182 }
4183
4184 /*
4185 if (255 < (unsigned char) atoi(str)) {
4186 PRINTF("value overflow (>255)\n");
4187 exit(0);
4188 }
4189 */
4190
4191 buf[i++] = (unsigned char) atoi(str);
4192
4193 while(isdigit(*str++)); // next
4194 //while( g_ascii_isdigit(c)); // next
4195
4196 } while(*str++ != '\0'); // skip ',' or exit
4197 }
4198
4199 buf[i] = '\0';
4200
4201 return i;
4202 }
4203
4204
4205 static GString *CLRLIN01 (S57_geo *geo)
4206 // Remarks: A clearing line shows a single arrow head at one of its ends. The direction
4207 // of the clearing line must be calculated from its line object in order to rotate
4208 // the arrow head symbol and place it at the correct end. This cannot be
4209 // achieved with a complex linestyle since linestyle symbols cannot be sized
4210 // to the length of the clearing line. Instead a linestyle with a repeating pattern
4211 // of arrow symbols had to be used which does not comply with the required
4212 // symbolization.
4213 {
4214
4215 PRINTF("Mariner's object not drawn\n");
4216
4217 return NULL;
4218 }
4219
4220 static GString *DATCVR01 (S57_geo *geo)
4221 // Remarks: This conditional symbology procedure describes procedures for:
4222 // - symbolizing the limit of ENC coverage;
4223 // - symbolizing navigational purpose boundaries ("scale boundarie"); and
4224 // - indicating overscale display.
4225 //
4226 // Note that the mandatory meta object CATQUA is symbolized by the look-up table.
4227 //
4228 // Because the methods adopted by an ECDIS to meet the IMO and IHO requirements
4229 // listed on the next page will depend on the manufacturer's software, and cannot be
4230 // described in terms of a flow chart in the same way as other conditional procedures,
4231 // this procedure is in the form of written notes.
4232 {
4233 GString *datcvr01 = NULL;
4234
4235 ///////////////////////
4236 // 1- REQUIREMENT
4237 // (IMO/IHO specs. explenation)
4238
4239 ///////////////////////
4240 // 2- ENC COVERAGE
4241 //
4242 // 2.1- Limit of ENC coverage
4243 //datcvr01 = g_string_new(";OP(3OD11060);LC(HODATA01)");
4244 // FIXME: get cell extend
4245
4246 // 2.2- No data areas
4247 // This can be done outside of CS (ie when clearing the screen in Mesa)
4248 // FIXME: ";OP(0---);AC(NODATA)"
4249 // FIXME: set geo to cover earth (!)
4250
4251 //////////////////////
4252 // 3- SCALE BOUNDARIES
4253 //
4254 // 3.1- Chart scale boundaties
4255 // FIXME;
4256 //g_string_append(datcvr01, ";LS(SOLD,1,CHGRD)");
4257 // -OR- LC(SCLBDYnn) (?)
4258 //
4259 // ;OP(3OS21030)
4260
4261 // 3.2- Graphical index of navigational purpose
4262 // FIXME: draw extent of available SENC in DB
4263
4264 //////////////////////
4265 // 4- OVERSCALE
4266 //
4267 // FIXME: get meta date CSCL of DSPM field
4268 // FIXME: get object M_CSCL or CSCALE
4269 //
4270 // 4.1- Overscale indication
4271 // FIXME: compute, scale = [denominator of the compilation scale] /
4272 // [denominator of the display scale]
4273 // FIXME: draw overscale indication (ie TX("X%3.1f",scale))
4274 //
4275 // 4.2- Ovescale area at a chart scale boundary
4276 // FIXME: test if next chart is over scale (ie going from large scale chart
4277 // to a small scale chart)
4278 // FIXME: draw AP(OVERSC01) on overscale part of display
4279 //g_string(";OP(3OS21030)");
4280
4281 //
4282 // 4.3- Larger scale data available
4283 // FIXME: display indication of better scale available (?)
4284
4285
4286 PRINTF("not computed\n");
4287
4288 return datcvr01;
4289 }
4290
4291 static GString *_SEABED01(double drval1, double drval2);
4292 static GString *_RESCSP01(S57_geo *geo);
4293 static GString *DEPARE01 (S57_geo *geo)
4294 // Remarks: An object of the class "depth area" is coloured and covered with fill patterns
4295 // according to the mariners selections of shallow contour, safety contour and
4296 // deep contour. This requires a decision making process provided by the sub-procedure
4297 // "SEABED01" which is called by this symbology procedure.
4298 // Objects of the class "dredged area" are handled by this routine as well to
4299 // ensure a consistent symbolization of areas that represent the surface of the
4300 // seabed.
4301 {
4302 GString *depare01 = NULL;
4303 int objl = 0;
4304 GString *objlstr = NULL;
4305 GString *drval1str = S57_getAttVal(geo, "DRVAL1");
4306 double drval1 = UNKNOWN;
4307 GString *drval2str = S57_getAttVal(geo, "DRVAL2");
4308 double drval2 = UNKNOWN;
4309
4310 if (NULL == drval1str || NULL == drval2str) {
4311 PRINTF("ERROR: drval1 or drval2 should have the value UNKNOWN\n");
4312 return NULL;
4313 }
4314
4315 drval1 = (NULL == drval1str) ? -1.0 : atof(drval1str->str);
4316 drval2 = (NULL == drval2str) ? drval1+0.01 : atof(drval2str->str);
4317
4318 depare01 = _SEABED01(drval1, drval2);
4319
4320 objlstr = S57_getAttVal(geo, "OBJL");
4321 objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
4322
4323 if (DRGARE == objl) {
4324 g_string_append(depare01, ";AP(DRGARE01)");
4325 g_string_append(depare01, ";LS(DASH,1,CHGRF)");
4326
4327 if (NULL != S57_getAttVal(geo, "RESTRN")) {
4328 GString *rescsp01 = _RESCSP01(geo);
4329 if (NULL != rescsp01) {
4330 g_string_append(depare01, rescsp01->str);
4331 g_string_free(rescsp01, TRUE);
4332 }
4333 }
4334
4335 }
4336
4337 return depare01;
4338 }
4339
4340 static GString *_SNDFRM02(S57_geo *geo, double depth_value);
4341 static GString *DEPCNT02 (S57_geo *geo)
4342 // Remarks: An object of the class "depth contour" or "line depth area" is highlighted and must
4343 // be shown under all circumstances if it matches the safety contour depth value
4344 // entered by the mariner (see IMO PS 3.6). But, while the mariner is free to enter any
4345 // safety contour depth value that he thinks is suitable for the safety of his ship, the
4346 // SENC only contains a limited choice of depth contours. This symbology procedure
4347 // determines whether a contour matches the selected safety contour. If the selected
4348 // safety contour does not exist in the data, the procedure will default to the next deeper
4349 // contour. The contour selected is highlighted as the safety contour and put in
4350 // DISPLAYBASE. The procedure also identifies any line segment of the spatial
4351 // component of the object that has a "QUAPOS" value indicating unreliable
4352 // positioning, and symbolizes it with a double dashed line.
4353 //
4354 // Note: Depth contours are not normally labeled. The ECDIS may provide labels, on demand
4355 // only as with other text, or provide the depth value on cursor picking
4356 {
4357 GString *depcnt02 = NULL;
4358 int safe = FALSE; // initialy not a safety contour
4359 GString *objlstr = NULL;
4360 int objl = 0;
4361 GString *quaposstr = NULL;
4362 int quapos = 0;
4363 double depth_value;
4364
4365 objlstr = S57_getAttVal(geo, "OBJL");
4366 objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
4367
4368 if (DEPARE==objl && LINES_T==S57_getObjtype(geo))
4369 {
4370 GString *drval1str = S57_getAttVal(geo, "DRVAL1");
4371 double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
4372 GString *drval2str = S57_getAttVal(geo, "DRVAL2");
4373 double drval2 = (NULL == drval2str) ? drval1 : atof(drval2str->str);
4374
4375 if (drval1 <= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
4376 {
4377 if (drval2 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
4378 safe = TRUE;
4379 }
4380 else
4381 {
4382 if (1 == S52_state)
4383 return NULL;
4384 else
4385 {
4386 S57_geo *geoTmp = geo;
4387
4388 // get area DEPARE & DRGARE that intersect this line
4389 while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
4390 drval1str = S57_getAttVal(geoTmp, "DRVAL1");
4391 drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
4392
4393 if (NULL == drval1str) {
4394 safe = TRUE;
4395 break;
4396 }
4397
4398 if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
4399 safe = TRUE;
4400 break;
4401 }
4402 }
4403 // debug trace
4404 //if (safe) PRINTF("** DEPARE: SAFE FOUND**\n");
4405 }
4406 }
4407
4408 depth_value = drval1;
4409
4410 }
4411 else
4412 {
4413 // continuation A (DEPCNT)
4414 GString *valdcostr = S57_getAttVal(geo, "VALDCO");
4415 double valdco = (NULL == valdcostr) ? 0.0 : atof(valdcostr->str);
4416
4417 depth_value = valdco;
4418
4419 if (valdco == S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
4420 safe = TRUE; // this is useless !?!?
4421 else
4422 {
4423 if (valdco > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
4424 if (1 == S52_state)
4425 return NULL;
4426 else {
4427 S57_geo *geoTmp = geo;
4428
4429 // get area DEPARE & DRGARE that intersect this line
4430 while (NULL != (geoTmp = S57_nextObj(geoTmp))){
4431 GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
4432 double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
4433
4434 if (NULL == drval1str) {
4435 safe = TRUE;
4436 break;
4437 }
4438
4439 if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
4440 safe = TRUE;
4441 break;
4442 }
4443 }
4444 // debug trace
4445 //if (safe) PRINTF("** DEPCN: SAFE FOUND**\n");
4446 }
4447 }
4448 }
4449 }
4450
4451 // Continuation B
4452 quaposstr = S57_getAttVal(geo, "QUAPOS");
4453 if (NULL != quaposstr) {
4454 quapos = atoi(quaposstr->str);
4455 if ( 2 <= quapos && quapos < 10) {
4456 if (safe)
4457 depcnt02 = g_string_new(";LS(DASH,2,DEPSC)");
4458 else
4459 depcnt02 = g_string_new(";LS(DASH,1,DEPCN)");
4460 }
4461 } else {
4462 if (safe)
4463 depcnt02 = g_string_new(";LS(SOLD,2,DEPSC)");
4464 else
4465 depcnt02 = g_string_new(";LS(SOLD,1,DEPCN)");
4466 }
4467
4468 if (safe) {
4469 S57_setAtt(geo, "SCAMIN", "INFINITE");
4470 depcnt02 = g_string_prepend(depcnt02, ";OP(8OD13010)");
4471 } else
4472 depcnt02 = g_string_prepend(depcnt02, ";OP(---33020)");
4473
4474 // facultative in S-52
4475 //if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
4476 // GString *sndfrm02 = _SNDFRM02(geo, depth_value);
4477 // depcnt02 = g_string_append(depcnt02, sndfrm02->str);
4478 // g_string_free(sndfrm02, TRUE);
4479 //}
4480
4481 // debug
4482 //PRINTF("depth= %f\n", depth_value);
4483
4484 S57_unlinkObj(geo);
4485
4486 return depcnt02;
4487 }
4488
4489 static double _DEPVAL01(S57_geo *geo, double least_depth)
4490 // Remarks: S-57 Appendix B1 Annex A requires in Section 6 that areas of rocks be
4491 // encoded as area obstruction, and that area OBSTRNs and area WRECKS
4492 // be covered by either group 1 object DEPARE or group 1 object UNSARE.
4493 // If the value of the attribute VALSOU for an area OBSTRN or WRECKS
4494 // is missing, the DRVAL1 of an underlying DEPARE is the preferred default
4495 // for establishing a depth value. This procedure either finds the shallowest
4496 // DRVAL1 of the one or more underlying DEPAREs, or returns an
4497 // "unknown"" depth value to the main procedure for the next default
4498 // procedure.
4499
4500 // NOTE: UNSARE test is useless since least_depth is already UNKNOWN
4501 {
4502 least_depth = UNKNOWN;
4503
4504
4505 S57_geo *geoTmp = geo;
4506
4507 // NOTE: the geo list is unchange (_UDWHAZ03 will unlink geo)
4508 while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
4509 GString *objlstr = S57_getAttVal(geoTmp, "OBJL");
4510 int objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
4511
4512 // get area DEPARE that intersect this area
4513 if (DEPARE==objl && LINES_T==S57_getObjtype(geo)) {
4514 GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
4515 double drval1 = (NULL == drval1str) ? 9.0 : atof(drval1str->str);
4516
4517 if (NULL != drval1str) {
4518 if (UNKNOWN==least_depth || least_depth<drval1)
4519 least_depth = drval1;
4520 }
4521
4522 }
4523 }
4524
4525 return least_depth;
4526 }
4527
4528 static GString *LEGLIN02 (S57_geo *geo)
4529
4530 // Remarks: The course of a leg is given by its start and end point. Therefore this
4531 // conditional symbology procedure calculates the course and shows it
4532 // alongside the leg. It also places the "distance to run" labels and cares for the
4533 // different presentation of planned & alternate legs.
4534 {
4535 PRINTF("Mariner's object not drawn\n");
4536 return NULL;
4537 }
4538
4539 static GString *_LITDSN01(S57_geo *geo);
4540 static GString *LIGHTS05 (S57_geo *geo)
4541 // Remarks: A light is one of the most complex S-57 objects. Its presentation depends on
4542 // whether it is a light on a floating or fixed platform, its range, it's colour and
4543 // so on. This conditional symbology procedure derives the correct
4544 // presentation from these parameters and also generates an area that shows the
4545 // coverage of the light.
4546 //
4547 // Notes on light sectors:
4548 // 1.) The radial leg-lines defining the light sectors are normally drawn to only 25mm
4549 // from the light to avoid clutter (see Part C). However, the mariner should be able to
4550 // select "full light-sector lines" and have the leg-lines extended to the nominal range
4551 // of the light (VALMAR).
4552 //
4553 // 2.) Part C of this procedure symbolizes the sectors at the light itself. In addition,
4554 // it should be possible, upon request, for the mariner to be capable of identifying
4555 // the colour and sector limit lines of the sectors affecting the ship even if the light
4556 // itself is off the display.
4557 // [ed. last sentence in bold]
4558
4559 // NOTE: why is this relationship not already encoded in S57 (ei. C_AGGR or C_STAC) ?
4560
4561 {
4562 GString *lights05 = NULL;
4563 GString *valnmrstr = S57_getAttVal(geo, "VALNMR");
4564 double valnmr = 0.0;
4565 GString *catlitstr = S57_getAttVal(geo, "CATLIT");
4566 char catlit[LISTSIZE] = {'\0'};
4567 int flare_at_45 = FALSE;
4568 int extend_arc_radius = TRUE;
4569 GString *sectr1str = NULL;
4570 GString *sectr2str = NULL;
4571 double sectr1 = 0.0;
4572 double sectr2 = 0.0;
4573 GString *colourstr = NULL;
4574 char colist[LISTSIZE] = {'\0'}; // colour list
4575 GString *orientstr = NULL;
4576 double sweep = 0.0;
4577
4578
4579 lights05 = g_string_new("");
4580
4581 valnmr = (NULL == valnmrstr) ? 9.0 : atof(valnmrstr->str);
4582
4583 if ( NULL != catlitstr) {
4584 _parseList(catlitstr->str, catlit);
4585
4586 // FIXME: OR vs AND/OR
4587 if (strpbrk(catlit, "\010\013")) {
4588 g_string_append(lights05, ";SY(LIGHTS82)");
4589 return lights05;
4590 }
4591
4592 if (strpbrk(catlit, "\011")) {
4593 g_string_append(lights05, ";SY(LIGHTS81)");
4594 return lights05;
4595 }
4596
4597 if (strpbrk(catlit, "\001\020")) {
4598 orientstr = S57_getAttVal(geo, "ORIENT");
4599 if (NULL != orientstr) {
4600 // FIXME: create a geo object (!?) LINE of lenght VALNMR
4601 // using ORIENT (from seaward) & POINT_T position
4602 g_string_append(lights05, ";LS(DASH,1,CHBLK)");
4603 }
4604 }
4605 }
4606
4607 // Continuation A
4608 colourstr = S57_getAttVal(geo, "COLOUR");
4609 if (NULL != colourstr)
4610 _parseList(colourstr->str, colist);
4611 else {
4612 colist[0] = '\014'; // maganta (12)
4613 colist[1] = '\000';
4614 }
4615
4616 sectr1str = S57_getAttVal(geo, "SECTR1");
4617 sectr1 = (NULL == sectr1str) ? 0.0 : atof(sectr1str->str);
4618 sectr2str = S57_getAttVal(geo, "SECTR2");
4619 sectr2 = (NULL == sectr2str) ? 0.0 : atof(sectr2str->str);
4620
4621 if (NULL==sectr1str || NULL==sectr2str) {
4622 // not a sector light
4623 char *sym;
4624
4625 if (1==S52_state) {
4626 _setPtPos(geo, LIGHTLIST);
4627 g_string_free(lights05, TRUE);
4628 return NULL;
4629 } else
4630 flare_at_45 = _atPtPos(geo, LIGHTLIST);
4631
4632 sym = _selSYcol(colist);
4633
4634 if (strpbrk(catlit, "\001\020")) {
4635 if (NULL != orientstr){
4636 g_string_append(lights05, sym);
4637 g_string_sprintfa(lights05, ",%s)", orientstr->str);
4638 g_string_append(lights05, ";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" );
4639 } else
4640 g_string_append(lights05, ";SY(QUSMRK1)");
4641 } else {
4642 g_string_append(lights05, sym);
4643 if (flare_at_45)
4644 g_string_append(lights05, ",145)");
4645 else
4646 g_string_append(lights05, ",135)");
4647 }
4648
4649 if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
4650 GString *litdsn01 = _LITDSN01(geo);
4651 if (NULL != litdsn01){
4652 g_string_append(lights05, ";TX('");
4653 g_string_append(lights05, litdsn01->str);
4654 g_string_free(litdsn01, TRUE);
4655
4656 if (flare_at_45)
4657 g_string_append(lights05, "',3,3,3,'15110',2,-1,CHBLK,23)" );
4658 else
4659 g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
4660 }
4661 }
4662
4663 return lights05;
4664 }
4665
4666 // Continuation B --sector light
4667 if (NULL == sectr1str) {
4668 sectr1 = 0.0;
4669 sectr2 = 0.0;
4670 } else
4671 sweep = (sectr1 > sectr2) ? sectr2-sectr1+360 : sectr2-sectr1;
4672
4673
4674 if (sweep<1.0 || sweep==360.0) {
4675 // handle all round light
4676 char *sym = _selSYcol(colist);;
4677
4678 g_string_append(lights05, sym);
4679 g_string_append(lights05, ",135)");
4680
4681 if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
4682 GString *litdsn01 = _LITDSN01(geo);
4683 if (NULL != litdsn01) {
4684 g_string_append(lights05, ";TX('");
4685 g_string_append(lights05, litdsn01->str);
4686 g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
4687 g_string_free(litdsn01, TRUE);
4688 }
4689
4690 }
4691
4692 return lights05;
4693 }
4694
4695 // scan for other lights with sector overlap at this position
4696 // compute light sector radius acording to other sector
4697 if (1 == S52_state) {
4698 _setPtPos(geo, SECTRLIST);
4699 g_string_free(lights05, TRUE);
4700 return NULL;
4701 } else {
4702 extend_arc_radius = _atPtPos(geo, SECTRLIST);
4703
4704 // passe value via attribs to _renderAC
4705 if (extend_arc_radius)
4706 // FIXME: draw radius 25 mm
4707 S57_setAtt(geo, "extend_arc_radius", "Y");
4708 else
4709 // FIXME: draw radius 20 mm
4710 S57_setAtt(geo, "extend_arc_radius", "N");
4711 }
4712
4713 // setup sector
4714 {
4715 char litvis[LISTSIZE] = {'\0'}; // list visibility
4716 GString *litvisstr = S57_getAttVal(geo, "LITVIS");
4717
4718 // sector leg --logic is _renderLS()
4719 g_string_append(lights05, ";LS(DASH,1,CHBLK)");
4720
4721 // get light vis.
4722 if (NULL != litvisstr) _parseList(litvisstr->str, litvis);
4723
4724 // faint light
4725 // FIXME: spec say OR (ie 1 number) the code is AND/OR
4726 if (strpbrk(litvis, "\003\007\010")) {
4727 // NOTE: LS(DASH,1,CHBLK)
4728 // pass flag to _renderAC()
4729 g_string_append(lights05, ";AC(CHBLK)");
4730 S57_setAtt(geo, "faint_light", "Y");
4731
4732 } else {
4733 // set arc colour
4734 char *sym = ";AC(CHMGD)"; // other
4735
4736 // max 1 color
4737 if ('\0' == colist[1]) {
4738 if (strpbrk(colist, "\003"))
4739 sym = ";AC(LITRD)";
4740 else if (strpbrk(colist, "\004"))
4741 sym = ";AC(LITGN)";
4742 else if (strpbrk(colist, "\001\006\013"))
4743 sym = ";AC(LITYW)";
4744 } else {
4745 // max 2 color
4746 if ('\0' == colist[2]) {
4747 if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
4748 sym = ";AC(LITRD)";
4749 else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
4750 sym = ";AC(LITGN)";
4751 }
4752 }
4753
4754 g_string_append(lights05, sym);
4755 }
4756 }
4757
4758 return lights05;
4759 }
4760
4761 static GString *_LITDSN01(S57_geo *geo)
4762 // Remarks: In S-57 the light characteristics are held as a series of attributes values. The
4763 // mariner may wish to see a light description text string displayed on the
4764 // screen similar to the string commonly found on a paper chart. This
4765 // conditional procedure, reads the attribute values from the above list of
4766 // attributes and composes a light description string which can be displayed.
4767 // This procedure is provided as a C function which has as input, the above
4768 // listed attribute values and as output, the light description.
4769 {
4770 GString *litdsn01 = g_string_new("");
4771 GString *gstr = NULL; // tmp
4772
4773 // FIXME: need grammar to create light's text
4774
4775 // CATLIT, LITCHR, COLOUR, HEIGHT, LITCHR, SIGGRP, SIGPER, STATUS, VALNMR
4776
4777 // CATLIT
4778 gstr = S57_getAttVal(geo, "CATLIT");
4779 if (NULL != gstr)
4780 g_string_append(litdsn01, gstr->str);
4781
4782 /*
4783 1: directional function IP 30.1-3; 475.7;
4784 2: rear/upper light
4785 3: front/lower light
4786 4: leading light IP 20.1-3; 475.6;
4787 5: aero light IP 60; 476.1;
4788 6: air obstruction light IP 61; 476.2;
4789 7: fog detector light IP 62; 477;
4790 8: flood light IP 63; 478.2;
4791 9: strip light IP 64; 478.5;
4792 10: subsidiary light IP 42; 471.8;
4793 11: spotlight
4794 12: front
4795 13: rear
4796 14: lower
4797 15: upper
4798 16: moire' effect IP 31; 475.8;
4799 17: emergency
4800 18: bearing light 478.1;
4801 19: horizontally disposed
4802 20: vertically disposed
4803 */
4804
4805 // LITCHR
4806 gstr = S57_getAttVal(geo, "LITCHR");
4807 if (NULL != gstr)
4808 g_string_append(litdsn01, gstr->str);
4809
4810 /*
4811 1: fixed IP 10.1;
4812 2: flashing IP 10.4;
4813 3: long-flashing IP 10.5;
4814 4: quick-flashing IP 10.6;
4815 5: very quick-flashing IP 10.7;
4816 6: ultra quick-flashing IP 10.8;
4817 7: isophased IP 10.3;
4818 8: occulting IP 10.2;
4819 9: interrupted quick-flashing IP 10.6;
4820 10: interrupted very quick-flashing IP 10.7;
4821 11: interrupted ultra quick-flashing IP 10.8;
4822 12: morse IP 10.9;
4823 13: fixed/flash IP 10.10;
4824 14: flash/long-flash
4825 15: occulting/flash
4826 16: fixed/long-flash
4827 17: occulting alternating
4828 18: long-flash alternating
4829 19: flash alternating
4830 20: group alternating
4831 21: 2 fixed (vertical)
4832 22: 2 fixed (horizontal)
4833 23: 3 fixed (vertical)
4834 24: 3 fixed (horizontal)
4835 25: quick-flash plus long-flash
4836 26: very quick-flash plus long-flash
4837 27: ultra quick-flash plus long-flash
4838 28: alternating
4839 29: fixed and alternating flashing
4840 */
4841
4842 // COLOUR,
4843 gstr = S57_getAttVal(geo, "COLOUR");
4844 if (NULL != gstr)
4845 g_string_append(litdsn01, gstr->str);
4846
4847 /*
4848 1: white IP 11.1; 450.2-3;
4849 2: black
4850 3: red IP 11.2; 450.2-3;
4851 4: green IP 11.3; 450.2-3;
4852 5: blue IP 11.4; 450.2-3;
4853 6: yellow IP 11.6; 450.2-3;
4854 7: grey
4855 8: brown
4856 9: amber IP 11.8; 450.2-3;
4857 10: violet IP 11.5; 450.2-3;
4858 11: orange IP 11.7; 450.2-3;
4859 12: magenta
4860 13: pink
4861 */
4862
4863 // HEIGHT, xxx.x
4864 gstr = S57_getAttVal(geo, "HEIGHT");
4865 if (NULL != gstr)
4866 g_string_append(litdsn01, gstr->str);
4867
4868
4869 // SIGGRP, (c)(c) ...
4870 gstr = S57_getAttVal(geo, "SIGGRP");
4871 if (NULL != gstr)
4872 g_string_append(litdsn01, gstr->str);
4873
4874
4875 // SIGPER, xx.xx
4876 gstr = S57_getAttVal(geo, "SIGPER");
4877 if (NULL != gstr)
4878 g_string_append(litdsn01, gstr->str);
4879
4880
4881 // STATUS,
4882 gstr = S57_getAttVal(geo, "STATUS");
4883 if (NULL != gstr)
4884 g_string_append(litdsn01, gstr->str);
4885
4886 /*
4887 1: permanent
4888 2: occasional IP 50; 473.2;
4889 3: recommended IN 10; 431.1;
4890 4: not in use IL 14, 44; 444.7;
4891 5: periodic/intermittent IC 21; IQ 71; 353.3; 460.5;
4892 6: reserved IN 12.9;
4893 7: temporary IP 54;
4894 8: private IQ 70;
4895 9: mandatory
4896 10: destroyed/ruined
4897 11: extinguished
4898 12: illuminated
4899 13: historic
4900 14: public
4901 15: synchronized
4902 16: watched
4903 17: un-watched
4904 18: existence doubtful
4905 */
4906
4907 // VALNMR, xx.x
4908 gstr = S57_getAttVal(geo, "VALNMR");
4909 if (NULL != gstr)
4910 g_string_append(litdsn01, gstr->str);
4911
4912
4913 PRINTF("FIXME: lights description not translated into text\n");
4914
4915 return litdsn01;
4916 }
4917
4918 static GString *_UDWHAZ03(S57_geo *geo, double depth_value);
4919 static GString *_QUAPNT01(S57_geo *geo);
4920
4921 static GString *OBSTRN04 (S57_geo *geo)
4922 // Remarks: Obstructions or isolated underwater dangers of depths less than the safety
4923 // contour which lie within the safe waters defined by the safety contour are
4924 // to be presented by a specific isolated danger symbol and put in IMO
4925 // category DISPLAYBASE (see (3), App.2, 1.3). This task is performed
4926 // by the sub-procedure "UDWHAZ03" which is called by this symbology
4927 // procedure. Objects of the class "under water rock" are handled by this
4928 // routine as well to ensure a consistent symbolization of isolated dangers on
4929 // the seabed.
4930 {
4931 GString *obstrn04str = g_string_new("");
4932 GString *sndfrm02str = NULL;
4933 GString *udwhaz03str = NULL;
4934 GString *valsoustr = S57_getAttVal(geo, "VALSOU");
4935 double valsou = UNKNOWN;
4936 double depth_value = UNKNOWN;
4937 double least_depth = UNKNOWN;
4938
4939 // exit if not in drawing state
4940 if (1 == S52_state)
4941 return NULL;
4942
4943 if (NULL != valsoustr) {
4944 valsou = atof(valsoustr->str);
4945 depth_value = valsou;
4946 sndfrm02str = _SNDFRM02(geo, depth_value);
4947 } else {
4948 if (AREAS_T == S57_getObjtype(geo))
4949 least_depth = _DEPVAL01(geo, least_depth);
4950
4951 if (UNKNOWN != least_depth) {
4952 GString *catobsstr = S57_getAttVal(geo, "CATOBS");
4953 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
4954
4955 if (NULL != catobsstr && '6' == *catobsstr->str)
4956 depth_value = 0.01;
4957 else
4958 if (NULL == watlevstr) // default
4959 depth_value = -15.0;
4960 else {
4961 switch (*watlevstr->str){
4962 case '5': depth_value = 0.0 ; break;
4963 case '3': depth_value = 0.01; break;
4964 case '4':
4965 case '1':
4966 case '2':
4967 default : depth_value = -15.0 ; break;
4968 }
4969 }
4970 } else
4971 depth_value = least_depth;
4972 }
4973
4974 udwhaz03str = _UDWHAZ03(geo, depth_value);
4975
4976 if (POINT_T == S57_getObjtype(geo)) {
4977 // Continuation A
4978 int sounding = FALSE;
4979 GString *quapnt01str = _QUAPNT01(geo);
4980
4981 if (NULL != udwhaz03str){
4982 g_string_append(obstrn04str, udwhaz03str->str);
4983 if (NULL != quapnt01str)
4984 g_string_append(obstrn04str, quapnt01str->str);
4985
4986 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
4987 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
4988 if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
4989
4990 return obstrn04str;
4991 }
4992
4993 if (UNKNOWN != valsou) {
4994 if (valsou <= 20.0) {
4995 GString *objlstr = S57_getAttVal(geo, "OBJL");
4996 int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
4997 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
4998
4999 if (UWTROC == objl) {
5000 if (NULL == watlevstr) { // default
5001 g_string_append(obstrn04str, ";SY(DANGER01)");
5002 sounding = TRUE;
5003 } else {
5004 switch (*watlevstr->str){
5005 case '3': g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE ; break;
5006 case '4':
5007 case '5': g_string_append(obstrn04str, ";SY(UWTROC04)"); sounding = FALSE; break;
5008 default : g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE ; break;
5009 }
5010 }
5011 } else { // OBSTRN
5012 if (NULL == watlevstr) { // default
5013 g_string_append(obstrn04str, ";SY(DANGER01)");
5014 sounding = TRUE;
5015 } else {
5016 switch (*watlevstr->str) {
5017 case '1':
5018 case '2': g_string_append(obstrn04str, ";SY(OBSTRN11)"); sounding = FALSE; break;
5019 case '3': g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE; break;
5020 case '4':
5021 case '5': g_string_append(obstrn04str, ";SY(DANGER03)"); sounding = TRUE; break;
5022 default : g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE; break;
5023 }
5024 }
5025 }
5026 } else { // valsou > 20.0
5027 g_string_append(obstrn04str, ";SY(DANGER02)");
5028 sounding = FALSE;
5029 }
5030
5031 } else { // NO valsou
5032 GString *objlstr = S57_getAttVal(geo, "OBJL");
5033 int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
5034 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
5035
5036 if (UWTROC == objl) {
5037 if (NULL == watlevstr) // default
5038 g_string_append(obstrn04str, ";SY(UWTROC04)");
5039 else {
5040 if ('3' == *watlevstr->str)
5041 g_string_append(obstrn04str, ";SY(UWTROC03)");
5042 else
5043 g_string_append(obstrn04str, ";SY(UWTROC04)");
5044 }
5045
5046 } else { // OBSTRN
5047 if ( NULL == watlevstr) // default
5048 g_string_append(obstrn04str, ";SY(OBSTRN01)");
5049 else {
5050 switch (*watlevstr->str) {
5051 case '1':
5052 case '2': g_string_append(obstrn04str, ";SY(OBSTRN11)"); break;
5053 case '3': g_string_append(obstrn04str, ";SY(OBSTRN01)"); break;
5054 case '4':
5055 case '5':
5056 default : g_string_append(obstrn04str, ";SY(OBSTRN01)"); break;
5057 }
5058 }
5059 }
5060
5061 }
5062
5063 if (sounding && NULL != sndfrm02str)
5064 g_string_append(obstrn04str, sndfrm02str->str);
5065
5066 if (NULL != quapnt01str)
5067 g_string_append(obstrn04str, quapnt01str->str);
5068
5069 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
5070 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
5071 if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
5072
5073 return obstrn04str;
5074
5075 } else {
5076 if (LINES_T == S57_getObjtype(geo)) {
5077 // Continuation B
5078 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
5079 int quapos = 0;
5080
5081 if (NULL != quaposstr) {
5082 quapos = atoi(quaposstr->str);
5083 if ( 2 <= quapos && quapos < 10){
5084 if (NULL != udwhaz03str)
5085 g_string_append(obstrn04str, ";LC(LOWACC41)");
5086 else
5087 g_string_append(obstrn04str, ";LC(LOWACC31)");
5088 }
5089 }
5090
5091 if (NULL != udwhaz03str)
5092 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
5093
5094 if (UNKNOWN != valsou)
5095 if (valsou <= 20.0)
5096 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
5097 else
5098 g_string_append(obstrn04str, ";LS(DASH,2,CHBLK)");
5099 else
5100 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
5101
5102
5103 if (NULL != udwhaz03str)
5104 g_string_append(obstrn04str, udwhaz03str->str);
5105 else {
5106 if (UNKNOWN != valsou)
5107 if (valsou <= 20.0)
5108 g_string_append(obstrn04str, sndfrm02str->str);
5109 }
5110
5111 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
5112 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
5113
5114 return obstrn04str;
5115
5116 } else {
5117 // Continuation C (AREAS_T)
5118 GString *quapnt01str = _QUAPNT01(geo);
5119 if (NULL != udwhaz03str) {
5120 g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01)");
5121 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
5122 g_string_append(obstrn04str, udwhaz03str->str);
5123 if (NULL != quapnt01str)
5124 g_string_append(obstrn04str, quapnt01str->str);
5125
5126 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
5127 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
5128 if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
5129
5130 return obstrn04str;
5131 }
5132
5133 if (UNKNOWN != valsou) {
5134 // BUG in CA49995B.000 if we get here because there is no color
5135 // beside NODATA (ie there is a hole in group 1 area!)
5136 //g_string_append(obstrn04, ";AC(UINFR)");
5137
5138 if (valsou <= 20.0)
5139 g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
5140 else
5141 g_string_append(obstrn04str, ";LS(DASH,2,CHBLK)");
5142
5143 g_string_append(obstrn04str, sndfrm02str->str);
5144
5145 } else {
5146 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
5147
5148 if (NULL == watlevstr) // default
5149 g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)");
5150 else {
5151 if ('3' == *watlevstr->str) {
5152 GString *catobsstr = S57_getAttVal(geo, "CATOBS");
5153 if (NULL != catobsstr && '6' == *catobsstr->str)
5154 g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)");
5155 } else {
5156 switch (*watlevstr->str) {
5157 case '1':
5158 case '2': g_string_append(obstrn04str, ";AC(CHBRN);LS(SOLD,2,CSTLN)"); break;
5159 case '4': g_string_append(obstrn04str, ";AC(DEPIT);LS(DASH,2,CSTLN)"); break;
5160 case '5':
5161 case '3':
5162 default : g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)"); break;
5163 }
5164 }
5165 }
5166 }
5167
5168 g_string_append(obstrn04str, quapnt01str->str);
5169
5170 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
5171 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
5172 if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
5173
5174
5175 return obstrn04str;
5176 }
5177
5178 }
5179
5180
5181 // check if one exit point could do!!!
5182 return NULL;
5183 }
5184
5185 static GString *OWNSHP02 (S57_geo *geo)
5186 // Remarks:
5187 // 1. CONNING POSITION
5188 // 1.1 When own-ship is drawn to scale, the conning position must be correctly located in
5189 // relation to the ship's outline. The conning position then serves as the pivot point for
5190 // the own-ship symbol, to be located by the ECDIS at the correct latitude, longitude
5191 // for the conning point, as computed from the positioning system, correcting for
5192 // antenna offset.
5193 // 1.2 In this procedure it is assumed that the heading line, beam bearing line and course
5194 // and speed vector originate at the conning point. If another point of origin is used,
5195 // for example to account for the varying position of the ships turning centre, this must
5196 // be made clear to the mariner.
5197 //
5198 // 2. DISPLAY OPTIONS
5199 // 2.1 Only the ship symbol is mandatory for an ECDIS. The mariner should be prompted
5200 // to select from the following additional optional features:
5201 // - display own-ship as:
5202 // 1. symbol, or
5203 // 2. scaled outline
5204 // - select time period determining vector length for own-ship and other vessel course and speed
5205 // vectors, (all vectors must be for the same time period),
5206 // - display own-ship vector,
5207 // - select ground or water stabilization for all vectors, and select whether to display the type of
5208 // stabilization, (by arrowhead),
5209 // - select one-minute or six-minute vector time marks,
5210 // - select whether to show a heading line, to the edge of the display window,
5211 // - select whether to show a beam bearing line, and if so what length (default: 10mm total
5212 // length).
5213 {
5214 PRINTF("Mariner's object not drawn\n");
5215 return NULL;
5216 }
5217
5218 static GString *PASTRK01 (S57_geo *geo)
5219 // Remarks: This conditional symbology procedure was designed to allow the mariner
5220 // to select time labels at the pasttrack (see (3) 10.5.11.1). The procedure also
5221 // cares for the presentation of primary and secondary pasttrack.
5222 //
5223 // The manufacturer should define his own data class (spatial primitive) in xyt
5224 // (position and time) in order to represent Pastrk.
5225 {
5226
5227 PRINTF("Mariner's object not drawn\n");
5228 return NULL;
5229 }
5230
5231 static GString *_QUALIN01(S57_geo *geo);
5232 static GString *QUAPOS01 (S57_geo *geo)
5233 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
5234 // to the spatial object, not the feature object.
5235 //
5236 // This procedure passes the object to procedure QUALIN01 or QUAPNT01,
5237 // which traces back to the spatial object, retrieves any QUAPOS attributes,
5238 // and returns the appropriate symbolization to QUAPOS01.
5239 {
5240 GString *quapos01 = NULL;
5241
5242 if (LINES_T == S57_getObjtype(geo))
5243 quapos01 = _QUALIN01(geo);
5244 else
5245 quapos01 = _QUAPNT01(geo);
5246
5247 return quapos01;
5248 }
5249
5250 static GString *_QUALIN01(S57_geo *geo)
5251 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
5252 // only to the spatial component(s) of an object.
5253 //
5254 // A line object may be composed of more than one spatial object.
5255 //
5256 // This procedure looks at each of the spatial
5257 // objects, and symbolizes the line according to the positional accuracy.
5258 {
5259 GString *qualino1 = NULL;
5260 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
5261 int quapos = 0;
5262 char *line = NULL;
5263
5264 if (NULL != quaposstr) {
5265 quapos = atoi(quaposstr->str);
5266 if ( 2 <= quapos && quapos < 10)
5267 line = ";LC(LOWACC21)";
5268 } else {
5269 GString *objlstr = S57_getAttVal(geo, "OBJL");
5270 int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
5271
5272 if (COALNE == objl) {
5273 GString *conradstr = S57_getAttVal(geo, "CONRAD");
5274
5275 if (NULL != conradstr) {
5276 if ('1' == *conradstr->str)
5277 line = ";LS(SOLD,3,CHMGF);LS(SOLD,1,CSTLN)";
5278 else
5279 line = ";LS(SOLD,1,CSTLN)";
5280 } else
5281 line = ";LS(SOLD,1,CSTLN)";
5282
5283 } else //LNDARE
5284 line = ";LS(SOLD,1,CSTLN)";
5285 }
5286
5287 if (NULL != line)
5288 qualino1 = g_string_new(line);
5289
5290 return qualino1;
5291 }
5292
5293 static GString *_QUAPNT01(S57_geo *geo)
5294 // Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
5295 // only to the spatial component(s) of an object.
5296 //
5297 // This procedure retrieves any QUAPOS attributes, and returns the
5298 // appropriate symbols to the calling procedure.
5299 {
5300 GString *quapnt01 = NULL;
5301 int accurate = TRUE;
5302 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
5303 int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
5304
5305 if (NULL != quaposstr) {
5306 if ( 2 <= quapos && quapos < 10)
5307 accurate = FALSE;
5308 }
5309
5310 if (accurate)
5311 quapnt01 = g_string_new(";SY(LOWACC01)");
5312
5313 return quapnt01;
5314 }
5315
5316 static GString *SLCONS03 (S57_geo *geo)
5317 // Remarks: Shoreline construction objects which have a QUAPOS attribute on their
5318 // spatial component indicating that their position is unreliable are symbolized
5319 // by a special linestyle in the place of the varied linestyles normally used.
5320 // Otherwise this procedure applies the normal symbolization.
5321 {
5322 GString *slcons03 = NULL;
5323 GString *valstr = NULL;
5324 char *cmdw = NULL; // command word
5325 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
5326 int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
5327
5328 if (POINT_T == S57_getObjtype(geo)) {
5329 if (NULL != quaposstr) {
5330 if (2 <= quapos && quapos < 10)
5331 cmdw =";SY(LOWACC01)";
5332 }
5333 } else {
5334 // LINE_T and AREA_T are the same
5335 if (NULL != quaposstr) {
5336 if (2 <= quapos && quapos < 10)
5337 cmdw =";LC(LOWACC01)";
5338 } else {
5339 valstr = S57_getAttVal(geo, "CONDTN");
5340
5341 if (NULL != valstr && ( '1' == *valstr->str || '2' == *valstr->str))
5342 cmdw = ";LS(DASH,1,CSTLN)";
5343 else {
5344 int val = 0;
5345 valstr = S57_getAttVal(geo, "CATSLC");
5346 val = (NULL == valstr)? 0 : atoi(valstr->str);
5347
5348 if (NULL != valstr && ( 6 == val || 15 == val || 16 == val ))
5349 cmdw = ";LS(SOLD,4,CSTLN)";
5350 else {
5351 valstr = S57_getAttVal(geo, "WATLEV");
5352
5353 if (NULL != valstr && '2' == *valstr->str)
5354 cmdw = ";LS(SOLD,2,CSTLN)";
5355 else
5356 if (NULL != valstr && ('3' == *valstr->str || '4' == *valstr->str))
5357 cmdw = ";LS(DASH,2,CSTLN)";
5358 else
5359 cmdw = ";LS(SOLD,2,CSTLN)"; // default
5360
5361 }
5362 }
5363 }
5364 }
5365
5366 // WARNING: not explicitly specified in S-52 !!
5367 // FIXME:this is to put AC(DEPIT) --intertidal area
5368 // Could this be bug in OGR ?
5369 /*
5370 if (AREAS_T == S57_getObjtype(geo)) {
5371 GString *seabed01 = NULL;
5372 GString *drval1str = S57_getAttVal(geo, "DRVAL1");
5373 double drval1 = (NULL == drval1str)? -UNKNOWN : atof(drval1str->str);
5374 GString *drval2str = S57_getAttVal(geo, "DRVAL2");
5375 double drval2 = (NULL == drval2str)? -UNKNOWN : atof(drval2str->str);
5376 // NOTE: change sign of infinity (minus) to get out of bound in seabed01
5377
5378
5379 PRINTF("***********drval1=%f drval2=%f \n", drval1, drval2);
5380 seabed01 = _SEABED01(drval1, drval2);
5381 slcons03 = g_string_new(seabed01->str);
5382 g_string_free(seabed01, TRUE);
5383
5384 }
5385 */
5386
5387 if (NULL != cmdw) {
5388 if (NULL == slcons03)
5389 slcons03 = g_string_new(cmdw);
5390 else
5391 g_string_append(slcons03, cmdw);
5392 }
5393
5394 return slcons03;
5395 }
5396
5397 static GString *RESARE02 (S57_geo *geo)
5398 // Remarks: A list-type attribute is used because an area of the object class RESARE may
5399 // have more than one category (CATREA). For example an inshore traffic
5400 // zone might also have fishing and anchoring prohibition and a prohibited
5401 // area might also be a bird sanctuary or a mine field.
5402 //
5403 // This conditional procedure is set up to ensure that the categories of most
5404 // importance to safe navigation are prominently symbolized, and to pass on
5405 // all given information with minimum clutter. Only the most significant
5406 // restriction is symbolized, and an indication of further limitations is given by
5407 // a subscript "!" or "I". Further details are given under conditional
5408 // symbology procedure RESTRN01
5409 //
5410 // Other object classes affected by attribute RESTRN are handled by
5411 // conditional symbology procedure RESTRN01.
5412 {
5413 GString *resare02 = g_string_new("");
5414 GString *restrnstr = S57_getAttVal(geo, "RESTRN");
5415 char restrn[LISTSIZE] = {'\0'};
5416 GString *catreastr = S57_getAttVal(geo, "CATREA");
5417 char catrea[LISTSIZE] = {'\0'};
5418 char *symb = NULL;
5419 char *line = NULL;
5420 char *prio = NULL;
5421
5422 if ( NULL != restrnstr) {
5423 _parseList(restrnstr->str, restrn);
5424
5425 if (NULL != catreastr) _parseList(catreastr->str, catrea);
5426
5427 if (strpbrk(restrn, "\007\010\016")) {
5428 // Continuation A
5429 if (strpbrk(restrn, "\001\002\003\004\005\006"))
5430 symb = ";SY(ENTRES61)";
5431 else {
5432 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
5433 symb = ";SY(ENTRES61)";
5434 else {
5435 if (strpbrk(restrn, "\011\012\013\014\015"))
5436 symb = ";SY(ENTRES71)";
5437 else {
5438 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
5439 symb = ";SY(ENTRES71)";
5440 else
5441 symb = ";SY(ENTRES51)";
5442 }
5443 }
5444 }
5445
5446 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
5447 line = ";LC(CTYARE51)";
5448 else
5449 line = ";LS(DASH,2,CHMGD)";
5450
5451 prio = ";OP(6---)"; // display prio set to 6
5452
5453 } else {
5454 if (strpbrk(restrn, "\001\002")) {
5455 // Continuation B
5456 if (strpbrk(restrn, "\003\004\005\006"))
5457 symb = ";SY(ACHRES61)";
5458 else {
5459 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
5460 symb = ";SY(ACHRES61)";
5461 else {
5462 if (strpbrk(restrn, "\011\012\013\014\015"))
5463 symb = ";SY(ACHRES71)";
5464 else {
5465 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
5466 symb = ";SY(ACHRES71)";
5467 else
5468 symb = ";SY(ACHRES51)";
5469 }
5470 }
5471 }
5472
5473 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
5474 line = ";LC(ACHRE51)";
5475 else
5476 line = ";LS(DASH,2,CHMGD)";
5477
5478 prio = ";OP(6---)"; // display prio set to 6
5479
5480 } else {
5481 if (strpbrk(restrn, "\003\004\005\006")) {
5482 // Continuation C
5483 if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
5484 symb = ";SY(FSHRES51)";
5485 else {
5486 if (strpbrk(restrn, "\011\012\013\014\015"))
5487 symb = ";SY(FSHRES71)";
5488 else{
5489 if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
5490 symb = ";SY(FSHRES71)";
5491 else
5492 symb = ";SY(FSHRES51)";
5493 }
5494 }
5495
5496 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
5497 line = ";LC(FSHRES51)";
5498 else
5499 line = ";LS(DASH,2,CHMGD)";
5500
5501 prio = ";OP(6---)"; // display prio set to 6
5502
5503 } else {
5504 if (strpbrk(restrn, "\011\012\013\014\015"))
5505 symb = ";SY(INFARE51)";
5506 else
5507 symb = ";SY(RSRDEF51)";
5508
5509 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
5510 line = ";LC(CTYARE51)";
5511 else
5512 line = ";LS(DASH,2,CHMGD)";
5513
5514 }
5515 }
5516 }
5517
5518 } else {
5519 // Continuation D
5520 if (NULL != catreastr) {
5521 if (strpbrk(catrea, "\001\010\011\014\016\023\025\031")) {
5522 if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
5523 symb = ";SY(CTYARE71)";
5524 else
5525 symb = ";SY(CTYARE51)";
5526 } else {
5527 if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
5528 symb = ";SY(INFARE71)";
5529 else
5530 symb = ";SY(RSRDEF51)";
5531 }
5532 } else
5533 symb = ";SY(RSRDEF51)";
5534
5535 if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
5536 line = ";LC(CTYARE51)";
5537 else
5538 line = ";LS(DASH,2,CHMGD)";
5539 }
5540
5541 // create command word
5542 if (NULL != prio)
5543 g_string_append(resare02, prio);
5544 g_string_append(resare02, line);
5545 g_string_append(resare02, symb);
5546
5547 return resare02;
5548 }
5549
5550 static GString *RESTRN01 (S57_geo *geo)
5551 // Remarks: Objects subject to RESTRN01 are actually symbolised in sub-process
5552 // RESCSP01, since the latter can also be accessed from other conditional
5553 // symbology procedures. RESTRN01 merely acts as a "signpost" for
5554 // RESCSP01.
5555 //
5556 // Object class RESARE is symbolised for the effect of attribute RESTRN in a separate
5557 // conditional symbology procedure called RESARE02.
5558 //
5559 // Since many of the areas concerned cover shipping channels, the number of symbols used
5560 // is minimised to reduce clutter. To do this, values of RESTRN are ranked for significance
5561 // as follows:
5562 // "Traffic Restriction" values of RESTRN:
5563 // (1) RESTRN 7,8: entry prohibited or restricted
5564 // RESTRN 14: IMO designated "area to be avoided" part of a TSS
5565 // (2) RESTRN 1,2: anchoring prohibited or restricted
5566 // (3) RESTRN 3,4,5,6: fishing or trawling prohibited or restricted
5567 // (4) "Other Restriction" values of RESTRN are:
5568 // RESTRN 9, 10: dredging prohibited or restricted,
5569 // RESTRN 11,12: diving prohibited or restricted,
5570 // RESTRN 13 : no wake area.
5571 {
5572 GString *restrn01str = S57_getAttVal(geo, "RESTRN");
5573 GString *restrn01 = NULL;
5574
5575 if (NULL != restrn01str)
5576 restrn01 = _RESCSP01(geo);
5577 else
5578 restrn01 = g_string_new(";OP(----)"); // return NOOP to silence error msg
5579
5580 return restrn01;
5581 }
5582
5583 static GString *_RESCSP01(S57_geo *geo)
5584 // Remarks: See procedure RESTRN01
5585 {
5586 GString *rescsp01 = NULL;
5587 GString *restrnstr = S57_getAttVal(geo, "RESTRN");
5588 char restrn[LISTSIZE] = {'\0'}; // restriction list
5589 char *symb = NULL;
5590
5591 if ( NULL != restrnstr) {
5592 _parseList(restrnstr->str, restrn);
5593
5594 if (strpbrk(restrn, "\007\010\016")) {
5595 // continuation A
5596 if (strpbrk(restrn, "\001\002\003\004\005\006"))
5597 symb = ";SY(ENTRES61)";
5598 else {
5599 if (strpbrk(restrn, "\011\012\013\014\015"))
5600 symb = ";SY(ENTRES71)";
5601 else
5602 symb = ";SY(ENTRES51)";
5603
5604 }
5605 } else {
5606 if (strpbrk(restrn, "\001\002")) {
5607 // continuation B
5608 if (strpbrk(restrn, "\003\004\005\006"))
5609 symb = ";SY(ACHRES61)";
5610 else {
5611 if (strpbrk(restrn, "\011\012\013\014\015"))
5612 symb = ";SY(ACHRES71)";
5613 else
5614 symb = ";SY(ACHRES51)";
5615 }
5616
5617
5618 } else {
5619 if (strpbrk(restrn, "\003\004\005\006")) {
5620 // continuation C
5621 if (strpbrk(restrn, "\011\012\013\014\015"))
5622 symb = ";SY(FSHRES71)";
5623 else
5624 symb = ";SY(FSHRES51)";
5625
5626
5627 } else {
5628 if (strpbrk(restrn, "\011\012\013\014\015"))
5629 symb = ";SY(INFARE51)";
5630 else
5631 symb = ";SY(RSRDEF51)";
5632
5633 }
5634 }
5635 }
5636
5637 rescsp01 = g_string_new(symb);
5638 }
5639
5640 return rescsp01;
5641 }
5642
5643 static GString *_SEABED01(double drval1, double drval2)
5644 // Remarks: An area object that is part of the seabed is coloured as necessary according
5645 // to the mariners selection of two shades, (shallow contour, safety contour,
5646 // deep contour), or four shades (safety contour only). This requires a decision
5647 // making process provided by this conditional symbology procedure. Note
5648 // that this procedure is called as a sub-procedure by other conditional
5649 // symbology procedures.
5650 //
5651 // Note: The requirement to show four depth shades is not mandatory. Also,
5652 // the requirement to show the shallow pattern is not mandatory. However,
5653 // both these features are strongly recommended.
5654
5655 // return: is never NULL
5656
5657 {
5658 GString *seabed01 = NULL;
5659 gboolean shallow = TRUE;
5660 char *arecol = ";AC(DEPIT)";
5661
5662 if (drval1 >= 0.0 && drval2 > 0.0)
5663 arecol = ";AC(DEPVS)";
5664
5665 if (TRUE == S52_getMarinerParam(S52_MAR_TWO_SHADES)){
5666 if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
5667 drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
5668 arecol = ";AC(DEPDW)";
5669 shallow = FALSE;
5670 }
5671 } else {
5672 if (drval1 >= S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) &&
5673 drval2 > S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR))
5674 arecol = ";AC(DEPMS)";
5675
5676 if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
5677 drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
5678 arecol = ";AC(DEPMD)";
5679 shallow = FALSE;
5680 }
5681
5682 if (drval1 >= S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) &&
5683 drval2 > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR)) {
5684 arecol = ";AC(DEPDW)";
5685 shallow = FALSE;
5686 }
5687
5688 }
5689
5690 seabed01 = g_string_new(arecol);
5691
5692 if (TRUE==S52_getMarinerParam(S52_MAR_SHALLOW_PATTERN) && TRUE==shallow)
5693 g_string_append(seabed01, ";AP(DIAMOND1)");
5694
5695 return seabed01;
5696 }
5697
5698 static GString *SOUNDG02 (S57_geo *geo)
5699 // Remarks: In S-57 soundings are elements of sounding arrays rather than individual
5700 // objects. Thus this conditional symbology procedure examines each
5701 // sounding of a sounding array one by one. To symbolize the depth values it
5702 // calls the procedure SNDFRM02 which in turn translates the depth values
5703 // into a set of symbols to be shown at the soundings position.
5704 {
5705 guint npt = 0;
5706 double *ppt = NULL;
5707
5708 if (POINT_T != S57_getObjtype(geo)) {
5709 PRINTF("invalid object type (not M_PNT_T)\n");
5710 //return NULL;
5711 exit(0);
5712 }
5713
5714 S57_getGeoData(geo, 0, &npt, &ppt);
5715
5716 return _SNDFRM02(geo, ppt[2]);
5717 }
5718
5719 static GString *_SNDFRM02(S57_geo *geo, double depth_value)
5720 // Remarks: Soundings differ from plain text because they have to be readable under all
5721 // circumstances and their digits are placed according to special rules. This
5722 // conditional symbology procedure accesses a set of carefully designed
5723 // sounding symbols provided by the symbol library and composes them to
5724 // sounding labels. It symbolizes swept depth and it also symbolizes for low
5725 // reliability as indicated by attributes QUASOU and QUAPOS.
5726 {
5727 GString *sndfrm02 = g_string_new("");
5728 char *symbol_prefix = NULL;
5729 GString *tecsoustr = S57_getAttVal(geo, "TECSOU");
5730 char tecsou[LISTSIZE] = {'\0'};
5731 GString *quasoustr = S57_getAttVal(geo, "QUASOU");
5732 char quasou[LISTSIZE] = {'\0'};
5733 GString *statusstr = S57_getAttVal(geo, "STATUS");
5734 char status[LISTSIZE] = {'\0'};
5735 double leading_digit = 0.0;
5736
5737 // FIXME: test to fix the rounding error (!?)
5738 depth_value += (depth_value > 0.0)? 0.01: -0.01;
5739 leading_digit = (int) depth_value;
5740
5741 if (depth_value <= S52_getMarinerParam(S52_MAR_SAFETY_DEPTH))
5742 symbol_prefix = "SOUNDS";
5743 else
5744 symbol_prefix = "SOUNDG";
5745
5746 if (NULL != tecsoustr) {
5747 _parseList(tecsoustr->str, tecsou);
5748 if (strpbrk(tecsou, "\006"))
5749 g_string_sprintfa(sndfrm02, ";SY(%sB1)", symbol_prefix);
5750 }
5751
5752 if (NULL != quasoustr) _parseList(quasoustr->str, quasou);
5753 if (NULL != statusstr) _parseList(statusstr->str, status);
5754
5755 if (strpbrk(quasou, "\003\004\005\010\011") || strpbrk(status, "\022"))
5756 g_string_sprintfa(sndfrm02, ";SY(%sC2)", symbol_prefix);
5757 else {
5758 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
5759 int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
5760
5761 if (NULL != quaposstr) {
5762 if (2 <= quapos && quapos < 10)
5763 g_string_sprintfa(sndfrm02, ";SY(%sC2)", symbol_prefix);
5764 }
5765 }
5766
5767 // Continuation A
5768 if (depth_value < 10.0) {
5769 // can be above water (negative)
5770 int fraction = (int)ABS((depth_value - leading_digit)*10);
5771
5772 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)ABS(leading_digit));
5773 g_string_sprintfa(sndfrm02, ";SY(%s5%1i)", symbol_prefix, fraction);
5774
5775 // above sea level (negative)
5776 if (depth_value < 0.0)
5777 g_string_sprintfa(sndfrm02, ";SY(%sA1)", symbol_prefix);
5778
5779 return sndfrm02;
5780 }
5781
5782 if (depth_value < 31.0) {
5783 double fraction = depth_value - leading_digit;
5784
5785 if (fraction != 0.0) {
5786 fraction = fraction * 10;
5787 if (leading_digit >= 10.0)
5788 g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)leading_digit/10);
5789
5790 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)leading_digit);
5791 g_string_sprintfa(sndfrm02, ";SY(%s5%1i)", symbol_prefix, (int)fraction);
5792
5793 return sndfrm02;
5794 }
5795 }
5796
5797 // Continuation B
5798 depth_value = leading_digit; // truncate to integer
5799 if (depth_value < 100.0) {
5800 double first_digit = leading_digit / 10;
5801 double secnd_digit = leading_digit - (first_digit * 10);
5802
5803 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)first_digit);
5804 g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)secnd_digit);
5805
5806 return sndfrm02;
5807 }
5808
5809 if (depth_value < 1000.0) {
5810 double first_digit = leading_digit / 100;
5811 double secnd_digit = leading_digit - (first_digit * 100);
5812 double third_digit = leading_digit - (first_digit * 100) - (secnd_digit * 10);
5813
5814 g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)first_digit);
5815 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)secnd_digit);
5816 g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)third_digit);
5817
5818 return sndfrm02;
5819 }
5820
5821 if (depth_value < 10000.0) {
5822 double first_digit = leading_digit / 1000;
5823 double secnd_digit = leading_digit - (first_digit * 1000);
5824 double third_digit = leading_digit - (first_digit * 1000) - (secnd_digit * 100);
5825 double last_digit = leading_digit - (first_digit * 1000) - (secnd_digit * 100) - (third_digit * 100) ;
5826
5827 g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)first_digit);
5828 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)secnd_digit);
5829 g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)third_digit);
5830 g_string_sprintfa(sndfrm02, ";SY(%s4%1i)", symbol_prefix, (int)last_digit);
5831
5832 return sndfrm02;
5833 }
5834
5835 // Continuation C
5836 {
5837 double first_digit = leading_digit / 10000;
5838 double secnd_digit = leading_digit - (first_digit * 10000);
5839 double third_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000);
5840 double fourth_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100) ;
5841 double last_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100) - (fourth_digit * 10) ;
5842
5843 g_string_sprintfa(sndfrm02, ";SY(%s3%1i)", symbol_prefix, (int)first_digit);
5844 g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)secnd_digit);
5845 g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)third_digit);
5846 g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)fourth_digit);
5847 g_string_sprintfa(sndfrm02, ";SY(%s4%1i)", symbol_prefix, (int)last_digit);
5848
5849 return sndfrm02;
5850 }
5851
5852 return sndfrm02;
5853 }
5854
5855 static GString *TOPMAR01 (S57_geo *geo)
5856 // Remarks: Topmark objects are to be symbolized through consideration of their
5857 // platforms e.g. a buoy. Therefore this conditional symbology procedure
5858 // searches for platforms by looking for other objects that are located at the
5859 // same position.. Based on the finding whether the platform is rigid or
5860 // floating, the respective upright or sloping symbol is selected and presented
5861 // at the objects location. Buoy symbols and topmark symbols have been
5862 // carefully designed to fit to each other when combined at the same position.
5863 // The result is a composed symbol that looks like the traditional symbols the
5864 // mariner is used to.
5865 {
5866 GString *topshpstr = S57_getAttVal(geo, "TOPSHP");
5867 GString *topmar = NULL;
5868 char *sy = NULL;
5869
5870 if (NULL == topshpstr)
5871 sy = ";SY(QUESMRK1)";
5872 else {
5873 int floating = FALSE; // not a floating platform
5874 int topshp = (NULL==topshpstr) ? 0 : atoi(topshpstr->str);
5875
5876 if (TRUE == _atPtPos(geo, FLOATLIST))
5877 floating = TRUE;
5878 else
5879 // FIXME: this test is wierd since it doesn't affect 'floating'
5880 if (TRUE == _atPtPos(geo, RIGIDLIST))
5881 floating = FALSE;
5882
5883
5884 if (floating) {
5885 // floating platform
5886 switch (topshp) {
5887 case 1 : sy = ";SY(TOPMAR02)"; break;
5888 case 2 : sy = ";SY(TOPMAR04)"; break;
5889 case 3 : sy = ";SY(TOPMAR10)"; break;
5890 case 4 : sy = ";SY(TOPMAR12)"; break;
5891
5892 case 5 : sy = ";SY(TOPMAR13)"; break;
5893 case 6 : sy = ";SY(TOPMAR14)"; break;
5894 case 7 : sy = ";SY(TOPMAR65)"; break;
5895 case 8 : sy = ";SY(TOPMAR17)"; break;
5896
5897 case 9 : sy = ";SY(TOPMAR16)"; break;
5898 case 10: sy = ";SY(TOPMAR08)"; break;
5899 case 11: sy = ";SY(TOPMAR07)"; break;
5900 case 12: sy = ";SY(TOPMAR14)"; break;
5901
5902 case 13: sy = ";SY(TOPMAR05)"; break;
5903 case 14: sy = ";SY(TOPMAR06)"; break;
5904 case 17: sy = ";SY(TMARDEF2)"; break;
5905 case 18: sy = ";SY(TOPMAR10)"; break;
5906
5907 case 19: sy = ";SY(TOPMAR13)"; break;
5908 case 20: sy = ";SY(TOPMAR14)"; break;
5909 case 21: sy = ";SY(TOPMAR13)"; break;
5910 case 22: sy = ";SY(TOPMAR14)"; break;
5911
5912 case 23: sy = ";SY(TOPMAR14)"; break;
5913 case 24: sy = ";SY(TOPMAR02)"; break;
5914 case 25: sy = ";SY(TOPMAR04)"; break;
5915 case 26: sy = ";SY(TOPMAR10)"; break;
5916
5917 case 27: sy = ";SY(TOPMAR17)"; break;
5918 case 28: sy = ";SY(TOPMAR18)"; break;
5919 case 29: sy = ";SY(TOPMAR02)"; break;
5920 case 30: sy = ";SY(TOPMAR17)"; break;
5921
5922 case 31: sy = ";SY(TOPMAR14)"; break;
5923 case 32: sy = ";SY(TOPMAR10)"; break;
5924 case 33: sy = ";SY(TMARDEF2)"; break;
5925 default: sy = ";SY(TMARDEF2)"; break;
5926 }
5927 } else {
5928 // not a floating platform
5929 switch (topshp) {
5930 case 1 : sy = ";SY(TOPMAR22)"; break;
5931 case 2 : sy = ";SY(TOPMAR24)"; break;
5932 case 3 : sy = ";SY(TOPMAR30)"; break;
5933 case 4 : sy = ";SY(TOPMAR32)"; break;
5934
5935 case 5 : sy = ";SY(TOPMAR33)"; break;
5936 case 6 : sy = ";SY(TOPMAR34)"; break;
5937 case 7 : sy = ";SY(TOPMAR85)"; break;
5938 case 8 : sy = ";SY(TOPMAR86)"; break;
5939
5940 case 9 : sy = ";SY(TOPMAR36)"; break;
5941 case 10: sy = ";SY(TOPMAR28)"; break;
5942 case 11: sy = ";SY(TOPMAR27)"; break;
5943 case 12: sy = ";SY(TOPMAR14)"; break;
5944
5945 case 13: sy = ";SY(TOPMAR25)"; break;
5946 case 14: sy = ";SY(TOPMAR26)"; break;
5947 case 15: sy = ";SY(TOPMAR88)"; break;
5948 case 16: sy = ";SY(TOPMAR87)"; break;
5949
5950 case 17: sy = ";SY(TMARDEF1)"; break;
5951 case 18: sy = ";SY(TOPMAR30)"; break;
5952 case 19: sy = ";SY(TOPMAR33)"; break;
5953 case 20: sy = ";SY(TOPMAR34)"; break;
5954
5955 case 21: sy = ";SY(TOPMAR33)"; break;
5956 case 22: sy = ";SY(TOPMAR34)"; break;
5957 case 23: sy = ";SY(TOPMAR34)"; break;
5958 case 24: sy = ";SY(TOPMAR22)"; break;
5959
5960 case 25: sy = ";SY(TOPMAR24)"; break;
5961 case 26: sy = ";SY(TOPMAR30)"; break;
5962 case 27: sy = ";SY(TOPMAR86)"; break;
5963 case 28: sy = ";SY(TOPMAR89)"; break;
5964
5965 case 29: sy = ";SY(TOPMAR22)"; break;
5966 case 30: sy = ";SY(TOPMAR86)"; break;
5967 case 31: sy = ";SY(TOPMAR14)"; break;
5968 case 32: sy = ";SY(TOPMAR30)"; break;
5969 case 33: sy = ";SY(TMARDEF1)"; break;
5970 default: sy = ";SY(TMARDEF1)"; break;
5971 }
5972 }
5973
5974 }
5975
5976 topmar = g_string_new(sy);
5977
5978 return topmar;
5979 }
5980
5981 /*
5982 static GString *_UDWHAZ03(S57_geo *geo, double depth_value)
5983 // Remarks: Obstructions or isolated underwater dangers of depths less than the safety
5984 // contour which lie within the safe waters defined by the safety contour are
5985 // to be presented by a specific isolated danger symbol as hazardous objects
5986 // and put in IMO category DISPLAYBASE (see (3), App.2, 1.3). This task
5987 // is performed by this conditional symbology procedure.
5988 {
5989 GString *udwhaz03str = NULL;
5990 int danger = FALSE;
5991 double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
5992 S57_geo *geoTmp = geo;
5993
5994 if (depth_value <= safety_contour) {
5995 // that intersect this point/line/area for OBSTRN04
5996 // that intersect this point/area for WRECKS02
5997
5998 // get area DEPARE & DRGARE that intersect this point/line/area
5999 while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
6000
6001 if (LINES_T == S57_getObjtype(geoTmp)) {
6002 GString *drval2str = S57_getAttVal(geoTmp, "DRVAL2");
6003 double drval2 = (NULL == drval2str) ? 0.0 : atof(drval2str->str);
6004
6005 if (drval2 < safety_contour) {
6006 danger = TRUE;
6007 break;
6008 }
6009
6010 } else {
6011 //
6012 GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
6013 double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
6014
6015 if (drval1 >= safety_contour) {
6016 danger = TRUE;
6017 break;
6018 }
6019 }
6020
6021 }
6022
6023
6024 //danger = TRUE; // true
6025 if (TRUE == danger) {
6026 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
6027 if (NULL != watlevstr && ('1' == *watlevstr->str || '2' == *watlevstr->str))
6028 udwhaz03str = g_string_new(";OP(--D14050");
6029 else {
6030 udwhaz03str = g_string_new(";OP(8OD14010);SY(ISODGR51)");
6031 S57_setAtt(geo, "SCAMIN", "INFINITE");
6032 }
6033 }
6034 }
6035
6036 S57_unlinkObj(geo);
6037
6038 return udwhaz03str;
6039 }
6040
6041 static GString *VESSEL01 (S57_geo *geo)
6042 // Remarks: The mariner should be prompted to select from the following options:
6043 // - ARPA target or AIS report (overall decision or vessel by vessel) (vesrce)
6044 // - *time-period determining vector-length for all vectors (vecper)
6045 // - whether to show a vector (overall or vessel by vessel) (vestat)
6046 // - *whether to symbolize vector stabilization (vecstb)
6047 // - *whether to show one-minute or six-minute vector time marks (vecmrk)
6048 // - whether to show heading line on AIS vessel reports (headng)
6049 // * Note that the same vector parameters should be used for own-ship and all vessel
6050 // vectors.
6051 {
6052 PRINTF("Mariner's object not drawn\n");
6053 return NULL;
6054 }
6055
6056 static GString *VRMEBL01 (S57_geo *geo)
6057 // Remarks: This conditional symbology procedure symbolizes the three cases of range
6058 // circle, bearing line and range/bearing line. VRM's and EBL's can be ship-centred
6059 // or freely movable, and two line-styles are available
6060 {
6061 PRINTF("Mariner's object not drawn\n");
6062 return NULL;
6063 }
6064
6065 static GString *WRECKS02 (S57_geo *geo)
6066 // Remarks: Wrecks of depths less than the safety contour which lie within the safe waters
6067 // defined by the safety contour are to be presented by a specific isolated
6068 // danger symbol and put in IMO category DISPLAYBASE (see (3), App.2,
6069 // 1.3). This task is performed by the sub-procedure "UDWHAZ03" which is
6070 // called by this symbology procedure.
6071 {
6072 GString *wrecks02str = NULL;
6073 GString *sndfrm02str = NULL;
6074 GString *udwhaz03str = NULL;
6075 GString *quapnt01str = NULL;
6076 double least_depth = UNKNOWN;
6077 double depth_value = UNKNOWN;
6078 GString *valsoustr = S57_getAttVal(geo, "VALSOU");
6079 double valsou = UNKNOWN;
6080
6081 // exit if not in drawing state
6082 if (1 == S52_state)
6083 return NULL;
6084
6085 if (NULL != valsoustr) {
6086 valsou = atof(valsoustr->str);
6087 depth_value = valsou;
6088 sndfrm02str = _SNDFRM02(geo, depth_value);
6089 } else {
6090 if (AREAS_T == S57_getObjtype(geo))
6091 least_depth = _DEPVAL01(geo, least_depth);
6092
6093 if (least_depth == UNKNOWN) {
6094 // WARNING: ambiguity removed in WRECKS03 (see update)
6095 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
6096 GString *catwrkstr = S57_getAttVal(geo, "CATWRK");
6097
6098 if (NULL == watlevstr) // default
6099 depth_value = -15.0;
6100 else
6101 switch (*watlevstr->str) { // ambiguous
6102 case '1':
6103 case '2': depth_value = -15.0 ; break;
6104 case '3': depth_value = 0.01; break;
6105 case '4': depth_value = -15.0 ; break;
6106 case '5': depth_value = 0.0 ; break;
6107 case '6': depth_value = -15.0 ; break;
6108 default :{
6109 if (NULL != catwrkstr) {
6110 switch (*catwrkstr->str) {
6111 case '1': depth_value = 20.0; break;
6112 case '2': depth_value = 0.0; break;
6113 case '4':
6114 case '5': depth_value = -15.0; break;
6115 }
6116 }
6117 }
6118 }
6119 } else
6120 depth_value = least_depth;
6121
6122
6123 }
6124
6125 udwhaz03str = _UDWHAZ03(geo, depth_value);
6126 quapnt01str = _QUAPNT01(geo);
6127
6128 if (POINT_T == S57_getObjtype(geo)) {
6129 if (NULL != udwhaz03str) {
6130 wrecks02str = g_string_new(udwhaz03str->str);
6131
6132 if (NULL != quapnt01str)
6133 g_string_append(wrecks02str, quapnt01str->str);
6134
6135 } else {
6136 // Continuation A (POINT_T)
6137 if (UNKNOWN != valsou) {
6138
6139 if (valsou <= 20.0) {
6140 wrecks02str = g_string_new(";SY(DANGER01)");
6141 if (NULL != sndfrm02str)
6142 g_string_append(wrecks02str, sndfrm02str->str);
6143
6144 } else
6145 wrecks02str = g_string_new(";SY(DANGER02)");
6146
6147 if (NULL != udwhaz03str)
6148 g_string_append(wrecks02str, udwhaz03str->str);
6149 if (NULL != quapnt01str)
6150 g_string_append(wrecks02str, quapnt01str->str);
6151
6152 } else {
6153 char *sym = NULL;
6154 GString *catwrkstr = S57_getAttVal(geo, "CATWRK");
6155 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
6156
6157 if (NULL != catwrkstr && NULL != watlevstr) {
6158 if ('1' == *catwrkstr->str && '3' == *watlevstr->str)
6159 sym =";SY(WRECKS04)";
6160 else {
6161 if ('2' == *catwrkstr->str && '3' == *watlevstr->str)
6162 sym = ";SY(WRECKS05)";
6163 else {
6164 if ('4' == *catwrkstr->str || '5' == *catwrkstr->str)
6165 sym = ";SY(WRECKS01)";
6166 else {
6167 if ('1' == *watlevstr->str ||
6168 '2' == *watlevstr->str ||
6169 '5' == *watlevstr->str ||
6170 '4' == *watlevstr->str ){
6171 sym = ";SY(WRECKS01)";
6172 } else
6173 sym = ";SY(WRECKS05)"; // default
6174
6175 }
6176 }
6177 }
6178 }
6179
6180 wrecks02str = g_string_new(sym);
6181 if (NULL != quapnt01str)
6182 g_string_append(wrecks02str, quapnt01str->str);
6183
6184 }
6185
6186 }
6187
6188
6189 } else {
6190 // Continuation B (AREAS_T)
6191 GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
6192 int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
6193 char *line = NULL;
6194
6195 if (2 <= quapos && quapos < 10)
6196 line = ";LC(LOWACC41)";
6197 else {
6198 if ( NULL != udwhaz03str)
6199 line = ";LS(DOTT,2,CHBLK)";
6200 else {
6201 if (UNKNOWN != valsou){
6202 if (valsou <= 20)
6203 line = ";LS(DOTT,2,CHBLK)";
6204 else
6205 line = ";LS(DASH,2,CHBLK)";
6206 } else {
6207 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
6208
6209 if (NULL == watlevstr)
6210 line = ";LS(DOTT,2,CSTLN)";
6211 else {
6212 switch (*watlevstr->str){
6213 case '1':
6214 case '2': line = ";LS(SOLD,2,CSTLN)"; break;
6215 case '4': line = ";LS(DASH,2,CSTLN)"; break;
6216 case '3':
6217 case '5':
6218
6219 default : line = ";LS(DOTT,2,CSTLN)"; break;
6220 }
6221 }
6222
6223 }
6224 }
6225 }
6226 wrecks02str = g_string_new(line);
6227
6228 if (UNKNOWN != valsou) {
6229 if (valsou <= 20) {
6230 if (NULL != udwhaz03str)
6231 g_string_append(wrecks02str, udwhaz03str->str);
6232
6233 if (NULL != quapnt01str)
6234 g_string_append(wrecks02str, quapnt01str->str);
6235
6236 if (NULL != sndfrm02str)
6237 g_string_append(wrecks02str, sndfrm02str->str);
6238
6239 } else {
6240 // NOTE: ??? same as above ???
6241 if (NULL != udwhaz03str)
6242 g_string_append(wrecks02str, udwhaz03str->str);
6243
6244 if (NULL != quapnt01str)
6245 g_string_append(wrecks02str, quapnt01str->str);
6246 }
6247 } else {
6248 char *ac = NULL;
6249 GString *watlevstr = S57_getAttVal(geo, "WATLEV");
6250
6251 if (NULL == watlevstr)
6252 ac = ";AC(DEPVS)";
6253 else
6254 switch (*watlevstr->str) {
6255 case '1':
6256 case '2': ac = ";AC(CHBRN)"; break;
6257 case '4': ac = ";AC(DEPIT)"; break;
6258 case '5':
6259 case '3':
6260 default : ac = ";AC(DEPVS)"; break;
6261 }
6262
6263 g_string_append(wrecks02str, ac);
6264
6265 if (NULL != udwhaz03str)
6266 g_string_append(wrecks02str, udwhaz03str->str);
6267
6268 if (NULL != quapnt01str)
6269 g_string_append(wrecks02str, quapnt01str->str);
6270 }
6271 }
6272
6273 if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
6274 if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
6275 if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
6276
6277 return wrecks02str;
6278 }
6279
6280
6281 //--------------------------------
6282 //
6283 // JUMP TABLE SECTION
6284 //
6285 //--------------------------------
6286
6287
6288 CondSymb condTable[] = {
6289 // name call Sub-Procedure
6290 {"CLRLIN01", CLRLIN01}, //
6291 {"DATCVR01", DATCVR01}, //
6292 {"DEPARE01", DEPARE01}, // _RESCSP01, _SEABED01
6293 {"DEPCNT02", DEPCNT02}, //
6294 {"LEGLIN02", LEGLIN02}, // str
6295 {"LIGHTS05", LIGHTS05}, // _LITDSN01
6296 {"OBSTRN04", OBSTRN04}, // _DEPVAL01, _QUAPNT01, _SNDFRM02, _UDWHAZ03
6297 {"OWNSHP02", OWNSHP02}, //
6298 {"PASTRK01", PASTRK01}, //
6299 {"QUAPOS01", QUAPOS01}, // _QUALIN01, _QUAPNT01
6300 {"SLCONS03", SLCONS03}, //
6301 {"RESARE02", RESARE02}, //
6302 {"RESTRN01", RESTRN01}, // _RESCSP01
6303 {"SOUNDG02", SOUNDG02}, // _SNDFRM02
6304 {"TOPMAR01", TOPMAR01}, //
6305 {"VESSEL01", VESSEL01}, //
6306 {"VRMEBL01", VRMEBL01}, //
6307 {"WRECKS02", WRECKS02}, // _DEPVAL01, _QUAPNT01, _SNDFRM02, _UDWHAZ03
6308
6309 {"########",NULL}
6310 };
6311 */
6312 #endif
6313