6262 lines
196 KiB
C++
6262 lines
196 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: OpenCPN
|
|
* Purpose: S52 Conditional Symbology Library
|
|
* Author: David Register, Sylvain Duclos
|
|
*
|
|
***************************************************************************
|
|
* Copyright (C) 2010 by David S. Register *
|
|
*
|
|
* Copyright (C) 2000-2001 Sylvain Duclos
|
|
* sylvain_duclos@yahoo.com
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
***************************************************************************
|
|
*
|
|
*/
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif // precompiled headers
|
|
|
|
#include "wx/tokenzr.h"
|
|
|
|
#include "s52plib.h"
|
|
#include "s52utils.h"
|
|
|
|
bool GetDoubleAttr(S57Obj *obj, const char *AttrName, double &val);
|
|
|
|
#define UNKNOWN 1e6 // HUGE_VAL // INFINITY/NAN
|
|
|
|
#ifndef chk_snprintf
|
|
#define chk_snprintf(buf, len, fmt, ...) \
|
|
{ \
|
|
int r = snprintf(buf, len, fmt, ##__VA_ARGS__); \
|
|
if (r == -1 || r >= len) wxLogWarning("snprint overrun"); \
|
|
}
|
|
#endif
|
|
|
|
WX_DEFINE_ARRAY_DOUBLE(double, ArrayOfSortedDoubles);
|
|
|
|
// size of attributes value list buffer
|
|
#define LISTSIZE 32 // list size
|
|
|
|
extern s52plib *ps52plib;
|
|
|
|
wxString *CSQUAPNT01(S57Obj *obj);
|
|
wxString *CSQUALIN01(S57Obj *obj);
|
|
|
|
wxArrayPtrVoid *GetChartFloatingATONArray(ObjRazRules *rzRules) {
|
|
S57Obj *obj = rzRules->obj;
|
|
if (obj->m_chart_context)
|
|
return obj->m_chart_context->pFloatingATONArray;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
wxArrayPtrVoid *GetChartRigidATONArray(ObjRazRules *rzRules) {
|
|
S57Obj *obj = rzRules->obj;
|
|
if (obj->m_chart_context->chart)
|
|
return obj->m_chart_context->pRigidATONArray;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void *CLRLIN01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : CLRLIN01 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *DATCVR01(void *param) {
|
|
// Remarks: This conditional symbology procedure describes procedures for:
|
|
// - symbolizing the limit of ENC coverage;
|
|
// - symbolizing navigational purpose boundaries ("scale boundarie"); and
|
|
// - indicating overscale display.
|
|
//
|
|
// Note that the mandatory meta object CATQUA is symbolized by the look-up
|
|
// table.
|
|
//
|
|
// Because the methods adopted by an ECDIS to meet the IMO and IHO
|
|
// requirements listed on the next page will depend on the manufacturer's
|
|
// software, and cannot be described in terms of a flow chart in the same way
|
|
// as other conditional procedures, this procedure is in the form of written
|
|
// notes.
|
|
|
|
// ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
wxString rule_str;
|
|
///////////////////////
|
|
// 1- REQUIREMENT
|
|
// (IMO/IHO specs. explenation)
|
|
|
|
///////////////////////
|
|
// 2- ENC COVERAGE
|
|
//
|
|
// 2.1- Limit of ENC coverage
|
|
// datcvr01 = g_string_new(";OP(3OD11060);LC(HODATA01)");
|
|
rule_str.Append(_T("LC(HODATA01)"));
|
|
// rule_str.Append("AC(DEPDW)");
|
|
// FIXME: get cell extend
|
|
|
|
// 2.2- No data areas
|
|
// This can be done outside of CS (ie when clearing the screen in Mesa)
|
|
// FIXME: ";OP(0---);AC(NODATA)"
|
|
// FIXME: set geo to cover earth (!)
|
|
|
|
//////////////////////
|
|
// 3- SCALE BOUNDARIES
|
|
//
|
|
// 3.1- Chart scale boundaties
|
|
// FIXME;
|
|
// g_string_append(datcvr01, ";LS(SOLD,1,CHGRD)");
|
|
// -OR- LC(SCLBDYnn) (?)
|
|
//
|
|
// ;OP(3OS21030)
|
|
|
|
// 3.2- Graphical index of navigational purpose
|
|
// FIXME: draw extent of available SENC in DB
|
|
|
|
//////////////////////
|
|
// 4- OVERSCALE
|
|
//
|
|
// FIXME: get meta date CSCL of DSPM field
|
|
// FIXME: get object M_CSCL or CSCALE
|
|
//
|
|
// 4.1- Overscale indication
|
|
// FIXME: compute, scale = [denominator of the compilation scale] /
|
|
// [denominator of the display scale]
|
|
// FIXME: draw overscale indication (ie TX("X%3.1f",scale))
|
|
//
|
|
// 4.2- Ovescale area at a chart scale boundary
|
|
// FIXME: test if next chart is over scale (ie going from large scale chart
|
|
// to a small scale chart)
|
|
// FIXME: draw AP(OVERSC01) on overscale part of display
|
|
// g_string(";OP(3OS21030)");
|
|
|
|
//
|
|
// 4.3- Larger scale data available
|
|
// FIXME: display indication of better scale available (?)
|
|
|
|
wxString datcvr01;
|
|
datcvr01.Append(rule_str);
|
|
datcvr01.Append('\037');
|
|
|
|
char *r = (char *)malloc(datcvr01.Len() + 1);
|
|
strcpy(r, datcvr01.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
bool GetIntAttr(S57Obj *obj, const char *AttrName, int &val) {
|
|
int idx = obj->GetAttributeIndex(AttrName);
|
|
|
|
if (idx >= 0) {
|
|
// using idx to get the attribute value
|
|
S57attVal *v = obj->attVal->Item(idx);
|
|
|
|
assert(v->valType == OGR_INT);
|
|
val = *(int *)(v->value);
|
|
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
#if 0
|
|
bool GetIntAttr(S57Obj *obj, const char *AttrName, int &val)
|
|
{
|
|
char *attList = (char *)calloc(obj->attList->Len()+1, 1);
|
|
strncpy(attList, obj->attList->mb_str(), obj->attList->Len());
|
|
|
|
char *patl = attList;
|
|
char *patr;
|
|
int idx = 0;
|
|
while(*patl)
|
|
{
|
|
patr = patl;
|
|
while(*patr != '\037')
|
|
patr++;
|
|
|
|
if(!strncmp(patl, AttrName, 6))
|
|
break;
|
|
|
|
patl = patr + 1;
|
|
idx++;
|
|
}
|
|
|
|
if(!*patl) // Requested Attribute not found
|
|
{
|
|
free(attList);
|
|
return false; // so don't return a value
|
|
}
|
|
|
|
// using idx to get the attribute value
|
|
wxArrayOfS57attVal *pattrVal = obj->attVal;
|
|
|
|
S57attVal *v = pattrVal->Item(idx);
|
|
val = *(int*)(v->value);
|
|
|
|
free(attList);
|
|
return true;
|
|
}
|
|
#endif
|
|
/*
|
|
bool GetFloatAttr(S57Obj *obj, char *AttrName, float &val)
|
|
{
|
|
char *attList = (char *)(obj->attList->mb_str()); //attList is
|
|
wxString
|
|
|
|
char *patl = attList;
|
|
char *patr;
|
|
int idx = 0;
|
|
while(*patl)
|
|
{
|
|
patr = patl;
|
|
while(*patr != '\037')
|
|
patr++;
|
|
|
|
if(!strncmp(patl, AttrName, 6))
|
|
break;
|
|
|
|
patl = patr + 1;
|
|
idx++;
|
|
}
|
|
|
|
if(!*patl) // Requested Attribute
|
|
not found
|
|
{
|
|
free(attList);
|
|
return false; // so don't return a
|
|
value
|
|
}
|
|
|
|
// using idx to get the attribute value
|
|
wxArrayOfS57attVal *pattrVal = obj->attVal;
|
|
|
|
S57attVal *v = pattrVal->Item(idx);
|
|
val = *(float*)(v->value);
|
|
|
|
free(attList);
|
|
return true;
|
|
}
|
|
|
|
*/
|
|
bool GetDoubleAttr(S57Obj *obj, const char *AttrName, double &val) {
|
|
int idx = obj->GetAttributeIndex(AttrName);
|
|
|
|
if (idx >= 0) {
|
|
// using idx to get the attribute value
|
|
|
|
S57attVal *v = obj->attVal->Item(idx);
|
|
assert(v->valType == OGR_REAL);
|
|
val = *(double *)(v->value);
|
|
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
bool GetStringAttr(S57Obj *obj, const char *AttrName, char *pval, int nc) {
|
|
if (!obj || !AttrName || !pval || nc <= 0) return false;
|
|
|
|
pval[0] = '\0';
|
|
|
|
int idx = obj->GetAttributeIndex(AttrName);
|
|
if (idx < 0) return false;
|
|
|
|
S57attVal *v = obj->attVal->Item(idx);
|
|
assert(v->valType == OGR_STR);
|
|
|
|
const char *val = static_cast<const char *>(v->value);
|
|
if (!val) return true;
|
|
|
|
strncpy(pval, val, nc - 1);
|
|
pval[nc - 1] = '\0';
|
|
return true;
|
|
}
|
|
|
|
wxString *GetStringAttrWXS(S57Obj *obj, const char *AttrName) {
|
|
int idx = obj->GetAttributeIndex(AttrName);
|
|
|
|
if (idx >= 0) {
|
|
// using idx to get the attribute value
|
|
S57attVal *v = obj->attVal->Item(idx);
|
|
|
|
assert(v->valType == OGR_STR);
|
|
char *val = (char *)(v->value);
|
|
|
|
return new wxString(val, wxConvUTF8);
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
static int _parseList(const char *str_in, char *buf, int buf_size)
|
|
// Put a string of comma delimited number in an array (buf).
|
|
// Return: the number of value in buf.
|
|
// Assume: - number < 256,
|
|
// - list size less than buf_size .
|
|
// Note: buf is \0 terminated for strpbrk().
|
|
{
|
|
char *str = (char *)str_in;
|
|
int i = 0;
|
|
|
|
if (NULL != str && *str != '\0') {
|
|
do {
|
|
if (i >= LISTSIZE - 1) {
|
|
printf("OVERFLOW --value in list lost!!\n");
|
|
break;
|
|
}
|
|
|
|
/*
|
|
if (255 < (unsigned char) atoi(str)) {
|
|
PRINTF("value overflow (>255)\n");
|
|
exit(0);
|
|
}
|
|
*/
|
|
|
|
buf[i++] = (unsigned char)atoi(str);
|
|
|
|
while (isdigit(*str)) str++; // next
|
|
|
|
} while (*str++ != '\0'); // skip ',' or exit
|
|
}
|
|
|
|
buf[i] = '\0';
|
|
|
|
return i;
|
|
}
|
|
|
|
static int _atPtPos(S57Obj *objNew, wxArrayPtrVoid *curntList, int bSectorCheck)
|
|
// return TRUE if there is a light at this position
|
|
// or if its an extended arc radius else FALSE
|
|
{
|
|
unsigned int i;
|
|
|
|
if (NULL == curntList) return false;
|
|
|
|
for (i = 0; i < curntList->GetCount(); i++) {
|
|
S57Obj *objOld = (S57Obj *)curntList->Item(i);
|
|
|
|
if ((objOld->x == objNew->x) && (objOld->y == objNew->y)) {
|
|
if (!bSectorCheck) return TRUE;
|
|
/*
|
|
else {
|
|
// check for extend arc radius
|
|
GString *Asectr1str = S57_getAttVal(geoOld, "SECTR1");
|
|
GString *Asectr2str = S57_getAttVal(geoOld, "SECTR2");
|
|
GString *Bsectr1str = S57_getAttVal(geoNew, "SECTR1");
|
|
GString *Bsectr2str = S57_getAttVal(geoNew, "SECTR2");
|
|
|
|
// check present
|
|
if (NULL == Asectr1str ||
|
|
NULL == Asectr1str ||
|
|
NULL == Asectr1str ||
|
|
NULL == Asectr1str)
|
|
return FALSE;
|
|
|
|
{
|
|
double Asectr1 = atof(Asectr1str->str);
|
|
double Asectr2 = atof(Asectr2str->str);
|
|
double Bsectr1 = atof(Bsectr1str->str);
|
|
double Bsectr2 = atof(Bsectr2str->str);
|
|
double Asweep = (Asectr1 > Asectr2) ?
|
|
Asectr2-Asectr1+360 : Asectr2-Asectr1;
|
|
double Bsweep = (Bsectr1 > Bsectr2) ?
|
|
Bsectr2-Bsectr1+360 : Bsectr2-Bsectr1;
|
|
|
|
// check sector overlap
|
|
if (Asectr2<=Bsectr1 || Asectr1>=Bsectr2) {
|
|
if (Asweep == Bsweep) {
|
|
g_string_truncate(Bsectr2str, 0);
|
|
g_string_sprintf(Bsectr2str, "%f",Bsectr2-1);
|
|
S57_setAtt(geoNew, "SECTR2", Bsectr2str->str);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// check if other sector larger
|
|
if (Asweep >= Bsweep)
|
|
return TRUE;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
wxString _selSYcol(char *buf, bool bsectr, double valnmr) {
|
|
wxString sym;
|
|
|
|
if (!bsectr) {
|
|
sym = _T(";SY(LITDEF11"); // default
|
|
|
|
// max 1 color
|
|
if ('\0' == buf[1]) {
|
|
if (strpbrk(buf, "\003"))
|
|
sym = _T(";SY(LIGHTS11");
|
|
else if (strpbrk(buf, "\004"))
|
|
sym = _T(";SY(LIGHTS12");
|
|
else if (strpbrk(buf, "\001\006\011"))
|
|
sym = _T(";SY(LIGHTS13");
|
|
} else {
|
|
// max 2 color
|
|
if ('\0' == buf[2]) {
|
|
if (strpbrk(buf, "\001") && strpbrk(buf, "\003"))
|
|
sym = _T(";SY(LIGHTS11");
|
|
else if (strpbrk(buf, "\001") && strpbrk(buf, "\004"))
|
|
sym = _T(";SY(LIGHTS12");
|
|
}
|
|
}
|
|
}
|
|
|
|
else // all-round fixed light symbolized as a circle, radius depends on color
|
|
// This treatment is seen on SeeMyDenc by SevenCs
|
|
// This may not be S-52 compliant....
|
|
{
|
|
// Another non-standard extension....
|
|
// All round light circle diameter is scaled if the light has a
|
|
// reasonable VALNMR attribute
|
|
int radius = 3;
|
|
if (valnmr > 0) {
|
|
if (valnmr < 7.0)
|
|
radius = 3;
|
|
else if (valnmr < 15.0)
|
|
radius = 10;
|
|
else if (valnmr < 30.0)
|
|
radius = 15;
|
|
else
|
|
radius = 20;
|
|
}
|
|
|
|
// max 1 color
|
|
if ('\0' == buf[1]) {
|
|
if (strpbrk(buf, "\003"))
|
|
sym.Printf(_T(",LITRD, 2,0,360,%d,0"), radius + 1);
|
|
else if (strpbrk(buf, "\004"))
|
|
sym.Printf(_T(",LITGN, 2,0,360,%d,0"), radius);
|
|
else if (strpbrk(buf, "\001\006\011"))
|
|
sym.Printf(_T(",LITYW, 2,0,360,%d,0"), radius + 2);
|
|
else if (strpbrk(buf, "\014"))
|
|
sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 3);
|
|
else
|
|
sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5); // default
|
|
|
|
} else if ('\0' == buf[2]) // or 2 color
|
|
{
|
|
if (strpbrk(buf, "\001") && strpbrk(buf, "\003"))
|
|
sym.Printf(_T(",LITRD, 2,0,360,%d,0"), radius + 1);
|
|
else if (strpbrk(buf, "\001") && strpbrk(buf, "\004"))
|
|
sym.Printf(_T(",LITGN, 2,0,360,%d,0"), radius);
|
|
else
|
|
sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5); // default
|
|
|
|
} else
|
|
sym.Printf(_T(",CHMGD, 2,0,360,%d,0"), radius + 5);
|
|
|
|
if (sym.Len()) sym.Prepend(_T(";CA(OUTLW, 4"));
|
|
}
|
|
|
|
return sym;
|
|
}
|
|
|
|
static double _DEPVAL01(S57Obj *obj, double least_depth)
|
|
// Remarks: S-57 Appendix B1 Annex A requires in Section 6 that areas of rocks
|
|
// be encoded as area obstruction, and that area OBSTRNs and area WRECKS be
|
|
// covered by either group 1 object DEPARE or group 1 object UNSARE. If the
|
|
// value of the attribute VALSOU for an area OBSTRN or WRECKS is missing, the
|
|
// DRVAL1 of an underlying DEPARE is the preferred default for establishing a
|
|
// depth value. This procedure either finds the shallowest DRVAL1 of the one or
|
|
// more underlying DEPAREs, or returns an "unknown"" depth value to the main
|
|
// procedure for the next default procedure.
|
|
|
|
// NOTE: UNSARE test is useless since least_depth is already UNKNOWN
|
|
{
|
|
least_depth = UNKNOWN;
|
|
|
|
/*
|
|
S57_geo *geoTmp = geo;
|
|
|
|
// NOTE: the geo list is unchange (_UDWHAZ03 will unlink geo)
|
|
while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
|
|
GString *objlstr = S57_getAttVal(geoTmp, "OBJL");
|
|
int objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
|
|
|
|
// get area DEPARE that intersect this area
|
|
if (DEPARE==objl && LINES_T==S57_getObjtype(geo)) {
|
|
GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
|
|
double drval1 = (NULL == drval1str) ? 9.0 :
|
|
atof(drval1str->str);
|
|
|
|
if (NULL != drval1str) {
|
|
if (UNKNOWN==least_depth || least_depth<drval1)
|
|
least_depth = drval1;
|
|
}
|
|
|
|
}
|
|
}
|
|
*/
|
|
return least_depth;
|
|
}
|
|
|
|
static wxString *_UDWHAZ03(S57Obj *obj, double depth_value,
|
|
ObjRazRules *rzRules, bool *promote_return)
|
|
// Remarks: Obstructions or isolated underwater dangers of depths less than the
|
|
// safety contour which lie within the safe waters defined by the safety contour
|
|
// are to be presented by a specific isolated danger symbol as hazardous objects
|
|
// and put in IMO category DISPLAYBASE (see (3), App.2, 1.3). This task
|
|
// is performed by this conditional symbology procedure.
|
|
{
|
|
wxString udwhaz03str;
|
|
int danger = FALSE;
|
|
int expsou = 0;
|
|
double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
|
|
bool b_promote = false;
|
|
|
|
if (depth_value == UNKNOWN) {
|
|
GetIntAttr(obj, "EXPSOU", expsou);
|
|
if (expsou != 1) danger = TRUE;
|
|
}
|
|
if (danger == FALSE && (expsou == 1 || depth_value <= safety_contour)) {
|
|
// that intersect this point/line/area for OBSTRN04
|
|
// that intersect this point/area for WRECKS02
|
|
|
|
// get area DEPARE & DRGARE that intersect this point/line/area
|
|
|
|
std::list<S57Obj*> *pobj_list = NULL;
|
|
if (obj->m_chart_context->chart){
|
|
chart_context *pcc = obj->m_chart_context;
|
|
s57chart *chart = (s57chart*)obj->m_chart_context->chart;
|
|
pobj_list = (chart->*pcc->pt2GetAssociatedObjects)(obj);
|
|
}
|
|
else{
|
|
danger = false;
|
|
}
|
|
|
|
if (pobj_list) {
|
|
for (S57Obj* ptest_obj: *pobj_list) {
|
|
if (GEO_LINE == ptest_obj->Primitive_type) {
|
|
double drval2 = 0.0;
|
|
GetDoubleAttr(ptest_obj, "DRVAL2", drval2);
|
|
|
|
if (drval2 < safety_contour) {
|
|
danger = TRUE;
|
|
break;
|
|
}
|
|
} else {
|
|
double drval1 = 0.0;
|
|
GetDoubleAttr(ptest_obj, "DRVAL1", drval1);
|
|
|
|
#if 0
|
|
double drval2 = 0.0;
|
|
GetDoubleAttr(ptest_obj, "DRVAL2", drval2);
|
|
|
|
if(expsou == 1 || depth_value < drval2 )
|
|
b_promote = true;
|
|
#endif
|
|
|
|
if (drval1 >= safety_contour && expsou != 1) {
|
|
danger = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pobj_list;
|
|
}
|
|
}
|
|
|
|
if (TRUE == danger) {
|
|
int watlev = 0; // Enum 0 invalid
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
|
|
if ((1 == watlev) || (2 == watlev)) {
|
|
// dry
|
|
} else {
|
|
udwhaz03str = _T(";SY(ISODGR51)"); //_T(";OP(8OD14010);SY(ISODGR51)");
|
|
// S57_setAtt(geo, "SCAMIN", "INFINITE");
|
|
}
|
|
|
|
// Move this object to DisplayBase category
|
|
rzRules->obj->m_DisplayCat = DISPLAYBASE;
|
|
|
|
}
|
|
|
|
if (promote_return) *promote_return = b_promote;
|
|
|
|
wxString *ret_str = new wxString(udwhaz03str);
|
|
return ret_str;
|
|
}
|
|
|
|
// Remarks: An object of the class "depth area" is coloured and covered with
|
|
// fill patterns according to the mariners selections of shallow contour, safety
|
|
// contour and deep contour. This requires a decision making process based on
|
|
// DRVAL1 and DRVAL2. Objects of the class "dredged area" are handled by this
|
|
// routine as well to ensure a consistent symbolization of areas that represent
|
|
// the surface of the seabed.
|
|
|
|
static void *DEPARE01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
double drval1, drval2;
|
|
bool drval1_found;
|
|
|
|
// Determine the color based on mariner selections
|
|
|
|
drval1 = -1.0; // default values
|
|
drval1_found = GetDoubleAttr(obj, "DRVAL1", drval1);
|
|
// drval2 = drval1 + 0.01;
|
|
GetDoubleAttr(obj, "DRVAL2", drval2);
|
|
//make sure drval2 is higher then drval1, always even in bad charts
|
|
if (drval2 <= drval1) drval2 = drval1 + 0.01;
|
|
|
|
// Create a string of the proper color reference
|
|
|
|
wxString rule_str = _T("AC(DEPIT)");
|
|
|
|
if (drval1 >= 0.0 && drval2 > 0.0) rule_str = _T("AC(DEPVS)");
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_TWO_SHADES)) {
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
rule_str = _T("AC(DEPDW)");
|
|
}
|
|
} else {
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR))
|
|
rule_str = _T("AC(DEPMS)");
|
|
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
rule_str = _T("AC(DEPMD)");
|
|
}
|
|
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR)) {
|
|
rule_str = _T("AC(DEPDW)");
|
|
}
|
|
}
|
|
|
|
// If object is DRGARE....
|
|
|
|
if (!strncmp(rzRules->LUP->OBCL, "DRGARE", 6)) {
|
|
if (!drval1_found) // If DRVAL1 was not defined...
|
|
{
|
|
rule_str = _T("AC(DEPMD)");
|
|
}
|
|
rule_str.Append(_T(";AP(DRGARE01)"));
|
|
rule_str.Append(_T(";LS(DASH,1,CHGRF)"));
|
|
|
|
// Todo Restrictions
|
|
/*
|
|
char pval[30];
|
|
if(true == GetStringAttr(obj, "RESTRN", pval, 20))
|
|
{
|
|
GString *rescsp01 = _RESCSP01(geo);
|
|
if (NULL != rescsp01)
|
|
{
|
|
g_string_append(depare01, rescsp01->str);
|
|
g_string_free(rescsp01, TRUE);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
rule_str.Append('\037');
|
|
|
|
return strdup(rule_str.mb_str());
|
|
}
|
|
/*
|
|
static void *DEPCNT02A(void *param)
|
|
{
|
|
// ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
// Add another rule onto the ruleList
|
|
|
|
Rules *r = NULL;
|
|
|
|
r = (Rules*)calloc(1, sizeof(Rules));
|
|
r->ruleType = RUL_SIM_LN;
|
|
r->INSTstr = "SOLD,1,DEPCN"; // points into
|
|
the plib data space
|
|
|
|
return NULL;
|
|
|
|
}
|
|
*/
|
|
|
|
static void *DEPCNT02(void *param)
|
|
// Remarks: An object of the class "depth contour" or "line depth area" is
|
|
// highlighted and must be shown under all circumstances if it matches the
|
|
// safety contour depth value entered by the mariner (see IMO PS 3.6). But,
|
|
// while the mariner is free to enter any safety contour depth value that he
|
|
// thinks is suitable for the safety of his ship, the SENC only contains a
|
|
// limited choice of depth contours. This symbology procedure determines whether
|
|
// a contour matches the selected safety contour. If the selected safety contour
|
|
// does not exist in the data, the procedure will default to the next deeper
|
|
// contour. The contour selected is highlighted as the safety contour and put in
|
|
// DISPLAYBASE. The procedure also identifies any line segment of the spatial
|
|
// component of the object that has a "QUAPOS" value indicating unreliable
|
|
// positioning, and symbolizes it with a double dashed line.
|
|
//
|
|
// Note: Depth contours are not normally labeled. The ECDIS may provide labels,
|
|
// on demand only as with other text, or provide the depth value on cursor
|
|
// picking
|
|
{
|
|
// GString *depcnt02 = NULL;
|
|
// int safe = FALSE; // initialy not a safety contour
|
|
// GString *objlstr = NULL;
|
|
// int objl = 0;
|
|
// GString *quaposstr = NULL;
|
|
// int quapos = 0;
|
|
double drval1, drval2;
|
|
bool safe = FALSE;
|
|
wxString rule_str;
|
|
double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
|
|
|
|
// objlstr = S57_getAttVal(geo, "OBJL");
|
|
// objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
|
|
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
// Debug
|
|
//if(obj->Index == 5014)
|
|
//int tty = 5;
|
|
|
|
if ((!strncmp(obj->FeatureName, "DEPARE", 6)) &&
|
|
GEO_LINE == obj->Primitive_type) {
|
|
drval1 = 0.0; // default values
|
|
GetDoubleAttr(obj, "DRVAL1", drval1);
|
|
drval2 = drval1;
|
|
GetDoubleAttr(obj, "DRVAL2", drval2);
|
|
|
|
if (drval1 <= safety_contour) {
|
|
if (drval2 >= safety_contour) safe = TRUE;
|
|
}
|
|
|
|
else {
|
|
double next_safe_contour = 1e6;
|
|
next_safe_contour = obj->m_chart_context->safety_contour;
|
|
if (fabs(drval1 - next_safe_contour) < 1e-4) safe = true;
|
|
}
|
|
|
|
} else {
|
|
// continuation A (DEPCNT)
|
|
double valdco = 0;
|
|
GetDoubleAttr(obj, "VALDCO", valdco);
|
|
|
|
if (valdco == safety_contour)
|
|
safe = TRUE; // this is useless !?!?
|
|
|
|
else {
|
|
double next_safe_contour = 1e6;
|
|
next_safe_contour = obj->m_chart_context->safety_contour;
|
|
if (fabs(valdco - next_safe_contour) < 1e-4) safe = true;
|
|
}
|
|
|
|
/*
|
|
if (valdco > safety_contour)
|
|
{
|
|
safe = FALSE;
|
|
if (1 == S52_state)
|
|
return NULL;
|
|
else {
|
|
S57_geo *geoTmp = geo;
|
|
|
|
// get area DEPARE & DRGARE that intersect this line
|
|
while (NULL != (geoTmp =
|
|
S57_nextObj(geoTmp))){ GString *drval1str = S57_getAttVal(geoTmp,
|
|
"DRVAL1"); double drval1 = (NULL == drval1str) ? 0.0 :
|
|
atof(drval1str->str);
|
|
|
|
if (NULL == drval1str) {
|
|
safe = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (drval1 <
|
|
S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) { safe = TRUE; break;
|
|
}
|
|
}
|
|
// debug trace
|
|
//if (safe) PRINTF("** DEPCN: SAFE FOUND**\n");
|
|
}
|
|
|
|
*/
|
|
}
|
|
|
|
// Continuation B
|
|
int quapos = 0;
|
|
GetIntAttr(obj, "QUAPOS",
|
|
quapos); // QUAPOS is an E (Enumerated) type attribute
|
|
|
|
if (0 != quapos) {
|
|
if (2 <= quapos && quapos < 10) {
|
|
if (safe) {
|
|
wxString safeCntr = _T("LS(DASH,2,DEPSC)");
|
|
S57Obj tempObj;
|
|
LUPrec *safelup = ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, "SAFECD",
|
|
&tempObj, false);
|
|
if (safelup) safeCntr = safelup->INST;
|
|
rule_str = _T(";") + safeCntr;
|
|
} else
|
|
rule_str = _T(";LS(DASH,1,DEPCN)");
|
|
}
|
|
} else {
|
|
if (safe) {
|
|
wxString safeCntr = _T("LS(SOLD,2,DEPSC)");
|
|
S57Obj tempObj;
|
|
LUPrec *safelup =
|
|
ps52plib->S52_LUPLookup(PLAIN_BOUNDARIES, "SAFECN", &tempObj, false);
|
|
if (safelup) safeCntr = safelup->INST;
|
|
rule_str = _T(";") + safeCntr;
|
|
} else
|
|
rule_str = _T(";LS(SOLD,1,DEPCN)");
|
|
}
|
|
|
|
if (safe) {
|
|
// S57_setAtt(geo, "SCAMIN", "INFINITE");
|
|
// rule_str.Prepend(_T(";OP(8OD13010)")); //depcnt02 =
|
|
// g_string_prepend(depcnt02, ";OP(8OD13010)");
|
|
// Move this object to DisplayBase category
|
|
rzRules->obj->m_DisplayCat = DISPLAYBASE;
|
|
rzRules->obj->Scamin = 1e8+1; // effectively no SCAMIN
|
|
// rzRules->LUP->DPRI = PRIO_HAZARDS;
|
|
|
|
} else {
|
|
// rule_str.Prepend(_T(";OP(---33020)")); //depcnt02 =
|
|
// g_string_prepend(depcnt02, ";OP(---33020)");
|
|
}
|
|
// facultative in S-52
|
|
// if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
// GString *sndfrm02 = _SNDFRM02(geo, depth_value);
|
|
// depcnt02 = g_string_append(depcnt02, sndfrm02->str);
|
|
// g_string_free(sndfrm02, TRUE);
|
|
//}
|
|
|
|
// debug
|
|
// PRINTF("depth= %f\n", depth_value);
|
|
|
|
// S57_unlinkObj(geo);
|
|
|
|
rule_str.Append('\037');
|
|
|
|
return strdup(rule_str.mb_str());
|
|
|
|
// return depcnt02;
|
|
}
|
|
|
|
static void *DEPVAL01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : DEPVAL01 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *LEGLIN02(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : LEGLIN02 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
static void *LIGHTS04A(void *param)
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString rule_str;
|
|
|
|
char col_str[2];
|
|
GetStringAttr(obj, "COLOUR", col_str, 1);
|
|
|
|
double height_val = 0;
|
|
GetDoubleAttr(obj, "HEIGHT", height_val);
|
|
|
|
// if(obj->attList->Contains(wxString("HEIGHT")))
|
|
// int uupr = 5;
|
|
|
|
// Different symbology depending upon Paper or Simplified Mariner Selection
|
|
|
|
|
|
if(ps52plib->m_nSymbolStyle == PAPER_CHART)
|
|
{
|
|
if(col_str[0] == '3')
|
|
{ // red
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS93)"); // all round
|
|
else
|
|
rule_str = _T("SY(LIGHTS01)"); // flare
|
|
}
|
|
|
|
else if(col_str[0] == '4') // green
|
|
{
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS92)");
|
|
else
|
|
rule_str = _T("SY(LIGHTS02)");
|
|
}
|
|
|
|
else // Generic,
|
|
shows as yellow
|
|
{
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS91)");
|
|
else
|
|
rule_str = _T("SY(LIGHTS03)");
|
|
}
|
|
}
|
|
|
|
else // must be
|
|
Simplified
|
|
{
|
|
if(col_str[0] == '3')
|
|
{ // red
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS93)"); // all round
|
|
else
|
|
rule_str = _T("SY(LIGHTS01)"); // flare
|
|
}
|
|
|
|
else if(col_str[0] == '4') // green
|
|
{
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS92)");
|
|
else
|
|
rule_str = _T("SY(LIGHTS02)");
|
|
}
|
|
|
|
else // Generic,
|
|
shows as yellow
|
|
{
|
|
if(height_val)
|
|
rule_str = _T("SY(LIGHTS91)");
|
|
else
|
|
rule_str = _T("SY(LIGHTS03)");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
rule_str.Append('\037');
|
|
|
|
char *r = (char *)malloc(rule_str.Len() + 1);
|
|
strcpy(r, rule_str.mb_str());
|
|
return r;
|
|
}
|
|
|
|
// A simple placeholder for Conditional Symbology method LIGHTS05
|
|
static void *LIGHTS05A(void *param)
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString rule_str;
|
|
|
|
char col_str[2];
|
|
GetStringAttr(obj, "COLOUR", col_str, 1);
|
|
|
|
double height_val = 0;
|
|
GetDoubleAttr(obj, "HEIGHT", height_val);
|
|
|
|
if(col_str[0] == '3')
|
|
{ // red
|
|
rule_str = _T("SY(LIGHTS11)"); // flare
|
|
}
|
|
|
|
else if(col_str[0] == '4') // green
|
|
rule_str = _T("SY(LIGHTS12)");
|
|
|
|
else // Generic, shows as
|
|
yellow rule_str = _T("SY(LIGHTS13)");
|
|
|
|
|
|
|
|
rule_str.Append('\037');
|
|
|
|
char *r = (char *)malloc(rule_str.Len() + 1);
|
|
strcpy(r, rule_str.mb_str());
|
|
return r;
|
|
}
|
|
*/
|
|
|
|
static wxString _LITDSN01(S57Obj *obj);
|
|
static void *LIGHTS06(void *param);
|
|
|
|
static void *LIGHTS05(void *param)
|
|
// Remarks: A light is one of the most complex S-57 objects. Its presentation
|
|
// depends on whether it is a light on a floating or fixed platform, its range,
|
|
// it's colour and so on. This conditional symbology procedure derives the
|
|
// correct presentation from these parameters and also generates an area that
|
|
// shows the coverage of the light.
|
|
//
|
|
// Notes on light sectors:
|
|
// 1.) The radial leg-lines defining the light sectors are normally drawn to
|
|
// only 25mm from the light to avoid clutter (see Part C). However, the mariner
|
|
// should be able to select "full light-sector lines" and have the leg-lines
|
|
// extended to the nominal range of the light (VALMAR).
|
|
//
|
|
// 2.) Part C of this procedure symbolizes the sectors at the light itself. In
|
|
// addition, it should be possible, upon request, for the mariner to be capable
|
|
// of identifying the colour and sector limit lines of the sectors affecting the
|
|
// ship even if the light itself is off the display. [ed. last sentence in bold]
|
|
|
|
{
|
|
// As transition, we use the PLIB 4.0 LIGHTS06 Procedure
|
|
return LIGHTS06(param);
|
|
|
|
#define UNKNOWN_DOUBLE -9;
|
|
wxString lights05;
|
|
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
double valnmr = UNKNOWN_DOUBLE;
|
|
GetDoubleAttr(obj, "VALNMR", valnmr);
|
|
|
|
char catlitstr[20] = {'\0'};
|
|
GetStringAttr(obj, "CATLIT", catlitstr, 19);
|
|
|
|
char litvisstr[20] = {'\0'};
|
|
;
|
|
GetStringAttr(obj, "LITVIS", litvisstr, 19);
|
|
|
|
char catlit[LISTSIZE] = {'\0'};
|
|
char litvis[LISTSIZE] = {'\0'};
|
|
char col_str[20] = {'\0'};
|
|
|
|
bool flare_at_45 = false;
|
|
double sectr1 = UNKNOWN_DOUBLE;
|
|
double sectr2 = UNKNOWN_DOUBLE;
|
|
double sweep = 0.;
|
|
char colist[LISTSIZE] = {'\0'}; // colour list
|
|
bool b_isflare = false;
|
|
|
|
wxString orientstr;
|
|
|
|
if (strlen(catlitstr)) {
|
|
_parseList(catlitstr, catlit, sizeof(colist));
|
|
|
|
// FIXME: OR vs AND/OR
|
|
if (strpbrk(catlit, "\010\013")) {
|
|
lights05.Append(_T(";SY(LIGHTS82)"));
|
|
goto l05_end;
|
|
}
|
|
|
|
if (strpbrk(catlit, "\011")) {
|
|
lights05.Append(_T(";SY(LIGHTS81)"));
|
|
goto l05_end;
|
|
}
|
|
|
|
/*
|
|
if (strpbrk(catlit, "\001\020")) {
|
|
orientstr = S57_getAttVal(geo, "ORIENT");
|
|
if (NULL != orientstr) {
|
|
// FIXME: create a geo object (!?) LINE of lenght VALNMR
|
|
// using ORIENT (from seaward) & POINT_T position
|
|
g_string_append(lights05, ";LS(DASH,1,CHBLK)");
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
// Continuation A
|
|
|
|
GetStringAttr(obj, "COLOUR", col_str, 19);
|
|
|
|
if (strlen(col_str))
|
|
_parseList(col_str, colist, sizeof(colist));
|
|
else {
|
|
colist[0] = '\014'; // magenta (12)
|
|
colist[1] = '\000';
|
|
}
|
|
|
|
GetDoubleAttr(obj, "SECTR1", sectr1);
|
|
GetDoubleAttr(obj, "SECTR2", sectr2);
|
|
|
|
if ((-9 == sectr1) || (-9 == sectr2)) {
|
|
// This is not a sector light
|
|
|
|
// What follows is one interpretation of the modern (3_3 +)
|
|
// Presentation Library CS flow chart, which I(dsr) have never seen
|
|
// verbatim. We will use flare light symbols for floating aids, and all
|
|
// round sector lights for fixed aids.
|
|
|
|
wxString ssym;
|
|
|
|
//FIXME plib
|
|
// if (_atPtPos(obj, GetChartFloatingATONArray(rzRules),
|
|
// false)) // Is this LIGHTS feature colocated with ...ANY...
|
|
// // floating aid?
|
|
// {
|
|
// flare_at_45 = false;
|
|
//
|
|
// // TODO create LightArray in s57chart.
|
|
// // Then, if another LIGHT object is colocated here, set flare_at_45
|
|
// /* if(_atPtPos(obj, rzRules->chart->pLIGHTSArray, false)) // Is
|
|
// this LIGHTS feature colocated with another LIGHTS?
|
|
//
|
|
//
|
|
// // If the light is white, yellow, or orange, make it a
|
|
// flare at 45 degrees if(strpbrk(colist, "\001\005\011")) flare_at_45 =
|
|
// true;
|
|
// */
|
|
// ssym = _selSYcol(colist, 0, valnmr); // flare
|
|
// b_isflare = true;
|
|
// } else
|
|
{
|
|
ssym = _selSYcol(colist, 1, valnmr); // all round light
|
|
b_isflare = false;
|
|
}
|
|
|
|
// Is the light a directional or moire?
|
|
if (strpbrk(catlit, "\001\016")) {
|
|
if (orientstr.Len()) {
|
|
lights05.Append(ssym);
|
|
lights05.Append(orientstr);
|
|
lights05.Append(
|
|
_T(";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" ));
|
|
} else
|
|
lights05.Append(_T(";SY(QUESMRK1)"));
|
|
} else {
|
|
lights05.Append(ssym);
|
|
if (b_isflare) {
|
|
if (flare_at_45)
|
|
lights05.Append(_T(",45)"));
|
|
else
|
|
lights05.Append(_T(",135)"));
|
|
}
|
|
}
|
|
|
|
goto l05_end;
|
|
}
|
|
|
|
// Continuation B --sector light
|
|
if (-9 == sectr1) {
|
|
sectr1 = 0.0;
|
|
sectr2 = 0.0;
|
|
} else
|
|
sweep = (sectr1 > sectr2) ? sectr2 - sectr1 + 360 : sectr2 - sectr1;
|
|
|
|
if (sweep < 1.0 || sweep == 360.0) {
|
|
// handle all round light
|
|
wxString ssym = _selSYcol(colist, 1, valnmr); // all round light
|
|
lights05.Append(ssym);
|
|
|
|
/*
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
GString *litdsn01 = _LITDSN01(geo);
|
|
if (NULL != litdsn01) {
|
|
g_string_append(lights05, ";TX('");
|
|
g_string_append(lights05, litdsn01->str);
|
|
g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
|
|
g_string_free(litdsn01, TRUE);
|
|
}
|
|
|
|
}
|
|
*/
|
|
goto l05_end;
|
|
}
|
|
|
|
/*
|
|
// scan for other lights with sector overlap at this position
|
|
// compute light sector radius according to other sector
|
|
if (1 == S52_state)
|
|
{
|
|
_setPtPos(geo, SECTRLIST);
|
|
g_string_free(lights05, TRUE);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
extend_arc_radius = _atPtPos(geo, SECTRLIST);
|
|
|
|
// passe value via attribs to _renderAC
|
|
if (extend_arc_radius)
|
|
// FIXME: draw radius 25 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "Y");
|
|
else
|
|
// FIXME: draw radius 20 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "N");
|
|
}
|
|
*/
|
|
// setup sector
|
|
{
|
|
// Build the (opencpn private) command string like this:
|
|
// e.g. ";CA(OUTLW, 4,LITRD, 2, sectr1, sectr2, radius)"
|
|
|
|
double arc_radius = 20.; // mm
|
|
double sector_radius = 25.;
|
|
|
|
// Another non-standard extension....
|
|
// Sector light arc radius is scaled if the light has a reasonable
|
|
// VALNMR attribute
|
|
if (valnmr > 0) {
|
|
if (valnmr < 15.0)
|
|
arc_radius = 10.;
|
|
else if (valnmr < 30.0)
|
|
arc_radius = 15.;
|
|
else
|
|
arc_radius = 20.;
|
|
}
|
|
|
|
char sym[80];
|
|
strcpy(sym, ";CA(OUTLW, 4");
|
|
|
|
// max 1 color
|
|
if ('\0' == colist[1]) {
|
|
if (strpbrk(colist, "\003"))
|
|
strcat(sym, ",LITRD, 2");
|
|
else if (strpbrk(colist, "\004"))
|
|
strcat(sym, ",LITGN, 2");
|
|
else if (strpbrk(colist, "\001\006\013"))
|
|
strcat(sym, ",LITYW, 2");
|
|
else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
|
|
} else if ('\0' == colist[2]) {
|
|
if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
|
|
strcat(sym, ",LITRD, 2");
|
|
else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
|
|
strcat(sym, ",LITGN, 2");
|
|
else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
} else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
|
|
if (strlen(litvisstr)) // Obscured/faint sector?
|
|
{
|
|
_parseList(litvisstr, litvis, sizeof(litvis));
|
|
|
|
if (strpbrk(litvis, "\003\007\010")) strcpy(sym, ";CA(CHBLK, 4,CHBRN, 1");
|
|
}
|
|
|
|
if (sectr2 <= sectr1) sectr2 += 360;
|
|
|
|
// Sectors are defined from seaward
|
|
if (sectr1 > 180)
|
|
sectr1 -= 180;
|
|
else
|
|
sectr1 += 180;
|
|
|
|
if (sectr2 > 180)
|
|
sectr2 -= 180;
|
|
else
|
|
sectr2 += 180;
|
|
|
|
char arc_data[80];
|
|
sprintf(arc_data, ",%5.1f, %5.1f, %5.1f, %5.1f", sectr1, sectr2, arc_radius,
|
|
sector_radius);
|
|
|
|
strcat(sym, arc_data);
|
|
|
|
wxString ssym(sym, wxConvUTF8);
|
|
lights05 = ssym;
|
|
|
|
goto l05_end;
|
|
}
|
|
|
|
l05_end:
|
|
|
|
// if( ps52plib->m_bShowLdisText )
|
|
{
|
|
// Only show Light in certain position once. Otherwise there will be
|
|
// clutter.
|
|
static double lastLat, lastLon;
|
|
static wxString lastDescription;
|
|
bool isFirstSector = true;
|
|
|
|
if (lastLat == obj->m_lat && lastLon == obj->m_lon) isFirstSector = false;
|
|
lastLat = obj->m_lat;
|
|
lastLon = obj->m_lon;
|
|
|
|
wxString litdsn01 = _LITDSN01(obj);
|
|
|
|
if (litdsn01.Len() && isFirstSector) {
|
|
lastDescription = litdsn01;
|
|
lights05.Append(_T(";TX('"));
|
|
lights05.Append(litdsn01);
|
|
|
|
if (flare_at_45)
|
|
lights05.Append(_T("',3,3,3,'15110',2,-1,CHBLK,23)" ));
|
|
else
|
|
lights05.Append(_T("',3,2,3,'15110',2,0,CHBLK,23)" ));
|
|
}
|
|
|
|
if (!isFirstSector && lastDescription != litdsn01) {
|
|
lastDescription = litdsn01;
|
|
lights05.Append(_T(";TX('"));
|
|
lights05.Append(litdsn01);
|
|
lights05.Append(_T("',3,2,3,'15110',2,1,CHBLK,23)" ));
|
|
}
|
|
}
|
|
|
|
lights05.Append('\037');
|
|
|
|
char *r = (char *)malloc(lights05.Len() + 1);
|
|
strcpy(r, lights05.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *LIGHTS06(void *param)
|
|
// Remarks: A light is one of the most complex S-57 objects. Its presentation
|
|
// depends on whether it is a light on a floating or fixed platform, its range,
|
|
// it's colour and so on. This conditional symbology procedure derives the
|
|
// correct presentation from these parameters and also generates an area that
|
|
// shows the coverage of the light.
|
|
//
|
|
// Notes on light sectors:
|
|
// 1.) The radial leg-lines defining the light sectors are normally drawn to
|
|
// only 25mm from the light to avoid clutter (see Part C). However, the mariner
|
|
// should be able to select "full light-sector lines" and have the leg-lines
|
|
// extended to the nominal range of the light (VALMAR).
|
|
//
|
|
// 2.) Part C of this procedure symbolizes the sectors at the light itself. In
|
|
// addition, it should be possible, upon request, for the mariner to be capable
|
|
// of identifying the colour and sector limit lines of the sectors affecting the
|
|
// ship even if the light itself is off the display. [ed. last sentence in bold]
|
|
|
|
{
|
|
#define UNKNOWN_DOUBLE -9;
|
|
wxString lights06;
|
|
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
double valnmr = 9.0;
|
|
GetDoubleAttr(obj, "VALNMR", valnmr);
|
|
|
|
char catlitstr[20] = {'\0'};
|
|
GetStringAttr(obj, "CATLIT", catlitstr, 19);
|
|
|
|
char litvisstr[20] = {'\0'};
|
|
;
|
|
GetStringAttr(obj, "LITVIS", litvisstr, 19);
|
|
|
|
char catlit[LISTSIZE] = {'\0'};
|
|
char litvis[LISTSIZE] = {'\0'};
|
|
char col_str[20] = {'\0'};
|
|
|
|
bool flare_at_45 = false;
|
|
double sectr1 = UNKNOWN_DOUBLE;
|
|
double sectr2 = UNKNOWN_DOUBLE;
|
|
double sweep = 0.;
|
|
char colist[LISTSIZE] = {'\0'}; // colour list
|
|
bool b_isflare = false;
|
|
|
|
wxString orientstr;
|
|
|
|
if (strlen(catlitstr)) {
|
|
_parseList(catlitstr, catlit, sizeof(colist));
|
|
|
|
if (strpbrk(catlit, "\010\013")) {
|
|
lights06.Append(_T(";SY(LIGHTS82)"));
|
|
goto l06_end;
|
|
}
|
|
|
|
if (strpbrk(catlit, "\011")) {
|
|
lights06.Append(_T(";SY(LIGHTS81)"));
|
|
goto l06_end;
|
|
}
|
|
|
|
/*
|
|
* if (strpbrk(catlit, "\001\020")) {
|
|
* orientstr = S57_getAttVal(geo, "ORIENT");
|
|
* if (NULL != orientstr) {
|
|
* // FIXME: create a geo object (!?) LINE of lenght VALNMR
|
|
* // using ORIENT (from seaward) & POINT_T position
|
|
* g_string_append(lights05, ";LS(DASH,1,CHBLK)");
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
// Continuation A
|
|
|
|
GetStringAttr(obj, "COLOUR", col_str, 19);
|
|
|
|
if (strlen(col_str))
|
|
_parseList(col_str, colist, sizeof(colist));
|
|
else {
|
|
colist[0] = '\014'; // magenta (12)
|
|
colist[1] = '\000';
|
|
}
|
|
|
|
GetDoubleAttr(obj, "SECTR1", sectr1);
|
|
GetDoubleAttr(obj, "SECTR2", sectr2);
|
|
|
|
if ((-9 == sectr1) || (-9 == sectr2)) {
|
|
// This is not a sector light
|
|
|
|
wxString ssym;
|
|
|
|
if (valnmr < 10.0) {
|
|
// TODO create LightArray in s57chart.
|
|
// Then, if another LIGHT object is colocated here, set flare_at_45
|
|
/* if(_atPtPos(obj, rzRules->chart->pLIGHTSArray, false)) // Is
|
|
* this LIGHTS feature colocated with another LIGHTS?
|
|
*
|
|
*
|
|
* // If the light is white, yellow, or orange, make it a
|
|
* flare at 45 degrees if(strpbrk(colist, "\001\005\011")) flare_at_45 =
|
|
* true;
|
|
*/
|
|
ssym = _selSYcol(colist, 0, valnmr); // flare
|
|
b_isflare = true;
|
|
flare_at_45 = false;
|
|
} else {
|
|
ssym = _selSYcol(colist, 1, valnmr); // all round light
|
|
b_isflare = false;
|
|
}
|
|
|
|
// Is the light a directional or moire?
|
|
if (strpbrk(catlit, "\001\016")) {
|
|
if (orientstr.Len()) {
|
|
lights06.Append(ssym);
|
|
lights06.Append(orientstr);
|
|
lights06.Append(
|
|
_T(";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" ));
|
|
} else
|
|
lights06.Append(_T(";SY(QUESMRK1)"));
|
|
} else {
|
|
lights06.Append(ssym);
|
|
|
|
if (b_isflare) {
|
|
if (flare_at_45)
|
|
lights06.Append(_T(",45)"));
|
|
else
|
|
lights06.Append(_T(",135)"));
|
|
}
|
|
}
|
|
|
|
goto l06_end;
|
|
}
|
|
|
|
// Continuation B --sector light
|
|
if (-9 == sectr1) {
|
|
sectr1 = 0.0;
|
|
sectr2 = 0.0;
|
|
} else
|
|
sweep = (sectr1 > sectr2) ? sectr2 - sectr1 + 360 : sectr2 - sectr1;
|
|
|
|
if (sweep < 1.0 || sweep == 360.0) {
|
|
// handle all round light
|
|
wxString ssym = _selSYcol(colist, 1, valnmr); // all round light
|
|
lights06.Append(ssym);
|
|
|
|
/*
|
|
* if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
* GString *litdsn01 = _LITDSN01(geo);
|
|
* if (NULL != litdsn01) {
|
|
* g_string_append(lights05, ";TX('");
|
|
* g_string_append(lights05, litdsn01->str);
|
|
* g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)"
|
|
);
|
|
* g_string_free(litdsn01, TRUE);
|
|
}
|
|
|
|
}
|
|
*/
|
|
goto l06_end;
|
|
}
|
|
|
|
/*
|
|
* // scan for other lights with sector overlap at this position
|
|
* // compute light sector radius according to other sector
|
|
* if (1 == S52_state)
|
|
* {
|
|
* _setPtPos(geo, SECTRLIST);
|
|
* g_string_free(lights05, TRUE);
|
|
* return NULL;
|
|
}
|
|
else
|
|
{
|
|
extend_arc_radius = _atPtPos(geo, SECTRLIST);
|
|
|
|
// passe value via attribs to _renderAC
|
|
if (extend_arc_radius)
|
|
// FIXME: draw radius 25 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "Y");
|
|
else
|
|
// FIXME: draw radius 20 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "N");
|
|
}
|
|
*/
|
|
// setup sector
|
|
{
|
|
// Build the (opencpn private) command string like this:
|
|
// e.g. ";CA(OUTLW, 4,LITRD, 2, sectr1, sectr2, radius)"
|
|
|
|
double arc_radius = 20.; // mm
|
|
double sector_radius = 25.;
|
|
|
|
// Another non-standard extension....
|
|
// Sector light arc radius is scaled if the light has a reasonable
|
|
// VALNMR attribute
|
|
if (valnmr > 0) {
|
|
if (valnmr < 15.0)
|
|
arc_radius = 10.;
|
|
else if (valnmr < 30.0)
|
|
arc_radius = 15.;
|
|
else
|
|
arc_radius = 20.;
|
|
}
|
|
|
|
char sym[80];
|
|
strcpy(sym, ";CA(OUTLW, 4");
|
|
|
|
// max 1 color
|
|
if ('\0' == colist[1]) {
|
|
if (strpbrk(colist, "\003"))
|
|
strcat(sym, ",LITRD, 2");
|
|
else if (strpbrk(colist, "\004"))
|
|
strcat(sym, ",LITGN, 2");
|
|
else if (strpbrk(colist, "\001\006\013"))
|
|
strcat(sym, ",LITYW, 2");
|
|
else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
|
|
} else if ('\0' == colist[2]) {
|
|
if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
|
|
strcat(sym, ",LITRD, 2");
|
|
else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
|
|
strcat(sym, ",LITGN, 2");
|
|
else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
} else
|
|
strcat(sym, ",CHMGD, 2"); // default is magenta
|
|
|
|
if (strlen(litvisstr)) // Obscured/faint sector?
|
|
{
|
|
_parseList(litvisstr, litvis, sizeof(litvis));
|
|
|
|
if (strpbrk(litvis, "\003\007\010")) strcpy(sym, ";CA(CHBLK, 4,CHBRN, 1");
|
|
}
|
|
|
|
if (sectr2 <= sectr1) sectr2 += 360;
|
|
|
|
// Sectors are defined from seaward
|
|
if (sectr1 > 180)
|
|
sectr1 -= 180;
|
|
else
|
|
sectr1 += 180;
|
|
|
|
if (sectr2 > 180)
|
|
sectr2 -= 180;
|
|
else
|
|
sectr2 += 180;
|
|
|
|
char arc_data[80];
|
|
sprintf(arc_data, ",%5.1f, %5.1f, %5.1f, %5.1f", sectr1, sectr2, arc_radius,
|
|
sector_radius);
|
|
|
|
strcat(sym, arc_data);
|
|
|
|
wxString ssym(sym, wxConvUTF8);
|
|
lights06 = ssym;
|
|
|
|
goto l06_end;
|
|
}
|
|
|
|
l06_end:
|
|
|
|
// if( ps52plib->m_bShowLdisText )
|
|
{
|
|
// Only show Light in certain position once. Otherwise there will be
|
|
// clutter.
|
|
static double lastLat, lastLon;
|
|
static wxString lastDescription;
|
|
bool isFirstSector = true;
|
|
|
|
if (lastLat == obj->m_lat && lastLon == obj->m_lon) isFirstSector = false;
|
|
lastLat = obj->m_lat;
|
|
lastLon = obj->m_lon;
|
|
|
|
wxString litdsn01 = _LITDSN01(obj);
|
|
|
|
if (litdsn01.Len() && isFirstSector) {
|
|
lastDescription = litdsn01;
|
|
lights06.Append(_T(";TX('"));
|
|
lights06.Append(litdsn01);
|
|
|
|
if (flare_at_45)
|
|
lights06.Append(_T("',3,3,3,'15110',2,-1,CHBLK,23)" ));
|
|
else
|
|
lights06.Append(_T("',3,2,3,'15110',2,0,CHBLK,23)" ));
|
|
}
|
|
|
|
if (!isFirstSector && lastDescription != litdsn01) {
|
|
lastDescription = litdsn01;
|
|
lights06.Append(_T(";TX('"));
|
|
lights06.Append(litdsn01);
|
|
lights06.Append(_T("',3,2,3,'15110',2,1,CHBLK,23)" ));
|
|
}
|
|
}
|
|
|
|
lights06.Append('\037');
|
|
|
|
char *r = (char *)malloc(lights06.Len() + 1);
|
|
strcpy(r, lights06.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *LITDSN01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : LITDSN01 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
static void *OBSTRN04a(void *param)
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
static int f03;
|
|
if(!f03)
|
|
printf("s52csny : OBSTRN04 ERROR no conditional symbology for:
|
|
%s\n",rzRules->LUP->OBCL); f03++; return NULL;
|
|
}
|
|
*/
|
|
|
|
wxString SNDFRM02(S57Obj *obj, double depth_value);
|
|
|
|
static void *OBSTRN04(void *param)
|
|
// Remarks: Obstructions or isolated underwater dangers of depths less than the
|
|
// safety contour which lie within the safe waters defined by the safety contour
|
|
// are to be presented by a specific isolated danger symbol and put in IMO
|
|
// category DISPLAYBASE (see (3), App.2, 1.3). This task is performed
|
|
// by the sub-procedure "UDWHAZ03" which is called by this symbology
|
|
// procedure. Objects of the class "under water rock" are handled by this
|
|
// routine as well to ensure a consistent symbolization of isolated dangers on
|
|
// the seabed.
|
|
{
|
|
wxString obstrn04str;
|
|
// GString *sndfrm02str = NULL;
|
|
wxString *udwhaz03str = NULL;
|
|
// GString *valsoustr = S57_getAttVal(geo, "VALSOU");
|
|
bool b_promote = false;
|
|
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
// TODO Debug Hook
|
|
// if(obj->Index == 534)
|
|
// int yyp = 5;
|
|
|
|
double valsou = UNKNOWN;
|
|
double depth_value = UNKNOWN;
|
|
double least_depth = UNKNOWN;
|
|
|
|
wxString sndfrm02str;
|
|
wxString *quapnt01str = NULL;
|
|
|
|
GetDoubleAttr(obj, "VALSOU", valsou);
|
|
wxString *objName = GetStringAttrWXS(obj, "OBJNAM");
|
|
|
|
if (valsou != UNKNOWN) {
|
|
depth_value = valsou;
|
|
sndfrm02str = SNDFRM02(obj, valsou);
|
|
} else {
|
|
if (GEO_AREA == obj->Primitive_type)
|
|
least_depth = _DEPVAL01(obj, least_depth);
|
|
|
|
if (UNKNOWN == least_depth) {
|
|
int catobs = 0;
|
|
GetIntAttr(obj, "CATOBS", catobs);
|
|
int watlev = 0;
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
int expsou = 0;
|
|
GetIntAttr(obj, "EXPSOU", expsou);
|
|
if (expsou != 1) {
|
|
if (6 == catobs)
|
|
depth_value = 0.01;
|
|
else if (0 == watlev) // default
|
|
depth_value = -15.0;
|
|
else {
|
|
switch (watlev) {
|
|
case 5:
|
|
depth_value = 0.0;
|
|
break;
|
|
case 3:
|
|
depth_value = 0.01;
|
|
break;
|
|
case 4:
|
|
case 1:
|
|
case 2:
|
|
default:
|
|
depth_value = -15.0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
depth_value = least_depth;
|
|
}
|
|
|
|
udwhaz03str = _UDWHAZ03(obj, depth_value, rzRules, &b_promote);
|
|
|
|
if (GEO_POINT == obj->Primitive_type) {
|
|
// Continuation A
|
|
int sounding = FALSE;
|
|
quapnt01str = CSQUAPNT01(obj);
|
|
|
|
if (0 != udwhaz03str->Len()) {
|
|
obstrn04str.Append(*udwhaz03str);
|
|
obstrn04str.Append(*quapnt01str);
|
|
|
|
goto end;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20.0) {
|
|
int watlev = -9;
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
|
|
if (!strncmp(obj->FeatureName, "UWTROC", 6)) {
|
|
if (-9 == watlev) { // default
|
|
obstrn04str.Append(_T(";SY(DANGER51)"));
|
|
sounding = TRUE;
|
|
} else {
|
|
switch (watlev) {
|
|
case 3:
|
|
obstrn04str.Append(_T(";SY(DANGER51)"));
|
|
sounding = TRUE;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
obstrn04str.Append(_T(";SY(UWTROC04)"));
|
|
sounding = FALSE;
|
|
break;
|
|
default:
|
|
obstrn04str.Append(_T(";SY(DANGER51)"));
|
|
sounding = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (b_promote) {
|
|
// Move this UWTROC object to DisplayBase category
|
|
rzRules->obj->m_DisplayCat = DISPLAYBASE;
|
|
}
|
|
} else { // OBSTRN
|
|
if (-9 == watlev) { // default
|
|
obstrn04str.Append(_T(";SY(DANGER01)"));
|
|
sounding = TRUE;
|
|
} else {
|
|
switch (watlev) {
|
|
case 1:
|
|
case 2:
|
|
obstrn04str.Append(_T(";SY(LNDARE01)"));
|
|
sounding = FALSE;
|
|
break;
|
|
case 3:
|
|
obstrn04str.Append(_T(";SY(DANGER52)"));
|
|
sounding = TRUE;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
obstrn04str.Append(_T(";SY(DANGER53)"));
|
|
sounding = TRUE;
|
|
break;
|
|
default:
|
|
obstrn04str.Append(_T(";SY(DANGER51)"));
|
|
sounding = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else { // valsou > 20.0
|
|
obstrn04str.Append(_T(";SY(DANGER52)"));
|
|
sounding = TRUE;
|
|
}
|
|
} else { // NO valsou
|
|
// GString *objlstr = S57_getAttVal(geo, "OBJL");
|
|
// int objl = (NULL == objlstr)? 0 :
|
|
// atoi(objlstr->str);
|
|
int watlev = -9;
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
// GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (!strncmp(obj->FeatureName, "UWTROC", 6)) {
|
|
if (watlev == -9) // default
|
|
obstrn04str.Append(_T(";SY(UWTROC04)"));
|
|
else {
|
|
switch (watlev) {
|
|
case 2:
|
|
obstrn04str.Append(_T(";SY(LNDARE01)"));
|
|
break;
|
|
case 3:
|
|
obstrn04str.Append(_T(";SY(UWTROC03)"));
|
|
break;
|
|
default:
|
|
obstrn04str.Append(_T(";SY(UWTROC04)"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (b_promote) {
|
|
// Move this UWTROC object to DisplayBase category
|
|
rzRules->obj->m_DisplayCat = DISPLAYBASE;
|
|
}
|
|
} else { // OBSTRN
|
|
if (-9 == watlev) // default
|
|
obstrn04str = _T(";SY(OBSTRN01)");
|
|
else {
|
|
switch (watlev) {
|
|
case 1:
|
|
obstrn04str.Append(_T(";SY(OBSTRN11)"));
|
|
break;
|
|
case 2:
|
|
obstrn04str.Append(_T(";SY(OBSTRN11)"));
|
|
break;
|
|
case 3:
|
|
obstrn04str.Append(_T(";SY(OBSTRN01)"));
|
|
break;
|
|
case 4:
|
|
obstrn04str.Append(_T(";SY(OBSTRN03)"));
|
|
break;
|
|
case 5:
|
|
obstrn04str.Append(_T(";SY(OBSTRN03)"));
|
|
break;
|
|
default:
|
|
obstrn04str.Append(_T(";SY(OBSTRN01)"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sounding) obstrn04str.Append(sndfrm02str);
|
|
|
|
obstrn04str.Append(*quapnt01str);
|
|
|
|
goto end;
|
|
|
|
} // if geopoint
|
|
else {
|
|
if (GEO_LINE == obj->Primitive_type) {
|
|
// Continuation B
|
|
|
|
quapnt01str = CSQUAPNT01(obj);
|
|
|
|
if (quapnt01str->Len() > 1) {
|
|
long quapos;
|
|
quapnt01str->ToLong(&quapos);
|
|
if (2 <= quapos && quapos < 10) {
|
|
if (udwhaz03str->Len())
|
|
obstrn04str.Append(_T(";LC(LOWACC41)"));
|
|
else
|
|
obstrn04str.Append(_T(";LC(LOWACC31)"));
|
|
}
|
|
goto end;
|
|
}
|
|
|
|
if (udwhaz03str->Len()) {
|
|
obstrn04str.Append(_T("LS(DOTT,2,CHBLK)"));
|
|
goto end;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20.0)
|
|
obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
|
|
else
|
|
obstrn04str.Append(_T(";LS(DASH,2,CHBLK)"));
|
|
} else
|
|
obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
|
|
|
|
if (udwhaz03str->Len()) {
|
|
// Show the isolated danger symbol at the midpoint of the line
|
|
} else {
|
|
if (UNKNOWN != valsou)
|
|
if (valsou <= 20.0) obstrn04str.Append(sndfrm02str);
|
|
}
|
|
}
|
|
|
|
else // Area feature
|
|
{
|
|
quapnt01str = CSQUAPNT01(obj);
|
|
|
|
if (0 != udwhaz03str->Len()) {
|
|
obstrn04str.Append(_T(";AC(DEPVS);AP(FOULAR01)"));
|
|
obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
|
|
obstrn04str.Append(*udwhaz03str);
|
|
obstrn04str.Append(*quapnt01str);
|
|
|
|
goto end;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
// BUG in CA49995B.000 if we get here because there is no color
|
|
// beside NODATA (ie there is a hole in group 1 area!)
|
|
// g_string_append(obstrn04, ";AC(UINFR)");
|
|
|
|
if (valsou <= 20.0)
|
|
obstrn04str.Append(_T(";LS(DOTT,2,CHBLK)"));
|
|
else
|
|
obstrn04str.Append(_T(";LS(DASH,2,CHBLK)"));
|
|
|
|
obstrn04str.Append(sndfrm02str);
|
|
|
|
} else {
|
|
int watlev = -9;
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
// GString *watlevstr = S57_getAttVal(geo,
|
|
// "WATLEV");
|
|
|
|
if (watlev == -9) // default
|
|
obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)"));
|
|
else {
|
|
switch (watlev) {
|
|
case 1:
|
|
case 2:
|
|
obstrn04str.Append(_T(";AC(CHBRN);LS(SOLD,2,CSTLN)"));
|
|
break;
|
|
case 4:
|
|
obstrn04str.Append(_T(";AC(DEPIT);LS(DASH,2,CSTLN)"));
|
|
break;
|
|
case 5:
|
|
case 3: {
|
|
int catobs = -9;
|
|
GetIntAttr(obj, "CATOBS", catobs);
|
|
if (6 == catobs)
|
|
obstrn04str.Append(
|
|
_T(";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)"));
|
|
else
|
|
obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)"));
|
|
} break;
|
|
default:
|
|
obstrn04str.Append(_T(";AC(DEPVS);LS(DOTT,2,CHBLK)"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
obstrn04str.Append(*quapnt01str);
|
|
goto end;
|
|
|
|
/*
|
|
// Continuation C (AREAS_T)
|
|
GString *quapnt01str = CSQUAPNT01(geo);
|
|
if (NULL != udwhaz03str) {
|
|
g_string_append(obstrn04str,
|
|
";AC(DEPVS);AP(FOULAR01)"); g_string_append(obstrn04str,
|
|
";LS(DOTT,2,CHBLK)"); g_string_append(obstrn04str, udwhaz03str->str);
|
|
if (NULL != quapnt01str)
|
|
g_string_append(obstrn04str,
|
|
quapnt01str->str);
|
|
|
|
return obstrn04str;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
// BUG in CA49995B.000 if we get here because there is no
|
|
color
|
|
// beside NODATA (ie there is a hole in group 1 area!)
|
|
//g_string_append(obstrn04, ";AC(UINFR)");
|
|
|
|
if (valsou <= 20.0)
|
|
g_string_append(obstrn04str,
|
|
";LS(DOTT,2,CHBLK)"); else g_string_append(obstrn04str,
|
|
";LS(DASH,2,CHBLK)");
|
|
|
|
g_string_append(obstrn04str, sndfrm02str->str);
|
|
|
|
} else {
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL == watlevstr) // default
|
|
g_string_append(obstrn04str,
|
|
";AC(DEPVS);LS(DOTT,2,CHBLK)"); else { if ('3' == *watlevstr->str) {
|
|
GString *catobsstr =
|
|
S57_getAttVal(geo, "CATOBS"); if (NULL != catobsstr && '6' ==
|
|
*catobsstr->str) g_string_append(obstrn04str,
|
|
";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)"); } else { switch
|
|
(*watlevstr->str) { case '1': case '2': g_string_append(obstrn04str,
|
|
";AC(CHBRN);LS(SOLD,2,CSTLN)"); break; case '4':
|
|
g_string_append(obstrn04str, ";AC(DEPIT);LS(DASH,2,CSTLN)"); break;
|
|
case '5':
|
|
case '3':
|
|
default :
|
|
g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)"); break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_string_append(obstrn04str, quapnt01str->str);
|
|
|
|
return obstrn04str;
|
|
*/
|
|
} // area
|
|
}
|
|
|
|
end:
|
|
|
|
// This is a specialization, to print OBJNAM for obstructions, if available
|
|
// Seen in NZ ENCs, e.g. "Horn Rock"
|
|
if (objName) {
|
|
obstrn04str.Append(_T(";TX(OBJNAM,1,2,3,'15118',-1,-1,CHBLK,26)"));
|
|
delete objName;
|
|
}
|
|
|
|
obstrn04str.Append('\037');
|
|
|
|
char *r = (char *)malloc(obstrn04str.Len() + 1);
|
|
strcpy(r, obstrn04str.mb_str());
|
|
|
|
delete udwhaz03str;
|
|
delete quapnt01str;
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *OWNSHP02(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : OWNSHP02 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *PASTRK01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
printf("s52csny : PASTRK01 ERROR no conditional symbology for: %s\n",
|
|
rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *QUALIN01(void *param);
|
|
static void *QUAPNT01(void *param);
|
|
|
|
static void *QUAPOS01(void *param)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is
|
|
// attached to the spatial object, not the feature object. In OpenCPN
|
|
// implementation, QUAPOS of Point Objects has been converted to QUALTY
|
|
// attribute of object.
|
|
//
|
|
// This procedure passes the object to procedure QUALIN01 or QUAPNT01,
|
|
// which traces back to the spatial object, retrieves any QUAPOS attributes,
|
|
// and returns the appropriate symbolization to QUAPOS01.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString *q = NULL;
|
|
|
|
if (GEO_LINE == obj->Primitive_type)
|
|
q = CSQUALIN01(obj);
|
|
|
|
else
|
|
q = CSQUAPNT01(obj);
|
|
|
|
char *r = (char *)malloc(q->Len() + 1);
|
|
strcpy(r, q->mb_str());
|
|
|
|
delete q;
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *QUALIN01(void *param)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is
|
|
// attached only to the spatial component(s) of an object.
|
|
//
|
|
// A line object may be composed of more than one spatial object.
|
|
//
|
|
// This procedure looks at each of the spatial
|
|
// objects, and symbolizes the line according to the positional accuracy.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString *q = CSQUALIN01(obj);
|
|
char *r = (char *)malloc(q->Len() + 1);
|
|
strcpy(r, q->mb_str());
|
|
|
|
delete q;
|
|
return r;
|
|
}
|
|
|
|
wxString *CSQUALIN01(S57Obj *obj)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is
|
|
// attached only to the spatial component(s) of an object.
|
|
//
|
|
// A line object may be composed of more than one spatial object.
|
|
//
|
|
// This procedure looks at each of the spatial
|
|
// objects, and symbolizes the line according to the positional accuracy.
|
|
{
|
|
wxString qualino1;
|
|
int quapos = 0;
|
|
bool bquapos = GetIntAttr(obj, "QUAPOS", quapos);
|
|
const char *line = NULL;
|
|
|
|
if (bquapos) {
|
|
if (2 <= quapos && quapos < 10) line = "LC(LOWACC21)";
|
|
} else {
|
|
if (!strncmp("COALNE", obj->FeatureName, 6)) {
|
|
int conrad;
|
|
bool bconrad = GetIntAttr(obj, "CONRAD", conrad);
|
|
|
|
if (bconrad) {
|
|
if (1 == conrad)
|
|
line = "LS(SOLD,3,CHMGF);LS(SOLD,1,CSTLN)";
|
|
else
|
|
line = "LS(SOLD,1,CSTLN)";
|
|
} else
|
|
line = "LS(SOLD,1,CSTLN)";
|
|
|
|
} else // LNDARE
|
|
line = "LS(SOLD,1,CSTLN)";
|
|
}
|
|
|
|
if (NULL != line) qualino1.Append(wxString(line, wxConvUTF8));
|
|
|
|
qualino1.Append('\037');
|
|
|
|
wxString *r = new wxString(qualino1);
|
|
|
|
/* char *r = (char *)malloc(qualino1.Len() + 1);
|
|
strcpy(r, qualino1.mb_str());
|
|
*/
|
|
return r;
|
|
}
|
|
|
|
static void *QUAPNT01(void *param)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is
|
|
// attached only to the spatial component(s) of an object.
|
|
//
|
|
// This procedure retrieves any QUALTY (ne QUAPOS) attributes, and returns the
|
|
// appropriate symbols to the calling procedure.
|
|
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString *q = CSQUAPNT01(obj);
|
|
|
|
char *r = (char *)malloc(q->Len() + 1);
|
|
strcpy(r, q->mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
wxString *CSQUAPNT01(S57Obj *obj)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is
|
|
// attached only to the spatial component(s) of an object.
|
|
//
|
|
// This procedure retrieves any QUALTY (ne QUAPOS) attributes, and returns the
|
|
// appropriate symbols to the calling procedure.
|
|
|
|
{
|
|
wxString quapnt01;
|
|
int accurate = TRUE;
|
|
int qualty = 10;
|
|
bool bquapos = GetIntAttr(obj, "QUAPOS", qualty);
|
|
|
|
if (bquapos) {
|
|
if (2 <= qualty && qualty < 10) accurate = FALSE;
|
|
}
|
|
|
|
if (!accurate) {
|
|
switch (qualty) {
|
|
case 4:
|
|
quapnt01.Append(_T(";SY(QUAPOS01)"));
|
|
break; // "PA"
|
|
case 5:
|
|
quapnt01.Append(_T(";SY(QUAPOS02)"));
|
|
break; // "PD"
|
|
case 7:
|
|
case 8:
|
|
quapnt01.Append(_T(";SY(QUAPOS03)"));
|
|
break; // "REP"
|
|
default:
|
|
quapnt01.Append(_T(";SY(LOWACC03)"));
|
|
break; // "?"
|
|
}
|
|
}
|
|
|
|
quapnt01.Append('\037');
|
|
|
|
wxString *r = new wxString;
|
|
|
|
*r = quapnt01;
|
|
|
|
/* char *r = (char *)malloc(quapnt01.Len() + 1);
|
|
strcpy(r, quapnt01.mb_str());
|
|
*/
|
|
return r;
|
|
}
|
|
|
|
static void *SLCONS03(void *param)
|
|
|
|
// Remarks: Shoreline construction objects which have a QUAPOS attribute on
|
|
// their
|
|
// spatial component indicating that their position is unreliable are symbolized
|
|
// by a special linestyle in the place of the varied linestyles normally used.
|
|
// Otherwise this procedure applies the normal symbolization.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString slcons03;
|
|
|
|
bool bvalstr;
|
|
int ival;
|
|
|
|
const char *cmdw = NULL; // command word
|
|
|
|
int quapos;
|
|
bool bquapos = GetIntAttr(obj, "QUAPOS", quapos);
|
|
|
|
if (GEO_POINT == obj->Primitive_type) {
|
|
if (bquapos) {
|
|
if (2 <= quapos && quapos < 10) cmdw = "SY(LOWACC01)";
|
|
}
|
|
} else {
|
|
// This instruction not found in PLIB 3.4, but seems to appear in later PLIB
|
|
// implementations by commercial ECDIS providers, so.....
|
|
if (GEO_AREA == obj->Primitive_type) {
|
|
slcons03 = _T("AP(CROSSX01);");
|
|
}
|
|
|
|
// GEO_LINE and GEO_AREA are the same
|
|
if (bquapos) {
|
|
if (2 <= quapos && quapos < 10) cmdw = "LC(LOWACC01)";
|
|
} else {
|
|
bvalstr = GetIntAttr(obj, "CONDTN", ival);
|
|
|
|
if (bvalstr && (1 == ival || 2 == ival))
|
|
cmdw = "LS(DASH,1,CSTLN)";
|
|
else {
|
|
ival = 0;
|
|
bvalstr = GetIntAttr(obj, "CATSLC", ival);
|
|
|
|
if (bvalstr &&
|
|
(6 == ival || 15 == ival || 16 == ival)) // Some sort of wharf
|
|
cmdw = "LS(SOLD,4,CSTLN)";
|
|
else {
|
|
bvalstr = GetIntAttr(obj, "WATLEV", ival);
|
|
|
|
if (bvalstr && 2 == ival)
|
|
cmdw = "LS(SOLD,2,CSTLN)";
|
|
else if (bvalstr && (3 == ival || 4 == ival))
|
|
cmdw = "LS(DASH,2,CSTLN)";
|
|
else
|
|
cmdw = "LS(SOLD,2,CSTLN)"; // default
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// WARNING: not explicitly specified in S-52 !!
|
|
// FIXME:this is to put AC(DEPIT) --intertidal area
|
|
// Could this be bug in OGR ?
|
|
/*
|
|
if (AREAS_T == S57_getObjtype(geo)) {
|
|
GString *seabed01 = NULL;
|
|
GString *drval1str = S57_getAttVal(geo, "DRVAL1");
|
|
double drval1 = (NULL == drval1str)? -UNKNOWN :
|
|
atof(drval1str->str); GString *drval2str = S57_getAttVal(geo, "DRVAL2");
|
|
double drval2 = (NULL == drval2str)? -UNKNOWN :
|
|
atof(drval2str->str);
|
|
// NOTE: change sign of infinity (minus) to get out of bound in seabed01
|
|
|
|
|
|
PRINTF("***********drval1=%f drval2=%f \n", drval1, drval2);
|
|
seabed01 = _SEABED01(drval1, drval2);
|
|
slcons03 = g_string_new(seabed01->str);
|
|
g_string_free(seabed01, TRUE);
|
|
|
|
}
|
|
*/
|
|
|
|
if (NULL != cmdw) slcons03.Append(wxString(cmdw, wxConvUTF8));
|
|
|
|
// Match CM93 CMAPECS presentation?
|
|
/*
|
|
if (GEO_AREA == obj->Primitive_type)
|
|
slcons03.Append(_T(";AC(LANDA)"));
|
|
*/
|
|
|
|
slcons03.Append('\037');
|
|
|
|
char *r = (char *)malloc(slcons03.Len() + 1);
|
|
strcpy(r, slcons03.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *RESARE02(void *param)
|
|
// Remarks: A list-type attribute is used because an area of the object class
|
|
// RESARE may have more than one category (CATREA). For example an inshore
|
|
// traffic zone might also have fishing and anchoring prohibition and a
|
|
// prohibited area might also be a bird sanctuary or a mine field.
|
|
//
|
|
// This conditional procedure is set up to ensure that the categories of most
|
|
// importance to safe navigation are prominently symbolized, and to pass on
|
|
// all given information with minimum clutter. Only the most significant
|
|
// restriction is symbolized, and an indication of further limitations is given
|
|
// by a subscript "!" or "I". Further details are given under conditional
|
|
// symbology procedure RESTRN01
|
|
//
|
|
// Other object classes affected by attribute RESTRN are handled by
|
|
// conditional symbology procedure RESTRN01.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString resare02;
|
|
|
|
wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
|
|
// GString *restrnstr = S57_getAttVal(geo, "RESTRN");
|
|
|
|
char restrn[LISTSIZE] = {'\0'};
|
|
// GString *catreastr = S57_getAttVal(geo, "CATREA");
|
|
wxString *catreastr = GetStringAttrWXS(obj, "CATREA");
|
|
|
|
char catrea[LISTSIZE] = {'\0'};
|
|
wxString symb;
|
|
wxString line;
|
|
wxString prio;
|
|
|
|
if (NULL != catreastr)
|
|
_parseList(catreastr->mb_str(), catrea, sizeof(catrea));
|
|
|
|
if (NULL != restrnstr) {
|
|
_parseList(restrnstr->mb_str(), restrn, sizeof(restrn));
|
|
|
|
if (strpbrk(restrn, "\007\010\016")) { // entry restrictions
|
|
// Continuation A
|
|
if (strpbrk(restrn,
|
|
"\001\002\003\004\005\006")) // anchoring, fishing, trawling
|
|
symb = _T(";SY(ENTRES61)");
|
|
else {
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = _T(";SY(ENTRES61)");
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(ENTRES71)");
|
|
else {
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = _T(";SY(ENTRES71)");
|
|
else
|
|
symb = _T(";SY(ENTRES51)");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = _T(";LC(RESARE51)");
|
|
else
|
|
line = _T( ";LS(DASH,2,CHMGD)");
|
|
|
|
prio = _T(";OP(6---)"); // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\001\002")) { // anchoring
|
|
// Continuation B
|
|
if (strpbrk(restrn, "\003\004\005\006"))
|
|
symb = _T(";SY(ACHRES61)");
|
|
else {
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = _T(";SY(ACHRES61)");
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(ACHRES71)");
|
|
else {
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = _T( ";SY(ACHRES71)");
|
|
else
|
|
symb = _T(";SY(RESTRN51)");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = _T(";LC(RESARE51)"); // could be ACHRES51 when _drawLC is
|
|
// implemented fully
|
|
else
|
|
line = _T(";LS(DASH,2,CHMGD)");
|
|
|
|
prio = _T(";OP(6---)"); // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\003\004\005\006")) { // fishing/trawling
|
|
// Continuation C
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = _T(";SY(FSHRES51)");
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(FSHRES71)");
|
|
else {
|
|
if (NULL != catreastr &&
|
|
strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = _T(";SY(FSHRES71)");
|
|
else
|
|
symb = _T(";SY(FSHRES51)");
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = _T(";LC(FSHRES51)");
|
|
else
|
|
line = _T(";LS(DASH,2,CHMGD)");
|
|
|
|
prio = _T(";OP(6---)"); // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn,
|
|
"\011\012\013\014\015")) // diving, dredging, waking...
|
|
symb = _T(";SY(INFARE51)");
|
|
else
|
|
symb = _T(";SY(RSRDEF51)");
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = _T(";LC(CTYARE51)");
|
|
else
|
|
line = _T(";LS(DASH,2,CHMGD)");
|
|
}
|
|
// Todo more for s57 3.1 Look at caris catalog ATTR::RESARE
|
|
}
|
|
}
|
|
} else {
|
|
// Continuation D
|
|
if (NULL != catreastr) {
|
|
if (strpbrk(catrea, "\001\010\011\014\016\023\025\031")) {
|
|
if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = _T(";SY(CTYARE71)");
|
|
else
|
|
symb = _T(";SY(CTYARE51)");
|
|
} else {
|
|
if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = _T(";SY(INFARE51)");
|
|
else
|
|
symb = _T(";SY(RSRDEF51)");
|
|
}
|
|
} else
|
|
symb = _T(";SY(RSRDEF51)");
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = _T(";LC(CTYARE51)");
|
|
else
|
|
line = _T(";LS(DASH,2,CHMGD)");
|
|
}
|
|
|
|
// create command word
|
|
if (prio.Len()) resare02.Append(prio);
|
|
resare02.Append(line);
|
|
resare02.Append(symb);
|
|
|
|
resare02.Append('\037');
|
|
|
|
char *r = (char *)malloc(resare02.Len() + 1);
|
|
strcpy(r, resare02.mb_str());
|
|
|
|
delete restrnstr;
|
|
delete catreastr;
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *_RESCSP01(void *param);
|
|
static void *RESTRN01(void *param)
|
|
// Remarks: Objects subject to RESTRN01 are actually symbolised in sub-process
|
|
// RESCSP01, since the latter can also be accessed from other conditional
|
|
// symbology procedures. RESTRN01 merely acts as a "signpost" for
|
|
// RESCSP01.
|
|
//
|
|
// Object class RESARE is symbolised for the effect of attribute RESTRN in a
|
|
// separate conditional symbology procedure called RESARE02.
|
|
//
|
|
// Since many of the areas concerned cover shipping channels, the number of
|
|
// symbols used is minimised to reduce clutter. To do this, values of RESTRN are
|
|
// ranked for significance as follows: "Traffic Restriction" values of RESTRN:
|
|
// (1) RESTRN 7,8: entry prohibited or restricted
|
|
// RESTRN 14: IMO designated "area to be avoided" part of a TSS
|
|
// (2) RESTRN 1,2: anchoring prohibited or restricted
|
|
// (3) RESTRN 3,4,5,6: fishing or trawling prohibited or restricted
|
|
// (4) "Other Restriction" values of RESTRN are:
|
|
// RESTRN 9, 10: dredging prohibited or restricted,
|
|
// RESTRN 11,12: diving prohibited or restricted,
|
|
// RESTRN 13 : no wake area.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
|
|
|
|
// GString *restrn01str = S57_getAttVal(geo, "RESTRN");
|
|
char *restrn01 = NULL;
|
|
|
|
if (NULL != restrnstr)
|
|
restrn01 = (char *)_RESCSP01(param);
|
|
else
|
|
restrn01 = NULL;
|
|
|
|
delete restrnstr;
|
|
return restrn01;
|
|
}
|
|
|
|
static void *_RESCSP01(void *param)
|
|
// Remarks: See procedure RESTRN01
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString rescsp01;
|
|
// char *rescsp01 = NULL;
|
|
wxString *restrnstr = GetStringAttrWXS(obj, "RESTRN");
|
|
// GString *restrnstr = S57_getAttVal(geo, "RESTRN");
|
|
char restrn[LISTSIZE] = {'\0'}; // restriction list
|
|
wxString symb;
|
|
char *r = NULL;
|
|
|
|
if (restrnstr->Len()) {
|
|
_parseList(restrnstr->mb_str(), restrn, sizeof(restrn));
|
|
|
|
if (strpbrk(restrn, "\007\010\016")) {
|
|
// continuation A
|
|
if (strpbrk(restrn, "\001\002\003\004\005\006"))
|
|
symb = _T(";SY(ENTRES61)");
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(ENTRES71)");
|
|
else
|
|
symb = _T(";SY(ENTRES51)");
|
|
}
|
|
} else {
|
|
if (strpbrk(restrn, "\001\002")) {
|
|
// continuation B
|
|
if (strpbrk(restrn, "\003\004\005\006"))
|
|
symb = _T(";SY(ACHRES61)");
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T( ";SY(ACHRES71)");
|
|
else
|
|
symb = _T(";SY(ACHRES51)");
|
|
}
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\003\004\005\006")) {
|
|
// continuation C
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(FSHRES71)");
|
|
else
|
|
symb = _T(";SY(FSHRES51)");
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = _T(";SY(INFARE51)");
|
|
else
|
|
symb = _T(";SY(RSRDEF51)");
|
|
}
|
|
}
|
|
}
|
|
|
|
rescsp01.Append(symb);
|
|
rescsp01.Append('\037');
|
|
|
|
r = (char *)malloc(rescsp01.Len() + 1);
|
|
strcpy(r, rescsp01.mb_str());
|
|
|
|
delete restrnstr;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *SEABED01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
// CPLError((CPLErr)0, 0,
|
|
// "s52csny : SEABED01 ERROR no conditional symbology for: %s\n",
|
|
// rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
static void *SNDFRM02(void *param)
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
CPLError((CPLErr)0, 0,"s52csny : SNDFRM02 ERROR no conditional symbology
|
|
for: %s\n",rzRules->LUP->OBCL); return NULL;
|
|
}
|
|
*/
|
|
|
|
wxString SNDFRM02(S57Obj *obj, double depth_value);
|
|
|
|
static void *SOUNDG02(void *param)
|
|
// Remarks: In S-57 soundings are elements of sounding arrays rather than
|
|
// individual objects. Thus the conditional symbology methodology must examine
|
|
// each sounding of a sounding array one by one. To symbolize the depth values
|
|
// it calls the procedure SNDFRM02 which in turn translates the depth values
|
|
// into a set of symbols to be shown at the soundings position.
|
|
{
|
|
// Shortcut. This CS method causes a branch to an S52plib method
|
|
// which splits multi-point soundings into separate point objects,
|
|
// and then calls CS(SOUNDG03) on successive points below.
|
|
char *r = (char *)malloc(6);
|
|
strcpy(r, "MP();");
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *SOUNDG03(void *param)
|
|
// Remarks: SOUNDG03 is a private conditional symbology,
|
|
// called to render individual points of a multi-point sounding set.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
wxString s = SNDFRM02(obj, obj->z);
|
|
|
|
char *r = (char *)malloc(s.Len() + 1);
|
|
strcpy(r, s.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
wxString SNDFRM02(S57Obj *obj, double depth_value_in)
|
|
// Remarks: Soundings differ from plain text because they have to be readable
|
|
// under all circumstances and their digits are placed according to special
|
|
// rules. This conditional symbology procedure accesses a set of carefully
|
|
// designed sounding symbols provided by the symbol library and composes them to
|
|
// sounding labels. It symbolizes swept depth and it also symbolizes for low
|
|
// reliability as indicated by attributes QUASOU and QUAPOS.
|
|
{
|
|
wxString sndfrm02;
|
|
char temp_str[LISTSIZE] = {'\0'};
|
|
wxString symbol_prefix;
|
|
|
|
char symbol_prefix_a[200];
|
|
|
|
wxString *tecsoustr = GetStringAttrWXS(obj, "TECSOU");
|
|
char tecsou[LISTSIZE] = {'\0'};
|
|
|
|
wxString *quasoustr = GetStringAttrWXS(obj, "QUASOU");
|
|
char quasou[LISTSIZE] = {'\0'};
|
|
|
|
wxString *statusstr = GetStringAttrWXS(obj, "STATUS");
|
|
char status[LISTSIZE] = {'\0'};
|
|
|
|
double leading_digit = 0.0;
|
|
|
|
double safety_depth = S52_getMarinerParam(S52_MAR_SAFETY_DEPTH);
|
|
|
|
// Do the math to convert soundings to ft/metres/fathoms on request
|
|
double depth_value = depth_value_in;
|
|
|
|
// If the sounding value from the ENC (or SENC) is bogus, so state
|
|
if (depth_value_in > 40000.) depth_value = 99999.;
|
|
if (depth_value_in < -1000.) depth_value = 0.;
|
|
|
|
switch (ps52plib->m_nDepthUnitDisplay) {
|
|
case 0:
|
|
depth_value = depth_value * (1.0 / 0.3048); // feet
|
|
safety_depth = safety_depth * (1.0 / 0.3048);
|
|
break;
|
|
case 2:
|
|
depth_value = depth_value * (1.0 / 0.3048) / 6; // fathoms
|
|
safety_depth = safety_depth * (1.0 / 0.3048) / 6;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// FIXME: test to fix the rounding error (!?)
|
|
depth_value += (depth_value > 0.0) ? 0.01 : -0.01;
|
|
leading_digit = (int)fabs(depth_value);
|
|
|
|
if (depth_value <= safety_depth) // S52_getMarinerParam(S52_MAR_SAFETY_DEPTH)
|
|
symbol_prefix = _T("SOUNDS");
|
|
else
|
|
symbol_prefix = _T("SOUNDG");
|
|
|
|
strcpy(symbol_prefix_a, symbol_prefix.mb_str());
|
|
|
|
if (NULL != tecsoustr) {
|
|
_parseList(tecsoustr->mb_str(), tecsou, sizeof(tecsou));
|
|
if (strpbrk(tecsou, "\006")) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sB1)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
}
|
|
|
|
if (NULL != quasoustr)
|
|
_parseList(quasoustr->mb_str(), quasou, sizeof(quasou));
|
|
if (NULL != statusstr)
|
|
_parseList(statusstr->mb_str(), status, sizeof(status));
|
|
|
|
if (strpbrk(quasou, "\003\004\005\010\011") || strpbrk(status, "\022")) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sC2)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
} else {
|
|
int quapos = 0;
|
|
GetIntAttr(obj, "QUAPOS", quapos);
|
|
if (0 != quapos) {
|
|
if (2 <= quapos && quapos < 10) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sC2)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Continuation A
|
|
if (fabs(depth_value) < 10.0) {
|
|
// If showing as "feet", round off to one digit only
|
|
if ((ps52plib->m_nDepthUnitDisplay == 0) && (depth_value > 0)) {
|
|
double r1 = depth_value;
|
|
depth_value = wxRound(r1);
|
|
leading_digit = (int)depth_value;
|
|
}
|
|
|
|
if (depth_value < 10.0) {
|
|
// can be above water (negative)
|
|
int fraction = (int)abs((fabs(depth_value) - leading_digit) * 10);
|
|
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)abs(leading_digit));
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
if (fraction > 0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s5%1i)", symbol_prefix_a,
|
|
fraction);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
|
|
// above sea level (negative)
|
|
if (depth_value < 0.0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sA1)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
goto return_point;
|
|
}
|
|
}
|
|
|
|
if (fabs(depth_value) < 31.0) {
|
|
bool b_2digit = false;
|
|
double depth_value_pos = fabs(depth_value);
|
|
|
|
// If showing as "feet", round off to two digits only
|
|
if ((ps52plib->m_nDepthUnitDisplay == 0) && (depth_value_pos > 0)) {
|
|
double r1 = depth_value;
|
|
depth_value = wxRound(r1);
|
|
leading_digit = (int)depth_value_pos;
|
|
b_2digit = true;
|
|
}
|
|
|
|
double fraction = fabs(depth_value_pos - floor(leading_digit));
|
|
|
|
if (fraction != 0.0) {
|
|
fraction = fraction * 10;
|
|
if (leading_digit >= 10.0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)", symbol_prefix_a,
|
|
(int)leading_digit / 10);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
|
|
double first_digit = floor(leading_digit / 10);
|
|
int secnd_digit = (int)(floor(leading_digit - (first_digit * 10)));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
secnd_digit /*(int)leading_digit*/);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
|
|
if (!b_2digit) {
|
|
if ((int)fraction > 0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s5%1i)", symbol_prefix_a,
|
|
(int)fraction);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
}
|
|
|
|
if (depth_value < 0.0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sA1)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
|
|
goto return_point;
|
|
}
|
|
}
|
|
|
|
// Continuation B
|
|
if (fabs(depth_value) < 100.0) {
|
|
leading_digit = fabs(leading_digit);
|
|
|
|
double first_digit = floor(leading_digit / 10);
|
|
double secnd_digit = floor(leading_digit - (first_digit * 10));
|
|
|
|
if (depth_value < 0.0) {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)", symbol_prefix_a,
|
|
(int)first_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)secnd_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%sA1)", symbol_prefix_a);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
} else {
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)first_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)", symbol_prefix_a,
|
|
(int)secnd_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
}
|
|
goto return_point;
|
|
}
|
|
|
|
if (depth_value < 1000.0) {
|
|
double first_digit = floor(leading_digit / 100);
|
|
double secnd_digit = floor((leading_digit - (first_digit * 100)) / 10);
|
|
double third_digit =
|
|
floor(leading_digit - (first_digit * 100) - (secnd_digit * 10));
|
|
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)", symbol_prefix_a,
|
|
(int)first_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)secnd_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)", symbol_prefix_a,
|
|
(int)third_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
|
|
goto return_point;
|
|
}
|
|
|
|
if (depth_value < 10000.0) {
|
|
double first_digit = floor(leading_digit / 1000);
|
|
double secnd_digit = floor((leading_digit - (first_digit * 1000)) / 100);
|
|
double third_digit = floor(
|
|
(leading_digit - (first_digit * 1000) - (secnd_digit * 100)) / 10);
|
|
double last_digit = floor(leading_digit - (first_digit * 1000) -
|
|
(secnd_digit * 100) - (third_digit * 10));
|
|
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)", symbol_prefix_a,
|
|
(int)first_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)secnd_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)", symbol_prefix_a,
|
|
(int)third_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s4%1i)", symbol_prefix_a,
|
|
(int)last_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
|
|
goto return_point;
|
|
}
|
|
|
|
// Continuation C
|
|
{
|
|
double first_digit = floor(leading_digit / 10000);
|
|
double secnd_digit = floor((leading_digit - (first_digit * 10000)) / 1000);
|
|
double third_digit = floor(
|
|
(leading_digit - (first_digit * 10000) - (secnd_digit * 1000)) / 100);
|
|
double fourth_digit = floor((leading_digit - (first_digit * 10000) -
|
|
(secnd_digit * 1000) - (third_digit * 100)) /
|
|
10);
|
|
double last_digit =
|
|
floor(leading_digit - (first_digit * 10000) - (secnd_digit * 1000) -
|
|
(third_digit * 100) - (fourth_digit * 10));
|
|
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s3%1i)", symbol_prefix_a,
|
|
(int)first_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s2%1i)", symbol_prefix_a,
|
|
(int)secnd_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s1%1i)", symbol_prefix_a,
|
|
(int)third_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s0%1i)", symbol_prefix_a,
|
|
(int)fourth_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
chk_snprintf(temp_str, LISTSIZE, ";SY(%s4%1i)", symbol_prefix_a,
|
|
(int)last_digit);
|
|
sndfrm02.Append(wxString(temp_str, wxConvUTF8));
|
|
|
|
goto return_point;
|
|
}
|
|
|
|
return_point:
|
|
sndfrm02.Append('\037');
|
|
|
|
delete tecsoustr;
|
|
delete quasoustr;
|
|
delete statusstr;
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
static void *TOPMAR01(void *param)
|
|
// Remarks: Topmark objects are to be symbolized through consideration of their
|
|
// platforms e.g. a buoy. Therefore this conditional symbology procedure
|
|
// searches for platforms by looking for other objects that are located at the
|
|
// same position.. Based on the finding whether the platform is rigid or
|
|
// floating, the respective upright or sloping symbol is selected and presented
|
|
// at the objects location. Buoyf symbols and topmark symbols have been
|
|
// carefully designed to fit to each other when combined at the same position.
|
|
// The result is a composed symbol that looks like the traditional symbols the
|
|
// mariner is used to.
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
int top_int = 0;
|
|
bool battr = GetIntAttr(obj, "TOPSHP", top_int);
|
|
|
|
wxString sy;
|
|
|
|
if (!battr)
|
|
sy = _T(";SY(QUESMRK1)");
|
|
else {
|
|
int floating = FALSE; // not a floating platform
|
|
int topshp = (!battr) ? 0 : top_int;
|
|
|
|
if (TRUE == _atPtPos(obj, GetChartFloatingATONArray(rzRules), false))
|
|
floating = TRUE;
|
|
|
|
if (floating) {
|
|
// floating platform
|
|
switch (topshp) {
|
|
case 1:
|
|
sy = _T(";SY(TOPMAR02)");
|
|
break;
|
|
case 2:
|
|
sy = _T(";SY(TOPMAR04)");
|
|
break;
|
|
case 3:
|
|
sy = _T(";SY(TOPMAR10)");
|
|
break;
|
|
case 4:
|
|
sy = _T(";SY(TOPMAR12)");
|
|
break;
|
|
|
|
case 5:
|
|
sy = _T(";SY(TOPMAR13)");
|
|
break;
|
|
case 6:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
case 7:
|
|
sy = _T(";SY(TOPMAR65)");
|
|
break;
|
|
case 8:
|
|
sy = _T(";SY(TOPMAR17)");
|
|
break;
|
|
|
|
case 9:
|
|
sy = _T(";SY(TOPMAR16)");
|
|
break;
|
|
case 10:
|
|
sy = _T(";SY(TOPMAR08)");
|
|
break;
|
|
case 11:
|
|
sy = _T(";SY(TOPMAR07)");
|
|
break;
|
|
case 12:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
|
|
case 13:
|
|
sy = _T(";SY(TOPMAR05)");
|
|
break;
|
|
case 14:
|
|
sy = _T(";SY(TOPMAR06)");
|
|
break;
|
|
case 17:
|
|
sy = _T(";SY(TMARDEF2)");
|
|
break;
|
|
case 18:
|
|
sy = _T(";SY(TOPMAR10)");
|
|
break;
|
|
|
|
case 19:
|
|
sy = _T(";SY(TOPMAR13)");
|
|
break;
|
|
case 20:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
case 21:
|
|
sy = _T(";SY(TOPMAR13)");
|
|
break;
|
|
case 22:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
|
|
case 23:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
case 24:
|
|
sy = _T(";SY(TOPMAR02)");
|
|
break;
|
|
case 25:
|
|
sy = _T(";SY(TOPMAR04)");
|
|
break;
|
|
case 26:
|
|
sy = _T(";SY(TOPMAR10)");
|
|
break;
|
|
|
|
case 27:
|
|
sy = _T(";SY(TOPMAR17)");
|
|
break;
|
|
case 28:
|
|
sy = _T(";SY(TOPMAR18)");
|
|
break;
|
|
case 29:
|
|
sy = _T(";SY(TOPMAR02)");
|
|
break;
|
|
case 30:
|
|
sy = _T(";SY(TOPMAR17)");
|
|
break;
|
|
|
|
case 31:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
case 32:
|
|
sy = _T(";SY(TOPMAR10)");
|
|
break;
|
|
case 33:
|
|
sy = _T(";SY(TMARDEF2)");
|
|
break;
|
|
default:
|
|
sy = _T(";SY(TMARDEF2)");
|
|
break;
|
|
}
|
|
} else {
|
|
// not a floating platform
|
|
switch (topshp) {
|
|
case 1:
|
|
sy = _T(";SY(TOPMAR22)");
|
|
break;
|
|
case 2:
|
|
sy = _T(";SY(TOPMAR24)");
|
|
break;
|
|
case 3:
|
|
sy = _T(";SY(TOPMAR30)");
|
|
break;
|
|
case 4:
|
|
sy = _T(";SY(TOPMAR32)");
|
|
break;
|
|
|
|
case 5:
|
|
sy = _T(";SY(TOPMAR33)");
|
|
break;
|
|
case 6:
|
|
sy = _T(";SY(TOPMAR34)");
|
|
break;
|
|
case 7:
|
|
sy = _T(";SY(TOPMAR85)");
|
|
break;
|
|
case 8:
|
|
sy = _T(";SY(TOPMAR86)");
|
|
break;
|
|
|
|
case 9:
|
|
sy = _T(";SY(TOPMAR36)");
|
|
break;
|
|
case 10:
|
|
sy = _T(";SY(TOPMAR28)");
|
|
break;
|
|
case 11:
|
|
sy = _T(";SY(TOPMAR27)");
|
|
break;
|
|
case 12:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
|
|
case 13:
|
|
sy = _T(";SY(TOPMAR25)");
|
|
break;
|
|
case 14:
|
|
sy = _T(";SY(TOPMAR26)");
|
|
break;
|
|
case 15:
|
|
sy = _T(";SY(TOPMAR88)");
|
|
break;
|
|
case 16:
|
|
sy = _T(";SY(TOPMAR87)");
|
|
break;
|
|
|
|
case 17:
|
|
sy = _T(";SY(TMARDEF1)");
|
|
break;
|
|
case 18:
|
|
sy = _T(";SY(TOPMAR30)");
|
|
break;
|
|
case 19:
|
|
sy = _T(";SY(TOPMAR33)");
|
|
break;
|
|
case 20:
|
|
sy = _T(";SY(TOPMAR34)");
|
|
break;
|
|
|
|
case 21:
|
|
sy = _T(";SY(TOPMAR33)");
|
|
break;
|
|
case 22:
|
|
sy = _T(";SY(TOPMAR34)");
|
|
break;
|
|
case 23:
|
|
sy = _T(";SY(TOPMAR34)");
|
|
break;
|
|
case 24:
|
|
sy = _T(";SY(TOPMAR22)");
|
|
break;
|
|
|
|
case 25:
|
|
sy = _T(";SY(TOPMAR24)");
|
|
break;
|
|
case 26:
|
|
sy = _T(";SY(TOPMAR30)");
|
|
break;
|
|
case 27:
|
|
sy = _T(";SY(TOPMAR86)");
|
|
break;
|
|
case 28:
|
|
sy = _T(";SY(TOPMAR89)");
|
|
break;
|
|
|
|
case 29:
|
|
sy = _T(";SY(TOPMAR22)");
|
|
break;
|
|
case 30:
|
|
sy = _T(";SY(TOPMAR86)");
|
|
break;
|
|
case 31:
|
|
sy = _T(";SY(TOPMAR14)");
|
|
break;
|
|
case 32:
|
|
sy = _T(";SY(TOPMAR30)");
|
|
break;
|
|
case 33:
|
|
sy = _T(";SY(TMARDEF1)");
|
|
break;
|
|
default:
|
|
sy = _T(";SY(TMARDEF1)");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
wxString topmar;
|
|
topmar.Append(sy);
|
|
topmar.Append('\037');
|
|
|
|
char *r = (char *)malloc(topmar.Len() + 1);
|
|
strcpy(r, topmar.mb_str());
|
|
|
|
return r;
|
|
}
|
|
|
|
static void *UDWHAZ03(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
// CPLError((CPLErr)0, 0,
|
|
// "s52csny : UDWHAZ03 ERROR no conditional symbology for: %s\n",
|
|
// rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *VESSEL01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
// CPLError((CPLErr)0, 0,
|
|
// "s52csny : VESSEL01 ERROR no conditional symbology for: %s\n",
|
|
// rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
static void *VRMEBL01(void *param) {
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
//FIXME plib
|
|
// CPLError((CPLErr)0, 0,
|
|
// "s52csny : VRMEBL01 ERROR no conditional symbology for: %s\n",
|
|
// rzRules->LUP->OBCL);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
static void *WRECKS02a(void *param)
|
|
{
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
// S57Obj *obj = rzRules->obj;
|
|
|
|
static int f07;
|
|
if(!f07)
|
|
CPLError((CPLErr)0, 0,"s52csny : WRECKS02 ERROR no conditional
|
|
symbology for: %s\n",rzRules->LUP->OBCL); f07++; return NULL;
|
|
}
|
|
*/
|
|
|
|
static void *WRECKS02(void *param)
|
|
// Remarks: Wrecks of depths less than the safety contour which lie within the
|
|
// safe waters defined by the safety contour are to be presented by a specific
|
|
// isolated danger symbol and put in IMO category DISPLAYBASE (see (3), App.2,
|
|
// 1.3). This task is performed by the sub-procedure "UDWHAZ03" which is
|
|
// called by this symbology procedure.
|
|
{
|
|
wxString wrecks02str;
|
|
wxString sndfrm02str;
|
|
wxString *udwhaz03str = NULL;
|
|
wxString *quapnt01str = NULL;
|
|
double least_depth = UNKNOWN;
|
|
double depth_value = UNKNOWN;
|
|
// GString *valsoustr = S57_getAttVal(geo, "VALSOU");
|
|
double valsou = UNKNOWN;
|
|
bool b_promote = false;
|
|
|
|
ObjRazRules *rzRules = (ObjRazRules *)param;
|
|
S57Obj *obj = rzRules->obj;
|
|
|
|
GetDoubleAttr(obj, "VALSOU", valsou);
|
|
|
|
int watlev = -9;
|
|
GetIntAttr(obj, "WATLEV", watlev);
|
|
int catwrk = -9;
|
|
GetIntAttr(obj, "CATWRK", catwrk);
|
|
|
|
int quasou = -9;
|
|
// QUASOU is a list ie a string for us
|
|
wxString *quasoustr = GetStringAttrWXS(obj, "QUASOU");
|
|
char quasouchar[LISTSIZE] = {'\0'};
|
|
|
|
double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
|
|
|
|
if (UNKNOWN != valsou) {
|
|
depth_value = valsou;
|
|
sndfrm02str = SNDFRM02(obj, depth_value);
|
|
} else {
|
|
if (GEO_AREA == obj->Primitive_type)
|
|
least_depth = _DEPVAL01(obj, least_depth);
|
|
|
|
if (least_depth == UNKNOWN)
|
|
/*
|
|
{
|
|
// WARNING: ambiguity removed in WRECKS03 (see update)
|
|
|
|
if (-9 == watlev) // default
|
|
depth_value = -15.0;
|
|
else
|
|
switch (watlev)
|
|
{ // ambiguous
|
|
case 1:
|
|
case 2: depth_value = -15.0 ; break;
|
|
case 3: depth_value = 0.01; break;
|
|
case 4: depth_value = -15.0 ; break;
|
|
case 5: depth_value = 0.0 ; break;
|
|
case 6: depth_value = -15.0 ; break;
|
|
default :
|
|
{
|
|
if (-9 != catwrk)
|
|
{
|
|
switch (catwrk)
|
|
{
|
|
case 1: depth_value = 20.0;
|
|
break; case 2: depth_value = 0.0; break; case 4: case 5: depth_value =
|
|
-15.0; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
////////////////////////////////////////////////
|
|
// DSR New Logic Here (FIXME)
|
|
{
|
|
if (-9 != catwrk) {
|
|
switch (catwrk) {
|
|
case 1:
|
|
depth_value = 20.0;
|
|
break; // safe
|
|
case 2:
|
|
depth_value = 0.0;
|
|
break; // dangerous
|
|
case 4:
|
|
case 5:
|
|
depth_value = -15.0;
|
|
break;
|
|
}
|
|
} else {
|
|
if (-9 == watlev) // default
|
|
depth_value = -15.0;
|
|
else
|
|
switch (watlev) {
|
|
case 1:
|
|
case 2:
|
|
depth_value = -15.0;
|
|
break;
|
|
case 3:
|
|
depth_value = 0.01;
|
|
break;
|
|
case 4:
|
|
depth_value = -15.0;
|
|
break;
|
|
case 5:
|
|
depth_value = 0.0;
|
|
break;
|
|
case 6:
|
|
depth_value = -15.0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
depth_value = least_depth;
|
|
}
|
|
if (NULL != quasoustr)
|
|
_parseList(quasoustr->mb_str(), quasouchar, sizeof(quasouchar));
|
|
|
|
if (quasouchar[0] == 0 || NULL == strpbrk(quasouchar, "\07")) {
|
|
// Fixes FS 165 XXX where it is?
|
|
// 7 is 'least depth unknown, safe clearance at value shown'
|
|
udwhaz03str = _UDWHAZ03(obj, depth_value, rzRules, &b_promote);
|
|
|
|
} else {
|
|
quasou = 7;
|
|
udwhaz03str = new wxString();
|
|
}
|
|
quapnt01str = CSQUAPNT01(obj);
|
|
|
|
if (GEO_POINT == obj->Primitive_type) {
|
|
if (0 != udwhaz03str->Len()) {
|
|
wrecks02str = wxString(*udwhaz03str);
|
|
|
|
wrecks02str.Append(*quapnt01str);
|
|
|
|
} else {
|
|
// Continuation A (POINT_T)
|
|
if (UNKNOWN != valsou) {
|
|
///////////////////////////////////////////
|
|
// DSR New logic here, FIXME check s52 specs
|
|
|
|
/*
|
|
if (valsou <= 20.0)
|
|
{
|
|
wrecks02str = wxString(";SY(DANGER51)");
|
|
if (NULL != sndfrm02str)
|
|
wrecks02str.Append(sndfrm02str);
|
|
}
|
|
else
|
|
wrecks02str = wxString(";SY(DANGER52)");
|
|
*/
|
|
if ((valsou <
|
|
safety_contour) /* || (2 == catwrk)*/) // maybe redundant, seems
|
|
// like wrecks with valsou
|
|
// < 20 are always coded as
|
|
// "dangerous wrecks"
|
|
// Excluding (2 == catwrk)
|
|
// matches Caris logic
|
|
wrecks02str = wxString(_T(";SY(DANGER51)"));
|
|
else
|
|
wrecks02str = wxString(_T(";SY(DANGER52)"));
|
|
wrecks02str.Append(_T(";TX('Wk',3,1,2,'15110',2,0,CHBLK,21)"));
|
|
if (7 == quasou) // Fixes FS 165
|
|
wrecks02str.Append(_T(";SY(WRECKS07)"));
|
|
|
|
wrecks02str.Append(sndfrm02str); // always show valsou depth
|
|
///////////////////////////////////////////
|
|
|
|
wrecks02str.Append(*udwhaz03str);
|
|
wrecks02str.Append(*quapnt01str);
|
|
|
|
} else {
|
|
wxString sym;
|
|
|
|
if (-9 != catwrk && -9 != watlev) {
|
|
if (1 == catwrk && 3 == watlev)
|
|
sym = _T(";SY(WRECKS04)");
|
|
else {
|
|
if (2 == catwrk && 3 == watlev)
|
|
sym = _T(";SY(WRECKS05)");
|
|
else {
|
|
if (4 == catwrk || 5 == catwrk)
|
|
sym = _T(";SY(WRECKS01)");
|
|
else {
|
|
if (1 == watlev || 2 == watlev || 5 == watlev || 4 == watlev) {
|
|
sym = _T(";SY(WRECKS01)");
|
|
} else
|
|
sym = _T(";SY(WRECKS05)"); // default
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wrecks02str = sym;
|
|
if (NULL != quapnt01str) wrecks02str.Append(*quapnt01str);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Continuation B (AREAS_T)
|
|
int quapos = 0;
|
|
GetIntAttr(obj, "QUAPOS", quapos);
|
|
|
|
wxString line;
|
|
|
|
if (2 <= quapos && quapos < 10)
|
|
line = _T(";LC(LOWACC41)");
|
|
else {
|
|
if (0 != udwhaz03str->Len())
|
|
line = _T(";LS(DOTT,2,CHBLK)");
|
|
else {
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20)
|
|
line = _T(";LS(DOTT,2,CHBLK)");
|
|
else
|
|
line = _T(";LS(DASH,2,CHBLK)");
|
|
} else {
|
|
if (-9 == watlev)
|
|
line = _T(";LS(DOTT,2,CSTLN)");
|
|
else {
|
|
switch (watlev) {
|
|
case 1:
|
|
case 2:
|
|
line = _T(";LS(SOLD,2,CSTLN)");
|
|
break;
|
|
case 4:
|
|
line = _T(";LS(DASH,2,CSTLN)");
|
|
break;
|
|
case 3:
|
|
case 5:
|
|
|
|
default:
|
|
line = _T(";LS(DOTT,2,CSTLN)");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
wrecks02str = wxString(line);
|
|
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20) {
|
|
wrecks02str.Append(*udwhaz03str);
|
|
wrecks02str.Append(*quapnt01str);
|
|
wrecks02str.Append(sndfrm02str);
|
|
|
|
} else {
|
|
// NOTE: ??? same as above ???
|
|
wrecks02str.Append(*udwhaz03str);
|
|
wrecks02str.Append(*quapnt01str);
|
|
}
|
|
} else {
|
|
wxString ac;
|
|
|
|
if (-9 == watlev)
|
|
ac = _T(";AC(DEPVS)");
|
|
else
|
|
switch (watlev) {
|
|
case 1:
|
|
case 2:
|
|
ac = _T(";AC(CHBRN)");
|
|
break;
|
|
case 4:
|
|
ac = _T(";AC(DEPIT)");
|
|
break;
|
|
case 5:
|
|
case 3:
|
|
default:
|
|
ac = _T(";AC(DEPVS)");
|
|
break;
|
|
}
|
|
|
|
wrecks02str.Append(ac);
|
|
|
|
wrecks02str.Append(*udwhaz03str);
|
|
wrecks02str.Append(*quapnt01str);
|
|
}
|
|
}
|
|
|
|
wrecks02str.Append('\037');
|
|
|
|
char *r = (char *)malloc(wrecks02str.Len() + 1);
|
|
strcpy(r, wrecks02str.mb_str());
|
|
|
|
delete udwhaz03str;
|
|
delete quapnt01str;
|
|
delete quasoustr;
|
|
return r;
|
|
}
|
|
|
|
static wxString _LITDSN01(S57Obj *obj)
|
|
// Remarks: In S-57 the light characteristics are held as a series of attributes
|
|
// values. The mariner may wish to see a light description text string displayed
|
|
// on the screen similar to the string commonly found on a paper chart. This
|
|
// conditional procedure, reads the attribute values from the above list of
|
|
// attributes and composes a light description string which can be displayed.
|
|
// This procedure is provided as a C function which has as input, the above
|
|
// listed attribute values and as output, the light description.
|
|
{
|
|
// CATLIT, LITCHR, COLOUR, HEIGHT, LITCHR, SIGGRP, SIGPER, STATUS, VALNMR
|
|
|
|
char colist[20];
|
|
wxString return_value;
|
|
#if 0
|
|
// XXX CATLIT
|
|
int catlit = -9;
|
|
GetIntAttr(obj, "CATLIT", catlit);
|
|
|
|
if(-9 != catlit)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
1: directional function IP 30.1-3; 475.7;
|
|
2: rear/upper light
|
|
3: front/lower light
|
|
4: leading light IP 20.1-3; 475.6;
|
|
5: aero light IP 60; 476.1;
|
|
6: air obstruction light IP 61; 476.2;
|
|
7: fog detector light IP 62; 477;
|
|
8: flood light IP 63; 478.2;
|
|
9: strip light IP 64; 478.5;
|
|
10: subsidiary light IP 42; 471.8;
|
|
11: spotlight
|
|
12: front
|
|
13: rear
|
|
14: lower
|
|
15: upper
|
|
16: moire' effect IP 31; 475.8;
|
|
17: emergency
|
|
18: bearing light 478.1;
|
|
19: horizontally disposed
|
|
20: vertically disposed
|
|
*/
|
|
|
|
// LITCHR
|
|
int litchr = -9;
|
|
wxString spost(_T(""));
|
|
GetIntAttr(obj, "LITCHR", litchr);
|
|
|
|
bool b_grp2 = false; // 2 GRP attributes expected
|
|
if (-9 != litchr) {
|
|
switch (litchr) {
|
|
/*
|
|
case 1: return_value.Append(_T("F")); break;
|
|
case 2: return_value.Append(_T("Fl")); break;
|
|
case 3: return_value.Append(_T("Fl")); break;
|
|
case 4: return_value.Append(_T("Q")); break;
|
|
case 7: return_value.Append(_T("Iso")); break;
|
|
case 8: return_value.Append(_T("Occ")); break;
|
|
case 12: return_value.Append(_T("Mo")); break;
|
|
*/
|
|
|
|
case 1:
|
|
return_value.Append(_T("F"));
|
|
break; // fixed IP 10.1;
|
|
case 2:
|
|
return_value.Append(_T("Fl"));
|
|
break; // flashing IP 10.4;
|
|
case 3:
|
|
return_value.Append(_T("LFl"));
|
|
break; // long-flashing IP 10.5;
|
|
case 4:
|
|
return_value.Append(_T("Q"));
|
|
break; // quick-flashing IP 10.6;
|
|
case 5:
|
|
return_value.Append(_T("VQ"));
|
|
break; // very quick-flashing IP 10.7;
|
|
case 6:
|
|
return_value.Append(_T("UQ"));
|
|
break; // ultra quick-flashing IP 10.8;
|
|
case 7:
|
|
return_value.Append(_T("Iso"));
|
|
break; // isophased IP 10.3;
|
|
case 8:
|
|
return_value.Append(_T("Occ"));
|
|
break; // occulting IP 10.2;
|
|
case 9:
|
|
return_value.Append(_T("IQ"));
|
|
break; // interrupted quick-flashing IP 10.6;
|
|
case 10:
|
|
return_value.Append(_T("IVQ"));
|
|
break; // interrupted very quick-flashing IP 10.7;
|
|
case 11:
|
|
return_value.Append(_T("IUQ"));
|
|
break; // interrupted ultra quick-flashing IP 10.8;
|
|
case 12:
|
|
return_value.Append(_T("Mo"));
|
|
break; // morse IP 10.9;
|
|
case 13:
|
|
return_value.Append(_T("F + Fl"));
|
|
b_grp2 = true;
|
|
break; // fixed/flash IP 10.10;
|
|
case 14:
|
|
return_value.Append(_T("Fl + LFl"));
|
|
b_grp2 = true;
|
|
break; // flash/long-flash
|
|
case 15:
|
|
return_value.Append(_T("Occ + Fl"));
|
|
b_grp2 = true;
|
|
break; // occulting/flash
|
|
case 16:
|
|
return_value.Append(_T("F + LFl"));
|
|
b_grp2 = true;
|
|
break; // fixed/long-flash
|
|
case 17:
|
|
return_value.Append(_T("Al Occ"));
|
|
break; // occulting alternating
|
|
case 18:
|
|
return_value.Append(_T("Al LFl"));
|
|
break; // long-flash alternating
|
|
case 19:
|
|
return_value.Append(_T("Al Fl"));
|
|
break; // flash alternating
|
|
case 20:
|
|
return_value.Append(_T("Al Grp"));
|
|
break; // group alternating
|
|
case 21:
|
|
return_value.Append(_T("F"));
|
|
spost = _T(" (vert)");
|
|
break; // 2 fixed (vertical)
|
|
case 22:
|
|
return_value.Append(_T("F"));
|
|
spost = _T(" (horz)");
|
|
break; // 2 fixed (horizontal)
|
|
case 23:
|
|
return_value.Append(_T("F"));
|
|
spost = _T(" (vert)");
|
|
break; // 3 fixed (vertical)
|
|
case 24:
|
|
return_value.Append(_T("F"));
|
|
spost = _T(" (horz)");
|
|
break; // 3 fixed (horizontal)
|
|
case 25:
|
|
return_value.Append(_T("Q + LFl"));
|
|
b_grp2 = true;
|
|
break; // quick-flash plus long-flash
|
|
case 26:
|
|
return_value.Append(_T("VQ + LFl"));
|
|
b_grp2 = true;
|
|
break; // very quick-flash plus long-flash
|
|
case 27:
|
|
return_value.Append(_T("UQ + LFl"));
|
|
b_grp2 = true;
|
|
break; // ultra quick-flash plus long-flash
|
|
case 28:
|
|
return_value.Append(_T("Alt"));
|
|
break; // alternating
|
|
case 29:
|
|
return_value.Append(_T("F + Alt"));
|
|
b_grp2 = true;
|
|
break; // fixed and alternating flashing
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int nfirst_grp = -1;
|
|
if (b_grp2) {
|
|
wxString ret_new;
|
|
nfirst_grp = return_value.Find(_T(" "));
|
|
if (wxNOT_FOUND != nfirst_grp) {
|
|
ret_new = return_value.Mid(0, nfirst_grp);
|
|
ret_new.Append(_T("(?)"));
|
|
ret_new.Append(return_value.Mid(nfirst_grp));
|
|
return_value = ret_new;
|
|
nfirst_grp += 1;
|
|
}
|
|
}
|
|
|
|
// SIGGRP, (c)(c) ...
|
|
char grp_str[20] = {'\0'};
|
|
GetStringAttr(obj, "SIGGRP", grp_str, 19);
|
|
if (strlen(grp_str)) {
|
|
wxString ss(grp_str, wxConvUTF8);
|
|
|
|
if (b_grp2) {
|
|
wxStringTokenizer tkz(ss, _T("()"));
|
|
|
|
int n_tok = 0;
|
|
while (tkz.HasMoreTokens() && (n_tok < 2)) {
|
|
wxString s = tkz.GetNextToken();
|
|
if (s.Len()) {
|
|
if ((n_tok == 0) && (nfirst_grp > 0)) {
|
|
return_value[nfirst_grp] = s[0];
|
|
} else {
|
|
if (s != _T("1")) {
|
|
return_value.Append(_T("("));
|
|
return_value.Append(s);
|
|
return_value.Append(_T(")"));
|
|
}
|
|
}
|
|
|
|
n_tok++;
|
|
}
|
|
}
|
|
} else {
|
|
if (ss != _T("(1)")) return_value.Append(ss);
|
|
}
|
|
}
|
|
|
|
// COLOUR,
|
|
char col_str[20] = {'\0'};
|
|
|
|
// Don't show for sectored lights since we are only showing one of the
|
|
// sectors.
|
|
double sectrTest;
|
|
bool hasSectors = GetDoubleAttr(obj, "SECTR1", sectrTest);
|
|
|
|
if (!hasSectors) {
|
|
GetStringAttr(obj, "COLOUR", col_str, 19);
|
|
|
|
int n_cols = 0;
|
|
if (strlen(col_str)) n_cols = _parseList(col_str, colist, sizeof(colist));
|
|
|
|
if (n_cols) return_value.Append(_T(" "));
|
|
|
|
for (int i = 0; i < n_cols; i++) {
|
|
switch (colist[i]) {
|
|
case 1:
|
|
return_value.Append(_T("W"));
|
|
break;
|
|
case 3:
|
|
return_value.Append(_T("R"));
|
|
break;
|
|
case 4:
|
|
return_value.Append(_T("G"));
|
|
break;
|
|
case 6:
|
|
return_value.Append(_T("Y"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
1: white IP 11.1; 450.2-3;
|
|
2: black
|
|
3: red IP 11.2; 450.2-3;
|
|
4: green IP 11.3; 450.2-3;
|
|
5: blue IP 11.4; 450.2-3;
|
|
6: yellow IP 11.6; 450.2-3;
|
|
7: grey
|
|
8: brown
|
|
9: amber IP 11.8; 450.2-3;
|
|
10: violet IP 11.5; 450.2-3;
|
|
11: orange IP 11.7; 450.2-3;
|
|
12: magenta
|
|
13: pink
|
|
*/
|
|
|
|
// SIGPER, xx.xx
|
|
double sigper = UNKNOWN;
|
|
GetDoubleAttr(obj, "SIGPER", sigper);
|
|
|
|
if (UNKNOWN != sigper) {
|
|
wxString s;
|
|
if (fabs(wxRound(sigper) - sigper) > 0.01)
|
|
s.Printf(_T("%4.1fs"), sigper);
|
|
else
|
|
s.Printf(_T("%2.0fs"), sigper);
|
|
|
|
s.Trim(false); // remove leading spaces
|
|
s.Prepend(_T(" "));
|
|
return_value.Append(s);
|
|
}
|
|
|
|
// HEIGHT, xxx.x
|
|
double height = UNKNOWN;
|
|
GetDoubleAttr(obj, "HEIGHT", height);
|
|
|
|
if (UNKNOWN != height) {
|
|
wxString s;
|
|
if (ps52plib->m_nHeightUnitDisplay == 1) { // feet
|
|
s.Printf(_T("%3.0fft"), height * (1.0 / 0.3048));
|
|
} else { // meters
|
|
s.Printf(_T("%3.0fm"), height);
|
|
}
|
|
|
|
s.Trim(false); // remove leading spaces
|
|
s.Prepend(_T(" "));
|
|
return_value.Append(s);
|
|
}
|
|
|
|
// VALNMR, xx.x
|
|
double valnmr = UNKNOWN;
|
|
GetDoubleAttr(obj, "VALNMR", valnmr);
|
|
|
|
if (UNKNOWN != valnmr && !hasSectors) {
|
|
wxString s;
|
|
s.Printf(_T("%2.0fNm"), valnmr);
|
|
s.Trim(false); // remove leading spaces
|
|
s.Prepend(_T(" "));
|
|
return_value.Append(s);
|
|
}
|
|
|
|
#if 0
|
|
|
|
// STATUS,
|
|
gstr = S57_getAttVal(geo, "STATUS");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
/*
|
|
1: permanent
|
|
2: occasional IP 50; 473.2;
|
|
3: recommended IN 10; 431.1;
|
|
4: not in use IL 14, 44; 444.7;
|
|
5: periodic/intermittent IC 21; IQ 71; 353.3; 460.5;
|
|
6: reserved IN 12.9;
|
|
7: temporary IP 54;
|
|
8: private IQ 70;
|
|
9: mandatory
|
|
10: destroyed/ruined
|
|
11: extinguished
|
|
12: illuminated
|
|
13: historic
|
|
14: public
|
|
15: synchronized
|
|
16: watched
|
|
17: un-watched
|
|
18: existence doubtful
|
|
*/
|
|
|
|
#endif
|
|
|
|
return_value.Append(spost); // add any final modifiers
|
|
|
|
return return_value;
|
|
}
|
|
|
|
static void *SYMINS01(void *param) {
|
|
ObjRazRules *rzRules = static_cast<ObjRazRules *>(param);
|
|
if (!rzRules || !rzRules->obj) return NULL;
|
|
|
|
char symins[258] = {'\0'};
|
|
GetStringAttr(rzRules->obj, "SYMINS", symins, sizeof(symins) - 2);
|
|
|
|
size_t len = strlen(symins);
|
|
symins[len] = '\037';
|
|
symins[len + 1] = '\0';
|
|
|
|
char *r = static_cast<char *>(malloc(len + 2));
|
|
if (!r) return NULL;
|
|
|
|
memcpy(r, symins, len + 2);
|
|
return r;
|
|
}
|
|
|
|
//--------------------------------
|
|
//
|
|
// JUMP TABLE SECTION
|
|
//
|
|
//--------------------------------
|
|
Cond condTable[] = {
|
|
{"CLRLIN01", CLRLIN01},
|
|
{"DATCVR01", DATCVR01},
|
|
{"DATCVR01", DATCVR01},
|
|
{"DEPARE01", DEPARE01},
|
|
{"DEPARE02", DEPARE01}, // new in PLIB 3_3, opencpn defaults to DEPARE01
|
|
{"DEPCNT02", DEPCNT02},
|
|
{"DEPVAL01", DEPVAL01},
|
|
{"LEGLIN02", LEGLIN02},
|
|
{"LIGHTS05", LIGHTS05}, // new in PLIB 3_3, replaces LIGHTS04
|
|
{"LITDSN01", LITDSN01},
|
|
{"OBSTRN04", OBSTRN04},
|
|
{"OWNSHP02", OWNSHP02},
|
|
{"PASTRK01", PASTRK01},
|
|
{"QUAPOS01", QUAPOS01},
|
|
{"QUALIN01", QUALIN01},
|
|
{"QUAPNT01", QUAPNT01},
|
|
{"SLCONS03", SLCONS03},
|
|
{"RESARE02", RESARE02},
|
|
{"RESTRN01", RESTRN01},
|
|
// {"RESCSP01",RESCSP01},
|
|
{"SEABED01", SEABED01},
|
|
// {"SNDFRM02",SNDFRM02},
|
|
{"SOUNDG02", SOUNDG02},
|
|
{"TOPMAR01", TOPMAR01},
|
|
{"UDWHAZ03", UDWHAZ03},
|
|
{"VESSEL01", VESSEL01},
|
|
{"VRMEBL01", VRMEBL01},
|
|
{"WRECKS02", WRECKS02},
|
|
{"SOUNDG03", SOUNDG03}, // special case for MPS
|
|
{"SYMINS01", SYMINS01}, // Container for Virtual AIS ATONS, special case
|
|
{"########", NULL}};
|
|
|
|
#if 0
|
|
// S52CS.c : Conditional Symbologie procedure 3.2 (CS)
|
|
//
|
|
// Project: OpENCview
|
|
|
|
/*
|
|
This file is part of the OpENCview project, a viewer of ENC
|
|
Copyright (C) 2000-2004 Sylvain Duclos sduclos@users.sourceforgue.net
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
// NOTE: remarks commenting each CS are extracted from pslb03_2.pdf (sec. 12)
|
|
|
|
// FIXME: DEPCNT02: call DB for area DEPARE & DRGARE that intersect this line
|
|
// FIXME:_DEPVAL01: call DB for area DEPARE & UNSARE that intersect this area
|
|
// FIXME:_UDWHAZ03: call DB for area DRGARE & DEPARE that intersect this point/area
|
|
|
|
#include "S52CS.h"
|
|
|
|
#include "S52utils.h" // PRINTF()
|
|
|
|
#include <stdlib.h> // atof()
|
|
#include <math.h> // fabsf(), HUGE_VAL
|
|
#include <ctype.h> // isdigit()
|
|
|
|
#define UNKNOWN 1e6 // HUGE_VAL // INFINITY/NAN
|
|
|
|
#define COALNE 30 // Coastline
|
|
#define DEPARE 42 // Depth area
|
|
#define DEPCNT 43 // Depth contour
|
|
#define DRGARE 46 // Dredged area
|
|
#define UWTROC 153 // Underwater rock / awash rock
|
|
#define WRECKS 159 // Wreck
|
|
|
|
// point list name
|
|
#define LIGHTLIST 0
|
|
#define SECTRLIST 1
|
|
#define FLOATLIST 2 // floating platform
|
|
#define RIGIDLIST 3 // rigid platform
|
|
//static GPtrArray *_lightList = NULL;
|
|
//static GPtrArray *_sectrList = NULL;
|
|
//static GPtrArray *_flaotList = NULL;
|
|
static GPtrArray *_ptList[] = {NULL, NULL, NULL, NULL};
|
|
|
|
int S52_state = 1;
|
|
|
|
// size of attributes value list buffer
|
|
#define LISTSIZE 16 // list size
|
|
|
|
#define version "3.2.0"
|
|
char *S52_CS_version()
|
|
{
|
|
return version;
|
|
}
|
|
|
|
int S52_CS_init()
|
|
{
|
|
_ptList[LIGHTLIST] = g_ptr_array_new();
|
|
_ptList[SECTRLIST] = g_ptr_array_new();
|
|
_ptList[FLOATLIST] = g_ptr_array_new();
|
|
_ptList[RIGIDLIST] = g_ptr_array_new();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int S52_CS_done()
|
|
{
|
|
g_ptr_array_free(_ptList[LIGHTLIST], TRUE);
|
|
g_ptr_array_free(_ptList[SECTRLIST], TRUE);
|
|
g_ptr_array_free(_ptList[FLOATLIST], TRUE);
|
|
g_ptr_array_free(_ptList[RIGIDLIST], TRUE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int S52_CS_setPtPos(S57_geo *geoData, char *name)
|
|
{
|
|
printf("name = %s\n", name);
|
|
|
|
if (POINT_T == S57_getObjtype(geoData)) {
|
|
|
|
// set floating platform
|
|
if ((0==strncmp(name, "LITFLT", 6)) ||
|
|
(0==strncmp(name, "LITVES", 6)) ||
|
|
(0==strncmp(name, "BOY", 3)))
|
|
g_ptr_array_add(_ptList[FLOATLIST], (gpointer) geoData);
|
|
|
|
// set rigid platform
|
|
if (0==strncmp(name, "BCN", 3))
|
|
g_ptr_array_add(_ptList[RIGIDLIST], (gpointer) geoData);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int _atPtPos(S57_geo *geoNew, int listNm)
|
|
// return TRUE if there is a light at this position
|
|
// or if its an extended arc radius else FALSE
|
|
{
|
|
int i;
|
|
GPtrArray *curntList = _ptList[listNm];
|
|
|
|
for (i=0; i<curntList->len; i++) {
|
|
S57_geo *geoOld = g_ptr_array_index(curntList, i);
|
|
|
|
if (S57_samePtPos(geoNew, geoOld)) {
|
|
|
|
if (SECTRLIST != listNm)
|
|
return TRUE;
|
|
else {
|
|
// check for extend arc radius
|
|
GString *Asectr1str = S57_getAttVal(geoOld, "SECTR1");
|
|
GString *Asectr2str = S57_getAttVal(geoOld, "SECTR2");
|
|
GString *Bsectr1str = S57_getAttVal(geoNew, "SECTR1");
|
|
GString *Bsectr2str = S57_getAttVal(geoNew, "SECTR2");
|
|
|
|
// check present
|
|
if (NULL == Asectr1str ||
|
|
NULL == Asectr1str ||
|
|
NULL == Asectr1str ||
|
|
NULL == Asectr1str)
|
|
return FALSE;
|
|
|
|
{
|
|
double Asectr1 = atof(Asectr1str->str);
|
|
double Asectr2 = atof(Asectr2str->str);
|
|
double Bsectr1 = atof(Bsectr1str->str);
|
|
double Bsectr2 = atof(Bsectr2str->str);
|
|
double Asweep = (Asectr1 > Asectr2) ?
|
|
Asectr2-Asectr1+360 : Asectr2-Asectr1;
|
|
double Bsweep = (Bsectr1 > Bsectr2) ?
|
|
Bsectr2-Bsectr1+360 : Bsectr2-Bsectr1;
|
|
|
|
// check sector overlap
|
|
if (Asectr2<=Bsectr1 || Asectr1>=Bsectr2) {
|
|
if (Asweep == Bsweep) {
|
|
g_string_truncate(Bsectr2str, 0);
|
|
g_string_sprintf(Bsectr2str, "%f",Bsectr2-1);
|
|
S57_setAtt(geoNew, "SECTR2", Bsectr2str->str);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// check if other sector larger
|
|
if (Asweep >= Bsweep)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int _setPtPos(S57_geo *geo, int listNm)
|
|
// TRUE if set new position of a light
|
|
// else FALSE (ie there is a light at this position)
|
|
{
|
|
GPtrArray *curntList = _ptList[listNm];
|
|
|
|
if (_atPtPos(geo, listNm))
|
|
return 1;
|
|
else
|
|
g_ptr_array_add(curntList, (gpointer) geo);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _parseList(const char *str, char *buf)
|
|
// Put a string of comma delimited number in an array (buf).
|
|
// Return: the number of value in buf.
|
|
// Assume: - number < 256,
|
|
// - list size less then LISTSIZE-1 .
|
|
// Note: buf is \0 terminated for strpbrk().
|
|
{
|
|
int i = 0;
|
|
|
|
if (NULL != str && *str != '\0') {
|
|
do {
|
|
if ( i>= LISTSIZE-1) {
|
|
PRINTF("OVERFLOW --value in list lost!!\n");
|
|
break;
|
|
}
|
|
|
|
/*
|
|
if (255 < (unsigned char) atoi(str)) {
|
|
PRINTF("value overflow (>255)\n");
|
|
exit(0);
|
|
}
|
|
*/
|
|
|
|
buf[i++] = (unsigned char) atoi(str);
|
|
|
|
while(isdigit(*str++)); // next
|
|
//while( g_ascii_isdigit(c)); // next
|
|
|
|
} while(*str++ != '\0'); // skip ',' or exit
|
|
}
|
|
|
|
buf[i] = '\0';
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static GString *CLRLIN01 (S57_geo *geo)
|
|
// Remarks: A clearing line shows a single arrow head at one of its ends. The direction
|
|
// of the clearing line must be calculated from its line object in order to rotate
|
|
// the arrow head symbol and place it at the correct end. This cannot be
|
|
// achieved with a complex linestyle since linestyle symbols cannot be sized
|
|
// to the length of the clearing line. Instead a linestyle with a repeating pattern
|
|
// of arrow symbols had to be used which does not comply with the required
|
|
// symbolization.
|
|
{
|
|
|
|
PRINTF("Mariner's object not drawn\n");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static GString *DATCVR01 (S57_geo *geo)
|
|
// Remarks: This conditional symbology procedure describes procedures for:
|
|
// - symbolizing the limit of ENC coverage;
|
|
// - symbolizing navigational purpose boundaries ("scale boundarie"); and
|
|
// - indicating overscale display.
|
|
//
|
|
// Note that the mandatory meta object CATQUA is symbolized by the look-up table.
|
|
//
|
|
// Because the methods adopted by an ECDIS to meet the IMO and IHO requirements
|
|
// listed on the next page will depend on the manufacturer's software, and cannot be
|
|
// described in terms of a flow chart in the same way as other conditional procedures,
|
|
// this procedure is in the form of written notes.
|
|
{
|
|
GString *datcvr01 = NULL;
|
|
|
|
///////////////////////
|
|
// 1- REQUIREMENT
|
|
// (IMO/IHO specs. explenation)
|
|
|
|
///////////////////////
|
|
// 2- ENC COVERAGE
|
|
//
|
|
// 2.1- Limit of ENC coverage
|
|
//datcvr01 = g_string_new(";OP(3OD11060);LC(HODATA01)");
|
|
// FIXME: get cell extend
|
|
|
|
// 2.2- No data areas
|
|
// This can be done outside of CS (ie when clearing the screen in Mesa)
|
|
// FIXME: ";OP(0---);AC(NODATA)"
|
|
// FIXME: set geo to cover earth (!)
|
|
|
|
//////////////////////
|
|
// 3- SCALE BOUNDARIES
|
|
//
|
|
// 3.1- Chart scale boundaties
|
|
// FIXME;
|
|
//g_string_append(datcvr01, ";LS(SOLD,1,CHGRD)");
|
|
// -OR- LC(SCLBDYnn) (?)
|
|
//
|
|
// ;OP(3OS21030)
|
|
|
|
// 3.2- Graphical index of navigational purpose
|
|
// FIXME: draw extent of available SENC in DB
|
|
|
|
//////////////////////
|
|
// 4- OVERSCALE
|
|
//
|
|
// FIXME: get meta date CSCL of DSPM field
|
|
// FIXME: get object M_CSCL or CSCALE
|
|
//
|
|
// 4.1- Overscale indication
|
|
// FIXME: compute, scale = [denominator of the compilation scale] /
|
|
// [denominator of the display scale]
|
|
// FIXME: draw overscale indication (ie TX("X%3.1f",scale))
|
|
//
|
|
// 4.2- Ovescale area at a chart scale boundary
|
|
// FIXME: test if next chart is over scale (ie going from large scale chart
|
|
// to a small scale chart)
|
|
// FIXME: draw AP(OVERSC01) on overscale part of display
|
|
//g_string(";OP(3OS21030)");
|
|
|
|
//
|
|
// 4.3- Larger scale data available
|
|
// FIXME: display indication of better scale available (?)
|
|
|
|
|
|
PRINTF("not computed\n");
|
|
|
|
return datcvr01;
|
|
}
|
|
|
|
static GString *_SEABED01(double drval1, double drval2);
|
|
static GString *_RESCSP01(S57_geo *geo);
|
|
static GString *DEPARE01 (S57_geo *geo)
|
|
// Remarks: An object of the class "depth area" is coloured and covered with fill patterns
|
|
// according to the mariners selections of shallow contour, safety contour and
|
|
// deep contour. This requires a decision making process provided by the sub-procedure
|
|
// "SEABED01" which is called by this symbology procedure.
|
|
// Objects of the class "dredged area" are handled by this routine as well to
|
|
// ensure a consistent symbolization of areas that represent the surface of the
|
|
// seabed.
|
|
{
|
|
GString *depare01 = NULL;
|
|
int objl = 0;
|
|
GString *objlstr = NULL;
|
|
GString *drval1str = S57_getAttVal(geo, "DRVAL1");
|
|
double drval1 = UNKNOWN;
|
|
GString *drval2str = S57_getAttVal(geo, "DRVAL2");
|
|
double drval2 = UNKNOWN;
|
|
|
|
if (NULL == drval1str || NULL == drval2str) {
|
|
PRINTF("ERROR: drval1 or drval2 should have the value UNKNOWN\n");
|
|
return NULL;
|
|
}
|
|
|
|
drval1 = (NULL == drval1str) ? -1.0 : atof(drval1str->str);
|
|
drval2 = (NULL == drval2str) ? drval1+0.01 : atof(drval2str->str);
|
|
|
|
depare01 = _SEABED01(drval1, drval2);
|
|
|
|
objlstr = S57_getAttVal(geo, "OBJL");
|
|
objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
|
|
|
|
if (DRGARE == objl) {
|
|
g_string_append(depare01, ";AP(DRGARE01)");
|
|
g_string_append(depare01, ";LS(DASH,1,CHGRF)");
|
|
|
|
if (NULL != S57_getAttVal(geo, "RESTRN")) {
|
|
GString *rescsp01 = _RESCSP01(geo);
|
|
if (NULL != rescsp01) {
|
|
g_string_append(depare01, rescsp01->str);
|
|
g_string_free(rescsp01, TRUE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return depare01;
|
|
}
|
|
|
|
static GString *_SNDFRM02(S57_geo *geo, double depth_value);
|
|
static GString *DEPCNT02 (S57_geo *geo)
|
|
// Remarks: An object of the class "depth contour" or "line depth area" is highlighted and must
|
|
// be shown under all circumstances if it matches the safety contour depth value
|
|
// entered by the mariner (see IMO PS 3.6). But, while the mariner is free to enter any
|
|
// safety contour depth value that he thinks is suitable for the safety of his ship, the
|
|
// SENC only contains a limited choice of depth contours. This symbology procedure
|
|
// determines whether a contour matches the selected safety contour. If the selected
|
|
// safety contour does not exist in the data, the procedure will default to the next deeper
|
|
// contour. The contour selected is highlighted as the safety contour and put in
|
|
// DISPLAYBASE. The procedure also identifies any line segment of the spatial
|
|
// component of the object that has a "QUAPOS" value indicating unreliable
|
|
// positioning, and symbolizes it with a double dashed line.
|
|
//
|
|
// Note: Depth contours are not normally labeled. The ECDIS may provide labels, on demand
|
|
// only as with other text, or provide the depth value on cursor picking
|
|
{
|
|
GString *depcnt02 = NULL;
|
|
int safe = FALSE; // initialy not a safety contour
|
|
GString *objlstr = NULL;
|
|
int objl = 0;
|
|
GString *quaposstr = NULL;
|
|
int quapos = 0;
|
|
double depth_value;
|
|
|
|
objlstr = S57_getAttVal(geo, "OBJL");
|
|
objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
|
|
|
|
if (DEPARE==objl && LINES_T==S57_getObjtype(geo))
|
|
{
|
|
GString *drval1str = S57_getAttVal(geo, "DRVAL1");
|
|
double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
|
|
GString *drval2str = S57_getAttVal(geo, "DRVAL2");
|
|
double drval2 = (NULL == drval2str) ? drval1 : atof(drval2str->str);
|
|
|
|
if (drval1 <= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
|
|
{
|
|
if (drval2 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
|
|
safe = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (1 == S52_state)
|
|
return NULL;
|
|
else
|
|
{
|
|
S57_geo *geoTmp = geo;
|
|
|
|
// get area DEPARE & DRGARE that intersect this line
|
|
while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
|
|
drval1str = S57_getAttVal(geoTmp, "DRVAL1");
|
|
drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
|
|
|
|
if (NULL == drval1str) {
|
|
safe = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
safe = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// debug trace
|
|
//if (safe) PRINTF("** DEPARE: SAFE FOUND**\n");
|
|
}
|
|
}
|
|
|
|
depth_value = drval1;
|
|
|
|
}
|
|
else
|
|
{
|
|
// continuation A (DEPCNT)
|
|
GString *valdcostr = S57_getAttVal(geo, "VALDCO");
|
|
double valdco = (NULL == valdcostr) ? 0.0 : atof(valdcostr->str);
|
|
|
|
depth_value = valdco;
|
|
|
|
if (valdco == S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR))
|
|
safe = TRUE; // this is useless !?!?
|
|
else
|
|
{
|
|
if (valdco > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
if (1 == S52_state)
|
|
return NULL;
|
|
else {
|
|
S57_geo *geoTmp = geo;
|
|
|
|
// get area DEPARE & DRGARE that intersect this line
|
|
while (NULL != (geoTmp = S57_nextObj(geoTmp))){
|
|
GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
|
|
double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
|
|
|
|
if (NULL == drval1str) {
|
|
safe = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (drval1 < S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
safe = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// debug trace
|
|
//if (safe) PRINTF("** DEPCN: SAFE FOUND**\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Continuation B
|
|
quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
if (NULL != quaposstr) {
|
|
quapos = atoi(quaposstr->str);
|
|
if ( 2 <= quapos && quapos < 10) {
|
|
if (safe)
|
|
depcnt02 = g_string_new(";LS(DASH,2,DEPSC)");
|
|
else
|
|
depcnt02 = g_string_new(";LS(DASH,1,DEPCN)");
|
|
}
|
|
} else {
|
|
if (safe)
|
|
depcnt02 = g_string_new(";LS(SOLD,2,DEPSC)");
|
|
else
|
|
depcnt02 = g_string_new(";LS(SOLD,1,DEPCN)");
|
|
}
|
|
|
|
if (safe) {
|
|
S57_setAtt(geo, "SCAMIN", "INFINITE");
|
|
depcnt02 = g_string_prepend(depcnt02, ";OP(8OD13010)");
|
|
} else
|
|
depcnt02 = g_string_prepend(depcnt02, ";OP(---33020)");
|
|
|
|
// facultative in S-52
|
|
//if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
// GString *sndfrm02 = _SNDFRM02(geo, depth_value);
|
|
// depcnt02 = g_string_append(depcnt02, sndfrm02->str);
|
|
// g_string_free(sndfrm02, TRUE);
|
|
//}
|
|
|
|
// debug
|
|
//PRINTF("depth= %f\n", depth_value);
|
|
|
|
S57_unlinkObj(geo);
|
|
|
|
return depcnt02;
|
|
}
|
|
|
|
static double _DEPVAL01(S57_geo *geo, double least_depth)
|
|
// Remarks: S-57 Appendix B1 Annex A requires in Section 6 that areas of rocks be
|
|
// encoded as area obstruction, and that area OBSTRNs and area WRECKS
|
|
// be covered by either group 1 object DEPARE or group 1 object UNSARE.
|
|
// If the value of the attribute VALSOU for an area OBSTRN or WRECKS
|
|
// is missing, the DRVAL1 of an underlying DEPARE is the preferred default
|
|
// for establishing a depth value. This procedure either finds the shallowest
|
|
// DRVAL1 of the one or more underlying DEPAREs, or returns an
|
|
// "unknown"" depth value to the main procedure for the next default
|
|
// procedure.
|
|
|
|
// NOTE: UNSARE test is useless since least_depth is already UNKNOWN
|
|
{
|
|
least_depth = UNKNOWN;
|
|
|
|
|
|
S57_geo *geoTmp = geo;
|
|
|
|
// NOTE: the geo list is unchange (_UDWHAZ03 will unlink geo)
|
|
while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
|
|
GString *objlstr = S57_getAttVal(geoTmp, "OBJL");
|
|
int objl = (NULL == objlstr) ? 0 : atoi(objlstr->str);
|
|
|
|
// get area DEPARE that intersect this area
|
|
if (DEPARE==objl && LINES_T==S57_getObjtype(geo)) {
|
|
GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
|
|
double drval1 = (NULL == drval1str) ? 9.0 : atof(drval1str->str);
|
|
|
|
if (NULL != drval1str) {
|
|
if (UNKNOWN==least_depth || least_depth<drval1)
|
|
least_depth = drval1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return least_depth;
|
|
}
|
|
|
|
static GString *LEGLIN02 (S57_geo *geo)
|
|
|
|
// Remarks: The course of a leg is given by its start and end point. Therefore this
|
|
// conditional symbology procedure calculates the course and shows it
|
|
// alongside the leg. It also places the "distance to run" labels and cares for the
|
|
// different presentation of planned & alternate legs.
|
|
{
|
|
PRINTF("Mariner's object not drawn\n");
|
|
return NULL;
|
|
}
|
|
|
|
static GString *_LITDSN01(S57_geo *geo);
|
|
static GString *LIGHTS05 (S57_geo *geo)
|
|
// Remarks: A light is one of the most complex S-57 objects. Its presentation depends on
|
|
// whether it is a light on a floating or fixed platform, its range, it's colour and
|
|
// so on. This conditional symbology procedure derives the correct
|
|
// presentation from these parameters and also generates an area that shows the
|
|
// coverage of the light.
|
|
//
|
|
// Notes on light sectors:
|
|
// 1.) The radial leg-lines defining the light sectors are normally drawn to only 25mm
|
|
// from the light to avoid clutter (see Part C). However, the mariner should be able to
|
|
// select "full light-sector lines" and have the leg-lines extended to the nominal range
|
|
// of the light (VALMAR).
|
|
//
|
|
// 2.) Part C of this procedure symbolizes the sectors at the light itself. In addition,
|
|
// it should be possible, upon request, for the mariner to be capable of identifying
|
|
// the colour and sector limit lines of the sectors affecting the ship even if the light
|
|
// itself is off the display.
|
|
// [ed. last sentence in bold]
|
|
|
|
// NOTE: why is this relationship not already encoded in S57 (ei. C_AGGR or C_STAC) ?
|
|
|
|
{
|
|
GString *lights05 = NULL;
|
|
GString *valnmrstr = S57_getAttVal(geo, "VALNMR");
|
|
double valnmr = 0.0;
|
|
GString *catlitstr = S57_getAttVal(geo, "CATLIT");
|
|
char catlit[LISTSIZE] = {'\0'};
|
|
int flare_at_45 = FALSE;
|
|
int extend_arc_radius = TRUE;
|
|
GString *sectr1str = NULL;
|
|
GString *sectr2str = NULL;
|
|
double sectr1 = 0.0;
|
|
double sectr2 = 0.0;
|
|
GString *colourstr = NULL;
|
|
char colist[LISTSIZE] = {'\0'}; // colour list
|
|
GString *orientstr = NULL;
|
|
double sweep = 0.0;
|
|
|
|
|
|
lights05 = g_string_new("");
|
|
|
|
valnmr = (NULL == valnmrstr) ? 9.0 : atof(valnmrstr->str);
|
|
|
|
if ( NULL != catlitstr) {
|
|
_parseList(catlitstr->str, catlit);
|
|
|
|
// FIXME: OR vs AND/OR
|
|
if (strpbrk(catlit, "\010\013")) {
|
|
g_string_append(lights05, ";SY(LIGHTS82)");
|
|
return lights05;
|
|
}
|
|
|
|
if (strpbrk(catlit, "\011")) {
|
|
g_string_append(lights05, ";SY(LIGHTS81)");
|
|
return lights05;
|
|
}
|
|
|
|
if (strpbrk(catlit, "\001\020")) {
|
|
orientstr = S57_getAttVal(geo, "ORIENT");
|
|
if (NULL != orientstr) {
|
|
// FIXME: create a geo object (!?) LINE of lenght VALNMR
|
|
// using ORIENT (from seaward) & POINT_T position
|
|
g_string_append(lights05, ";LS(DASH,1,CHBLK)");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Continuation A
|
|
colourstr = S57_getAttVal(geo, "COLOUR");
|
|
if (NULL != colourstr)
|
|
_parseList(colourstr->str, colist);
|
|
else {
|
|
colist[0] = '\014'; // maganta (12)
|
|
colist[1] = '\000';
|
|
}
|
|
|
|
sectr1str = S57_getAttVal(geo, "SECTR1");
|
|
sectr1 = (NULL == sectr1str) ? 0.0 : atof(sectr1str->str);
|
|
sectr2str = S57_getAttVal(geo, "SECTR2");
|
|
sectr2 = (NULL == sectr2str) ? 0.0 : atof(sectr2str->str);
|
|
|
|
if (NULL==sectr1str || NULL==sectr2str) {
|
|
// not a sector light
|
|
char *sym;
|
|
|
|
if (1==S52_state) {
|
|
_setPtPos(geo, LIGHTLIST);
|
|
g_string_free(lights05, TRUE);
|
|
return NULL;
|
|
} else
|
|
flare_at_45 = _atPtPos(geo, LIGHTLIST);
|
|
|
|
sym = _selSYcol(colist);
|
|
|
|
if (strpbrk(catlit, "\001\020")) {
|
|
if (NULL != orientstr){
|
|
g_string_append(lights05, sym);
|
|
g_string_sprintfa(lights05, ",%s)", orientstr->str);
|
|
g_string_append(lights05, ";TE('%03.0lf deg','ORIENT',3,3,3,'15110',3,1,CHBLK,23)" );
|
|
} else
|
|
g_string_append(lights05, ";SY(QUSMRK1)");
|
|
} else {
|
|
g_string_append(lights05, sym);
|
|
if (flare_at_45)
|
|
g_string_append(lights05, ",145)");
|
|
else
|
|
g_string_append(lights05, ",135)");
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
GString *litdsn01 = _LITDSN01(geo);
|
|
if (NULL != litdsn01){
|
|
g_string_append(lights05, ";TX('");
|
|
g_string_append(lights05, litdsn01->str);
|
|
g_string_free(litdsn01, TRUE);
|
|
|
|
if (flare_at_45)
|
|
g_string_append(lights05, "',3,3,3,'15110',2,-1,CHBLK,23)" );
|
|
else
|
|
g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
|
|
}
|
|
}
|
|
|
|
return lights05;
|
|
}
|
|
|
|
// Continuation B --sector light
|
|
if (NULL == sectr1str) {
|
|
sectr1 = 0.0;
|
|
sectr2 = 0.0;
|
|
} else
|
|
sweep = (sectr1 > sectr2) ? sectr2-sectr1+360 : sectr2-sectr1;
|
|
|
|
|
|
if (sweep<1.0 || sweep==360.0) {
|
|
// handle all round light
|
|
char *sym = _selSYcol(colist);;
|
|
|
|
g_string_append(lights05, sym);
|
|
g_string_append(lights05, ",135)");
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SHOW_TEXT)) {
|
|
GString *litdsn01 = _LITDSN01(geo);
|
|
if (NULL != litdsn01) {
|
|
g_string_append(lights05, ";TX('");
|
|
g_string_append(lights05, litdsn01->str);
|
|
g_string_append(lights05, "',3,2,3,'15110',2,0,CHBLK,23)" );
|
|
g_string_free(litdsn01, TRUE);
|
|
}
|
|
|
|
}
|
|
|
|
return lights05;
|
|
}
|
|
|
|
// scan for other lights with sector overlap at this position
|
|
// compute light sector radius acording to other sector
|
|
if (1 == S52_state) {
|
|
_setPtPos(geo, SECTRLIST);
|
|
g_string_free(lights05, TRUE);
|
|
return NULL;
|
|
} else {
|
|
extend_arc_radius = _atPtPos(geo, SECTRLIST);
|
|
|
|
// passe value via attribs to _renderAC
|
|
if (extend_arc_radius)
|
|
// FIXME: draw radius 25 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "Y");
|
|
else
|
|
// FIXME: draw radius 20 mm
|
|
S57_setAtt(geo, "extend_arc_radius", "N");
|
|
}
|
|
|
|
// setup sector
|
|
{
|
|
char litvis[LISTSIZE] = {'\0'}; // list visibility
|
|
GString *litvisstr = S57_getAttVal(geo, "LITVIS");
|
|
|
|
// sector leg --logic is _renderLS()
|
|
g_string_append(lights05, ";LS(DASH,1,CHBLK)");
|
|
|
|
// get light vis.
|
|
if (NULL != litvisstr) _parseList(litvisstr->str, litvis);
|
|
|
|
// faint light
|
|
// FIXME: spec say OR (ie 1 number) the code is AND/OR
|
|
if (strpbrk(litvis, "\003\007\010")) {
|
|
// NOTE: LS(DASH,1,CHBLK)
|
|
// pass flag to _renderAC()
|
|
g_string_append(lights05, ";AC(CHBLK)");
|
|
S57_setAtt(geo, "faint_light", "Y");
|
|
|
|
} else {
|
|
// set arc colour
|
|
char *sym = ";AC(CHMGD)"; // other
|
|
|
|
// max 1 color
|
|
if ('\0' == colist[1]) {
|
|
if (strpbrk(colist, "\003"))
|
|
sym = ";AC(LITRD)";
|
|
else if (strpbrk(colist, "\004"))
|
|
sym = ";AC(LITGN)";
|
|
else if (strpbrk(colist, "\001\006\013"))
|
|
sym = ";AC(LITYW)";
|
|
} else {
|
|
// max 2 color
|
|
if ('\0' == colist[2]) {
|
|
if (strpbrk(colist, "\001") && strpbrk(colist, "\003"))
|
|
sym = ";AC(LITRD)";
|
|
else if (strpbrk(colist, "\001") && strpbrk(colist, "\004"))
|
|
sym = ";AC(LITGN)";
|
|
}
|
|
}
|
|
|
|
g_string_append(lights05, sym);
|
|
}
|
|
}
|
|
|
|
return lights05;
|
|
}
|
|
|
|
static GString *_LITDSN01(S57_geo *geo)
|
|
// Remarks: In S-57 the light characteristics are held as a series of attributes values. The
|
|
// mariner may wish to see a light description text string displayed on the
|
|
// screen similar to the string commonly found on a paper chart. This
|
|
// conditional procedure, reads the attribute values from the above list of
|
|
// attributes and composes a light description string which can be displayed.
|
|
// This procedure is provided as a C function which has as input, the above
|
|
// listed attribute values and as output, the light description.
|
|
{
|
|
GString *litdsn01 = g_string_new("");
|
|
GString *gstr = NULL; // tmp
|
|
|
|
// FIXME: need grammar to create light's text
|
|
|
|
// CATLIT, LITCHR, COLOUR, HEIGHT, LITCHR, SIGGRP, SIGPER, STATUS, VALNMR
|
|
|
|
// CATLIT
|
|
gstr = S57_getAttVal(geo, "CATLIT");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
/*
|
|
1: directional function IP 30.1-3; 475.7;
|
|
2: rear/upper light
|
|
3: front/lower light
|
|
4: leading light IP 20.1-3; 475.6;
|
|
5: aero light IP 60; 476.1;
|
|
6: air obstruction light IP 61; 476.2;
|
|
7: fog detector light IP 62; 477;
|
|
8: flood light IP 63; 478.2;
|
|
9: strip light IP 64; 478.5;
|
|
10: subsidiary light IP 42; 471.8;
|
|
11: spotlight
|
|
12: front
|
|
13: rear
|
|
14: lower
|
|
15: upper
|
|
16: moire' effect IP 31; 475.8;
|
|
17: emergency
|
|
18: bearing light 478.1;
|
|
19: horizontally disposed
|
|
20: vertically disposed
|
|
*/
|
|
|
|
// LITCHR
|
|
gstr = S57_getAttVal(geo, "LITCHR");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
/*
|
|
1: fixed IP 10.1;
|
|
2: flashing IP 10.4;
|
|
3: long-flashing IP 10.5;
|
|
4: quick-flashing IP 10.6;
|
|
5: very quick-flashing IP 10.7;
|
|
6: ultra quick-flashing IP 10.8;
|
|
7: isophased IP 10.3;
|
|
8: occulting IP 10.2;
|
|
9: interrupted quick-flashing IP 10.6;
|
|
10: interrupted very quick-flashing IP 10.7;
|
|
11: interrupted ultra quick-flashing IP 10.8;
|
|
12: morse IP 10.9;
|
|
13: fixed/flash IP 10.10;
|
|
14: flash/long-flash
|
|
15: occulting/flash
|
|
16: fixed/long-flash
|
|
17: occulting alternating
|
|
18: long-flash alternating
|
|
19: flash alternating
|
|
20: group alternating
|
|
21: 2 fixed (vertical)
|
|
22: 2 fixed (horizontal)
|
|
23: 3 fixed (vertical)
|
|
24: 3 fixed (horizontal)
|
|
25: quick-flash plus long-flash
|
|
26: very quick-flash plus long-flash
|
|
27: ultra quick-flash plus long-flash
|
|
28: alternating
|
|
29: fixed and alternating flashing
|
|
*/
|
|
|
|
// COLOUR,
|
|
gstr = S57_getAttVal(geo, "COLOUR");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
/*
|
|
1: white IP 11.1; 450.2-3;
|
|
2: black
|
|
3: red IP 11.2; 450.2-3;
|
|
4: green IP 11.3; 450.2-3;
|
|
5: blue IP 11.4; 450.2-3;
|
|
6: yellow IP 11.6; 450.2-3;
|
|
7: grey
|
|
8: brown
|
|
9: amber IP 11.8; 450.2-3;
|
|
10: violet IP 11.5; 450.2-3;
|
|
11: orange IP 11.7; 450.2-3;
|
|
12: magenta
|
|
13: pink
|
|
*/
|
|
|
|
// HEIGHT, xxx.x
|
|
gstr = S57_getAttVal(geo, "HEIGHT");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
|
|
// SIGGRP, (c)(c) ...
|
|
gstr = S57_getAttVal(geo, "SIGGRP");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
|
|
// SIGPER, xx.xx
|
|
gstr = S57_getAttVal(geo, "SIGPER");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
|
|
// STATUS,
|
|
gstr = S57_getAttVal(geo, "STATUS");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
/*
|
|
1: permanent
|
|
2: occasional IP 50; 473.2;
|
|
3: recommended IN 10; 431.1;
|
|
4: not in use IL 14, 44; 444.7;
|
|
5: periodic/intermittent IC 21; IQ 71; 353.3; 460.5;
|
|
6: reserved IN 12.9;
|
|
7: temporary IP 54;
|
|
8: private IQ 70;
|
|
9: mandatory
|
|
10: destroyed/ruined
|
|
11: extinguished
|
|
12: illuminated
|
|
13: historic
|
|
14: public
|
|
15: synchronized
|
|
16: watched
|
|
17: un-watched
|
|
18: existence doubtful
|
|
*/
|
|
|
|
// VALNMR, xx.x
|
|
gstr = S57_getAttVal(geo, "VALNMR");
|
|
if (NULL != gstr)
|
|
g_string_append(litdsn01, gstr->str);
|
|
|
|
|
|
PRINTF("FIXME: lights description not translated into text\n");
|
|
|
|
return litdsn01;
|
|
}
|
|
|
|
static GString *_UDWHAZ03(S57_geo *geo, double depth_value);
|
|
static GString *_QUAPNT01(S57_geo *geo);
|
|
|
|
static GString *OBSTRN04 (S57_geo *geo)
|
|
// Remarks: Obstructions or isolated underwater dangers of depths less than the safety
|
|
// contour which lie within the safe waters defined by the safety contour are
|
|
// to be presented by a specific isolated danger symbol and put in IMO
|
|
// category DISPLAYBASE (see (3), App.2, 1.3). This task is performed
|
|
// by the sub-procedure "UDWHAZ03" which is called by this symbology
|
|
// procedure. Objects of the class "under water rock" are handled by this
|
|
// routine as well to ensure a consistent symbolization of isolated dangers on
|
|
// the seabed.
|
|
{
|
|
GString *obstrn04str = g_string_new("");
|
|
GString *sndfrm02str = NULL;
|
|
GString *udwhaz03str = NULL;
|
|
GString *valsoustr = S57_getAttVal(geo, "VALSOU");
|
|
double valsou = UNKNOWN;
|
|
double depth_value = UNKNOWN;
|
|
double least_depth = UNKNOWN;
|
|
|
|
// exit if not in drawing state
|
|
if (1 == S52_state)
|
|
return NULL;
|
|
|
|
if (NULL != valsoustr) {
|
|
valsou = atof(valsoustr->str);
|
|
depth_value = valsou;
|
|
sndfrm02str = _SNDFRM02(geo, depth_value);
|
|
} else {
|
|
if (AREAS_T == S57_getObjtype(geo))
|
|
least_depth = _DEPVAL01(geo, least_depth);
|
|
|
|
if (UNKNOWN != least_depth) {
|
|
GString *catobsstr = S57_getAttVal(geo, "CATOBS");
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL != catobsstr && '6' == *catobsstr->str)
|
|
depth_value = 0.01;
|
|
else
|
|
if (NULL == watlevstr) // default
|
|
depth_value = -15.0;
|
|
else {
|
|
switch (*watlevstr->str){
|
|
case '5': depth_value = 0.0 ; break;
|
|
case '3': depth_value = 0.01; break;
|
|
case '4':
|
|
case '1':
|
|
case '2':
|
|
default : depth_value = -15.0 ; break;
|
|
}
|
|
}
|
|
} else
|
|
depth_value = least_depth;
|
|
}
|
|
|
|
udwhaz03str = _UDWHAZ03(geo, depth_value);
|
|
|
|
if (POINT_T == S57_getObjtype(geo)) {
|
|
// Continuation A
|
|
int sounding = FALSE;
|
|
GString *quapnt01str = _QUAPNT01(geo);
|
|
|
|
if (NULL != udwhaz03str){
|
|
g_string_append(obstrn04str, udwhaz03str->str);
|
|
if (NULL != quapnt01str)
|
|
g_string_append(obstrn04str, quapnt01str->str);
|
|
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
|
|
|
|
return obstrn04str;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20.0) {
|
|
GString *objlstr = S57_getAttVal(geo, "OBJL");
|
|
int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (UWTROC == objl) {
|
|
if (NULL == watlevstr) { // default
|
|
g_string_append(obstrn04str, ";SY(DANGER01)");
|
|
sounding = TRUE;
|
|
} else {
|
|
switch (*watlevstr->str){
|
|
case '3': g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE ; break;
|
|
case '4':
|
|
case '5': g_string_append(obstrn04str, ";SY(UWTROC04)"); sounding = FALSE; break;
|
|
default : g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE ; break;
|
|
}
|
|
}
|
|
} else { // OBSTRN
|
|
if (NULL == watlevstr) { // default
|
|
g_string_append(obstrn04str, ";SY(DANGER01)");
|
|
sounding = TRUE;
|
|
} else {
|
|
switch (*watlevstr->str) {
|
|
case '1':
|
|
case '2': g_string_append(obstrn04str, ";SY(OBSTRN11)"); sounding = FALSE; break;
|
|
case '3': g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE; break;
|
|
case '4':
|
|
case '5': g_string_append(obstrn04str, ";SY(DANGER03)"); sounding = TRUE; break;
|
|
default : g_string_append(obstrn04str, ";SY(DANGER01)"); sounding = TRUE; break;
|
|
}
|
|
}
|
|
}
|
|
} else { // valsou > 20.0
|
|
g_string_append(obstrn04str, ";SY(DANGER02)");
|
|
sounding = FALSE;
|
|
}
|
|
|
|
} else { // NO valsou
|
|
GString *objlstr = S57_getAttVal(geo, "OBJL");
|
|
int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (UWTROC == objl) {
|
|
if (NULL == watlevstr) // default
|
|
g_string_append(obstrn04str, ";SY(UWTROC04)");
|
|
else {
|
|
if ('3' == *watlevstr->str)
|
|
g_string_append(obstrn04str, ";SY(UWTROC03)");
|
|
else
|
|
g_string_append(obstrn04str, ";SY(UWTROC04)");
|
|
}
|
|
|
|
} else { // OBSTRN
|
|
if ( NULL == watlevstr) // default
|
|
g_string_append(obstrn04str, ";SY(OBSTRN01)");
|
|
else {
|
|
switch (*watlevstr->str) {
|
|
case '1':
|
|
case '2': g_string_append(obstrn04str, ";SY(OBSTRN11)"); break;
|
|
case '3': g_string_append(obstrn04str, ";SY(OBSTRN01)"); break;
|
|
case '4':
|
|
case '5':
|
|
default : g_string_append(obstrn04str, ";SY(OBSTRN01)"); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (sounding && NULL != sndfrm02str)
|
|
g_string_append(obstrn04str, sndfrm02str->str);
|
|
|
|
if (NULL != quapnt01str)
|
|
g_string_append(obstrn04str, quapnt01str->str);
|
|
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
|
|
|
|
return obstrn04str;
|
|
|
|
} else {
|
|
if (LINES_T == S57_getObjtype(geo)) {
|
|
// Continuation B
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = 0;
|
|
|
|
if (NULL != quaposstr) {
|
|
quapos = atoi(quaposstr->str);
|
|
if ( 2 <= quapos && quapos < 10){
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(obstrn04str, ";LC(LOWACC41)");
|
|
else
|
|
g_string_append(obstrn04str, ";LC(LOWACC31)");
|
|
}
|
|
}
|
|
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
|
|
|
|
if (UNKNOWN != valsou)
|
|
if (valsou <= 20.0)
|
|
g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
|
|
else
|
|
g_string_append(obstrn04str, ";LS(DASH,2,CHBLK)");
|
|
else
|
|
g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
|
|
|
|
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(obstrn04str, udwhaz03str->str);
|
|
else {
|
|
if (UNKNOWN != valsou)
|
|
if (valsou <= 20.0)
|
|
g_string_append(obstrn04str, sndfrm02str->str);
|
|
}
|
|
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
|
|
return obstrn04str;
|
|
|
|
} else {
|
|
// Continuation C (AREAS_T)
|
|
GString *quapnt01str = _QUAPNT01(geo);
|
|
if (NULL != udwhaz03str) {
|
|
g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01)");
|
|
g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
|
|
g_string_append(obstrn04str, udwhaz03str->str);
|
|
if (NULL != quapnt01str)
|
|
g_string_append(obstrn04str, quapnt01str->str);
|
|
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
|
|
|
|
return obstrn04str;
|
|
}
|
|
|
|
if (UNKNOWN != valsou) {
|
|
// BUG in CA49995B.000 if we get here because there is no color
|
|
// beside NODATA (ie there is a hole in group 1 area!)
|
|
//g_string_append(obstrn04, ";AC(UINFR)");
|
|
|
|
if (valsou <= 20.0)
|
|
g_string_append(obstrn04str, ";LS(DOTT,2,CHBLK)");
|
|
else
|
|
g_string_append(obstrn04str, ";LS(DASH,2,CHBLK)");
|
|
|
|
g_string_append(obstrn04str, sndfrm02str->str);
|
|
|
|
} else {
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL == watlevstr) // default
|
|
g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)");
|
|
else {
|
|
if ('3' == *watlevstr->str) {
|
|
GString *catobsstr = S57_getAttVal(geo, "CATOBS");
|
|
if (NULL != catobsstr && '6' == *catobsstr->str)
|
|
g_string_append(obstrn04str, ";AC(DEPVS);AP(FOULAR01);LS(DOTT,2,CHBLK)");
|
|
} else {
|
|
switch (*watlevstr->str) {
|
|
case '1':
|
|
case '2': g_string_append(obstrn04str, ";AC(CHBRN);LS(SOLD,2,CSTLN)"); break;
|
|
case '4': g_string_append(obstrn04str, ";AC(DEPIT);LS(DASH,2,CSTLN)"); break;
|
|
case '5':
|
|
case '3':
|
|
default : g_string_append(obstrn04str, ";AC(DEPVS);LS(DOTT,2,CHBLK)"); break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_string_append(obstrn04str, quapnt01str->str);
|
|
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
|
|
|
|
|
|
return obstrn04str;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// check if one exit point could do!!!
|
|
return NULL;
|
|
}
|
|
|
|
static GString *OWNSHP02 (S57_geo *geo)
|
|
// Remarks:
|
|
// 1. CONNING POSITION
|
|
// 1.1 When own-ship is drawn to scale, the conning position must be correctly located in
|
|
// relation to the ship's outline. The conning position then serves as the pivot point for
|
|
// the own-ship symbol, to be located by the ECDIS at the correct latitude, longitude
|
|
// for the conning point, as computed from the positioning system, correcting for
|
|
// antenna offset.
|
|
// 1.2 In this procedure it is assumed that the heading line, beam bearing line and course
|
|
// and speed vector originate at the conning point. If another point of origin is used,
|
|
// for example to account for the varying position of the ships turning centre, this must
|
|
// be made clear to the mariner.
|
|
//
|
|
// 2. DISPLAY OPTIONS
|
|
// 2.1 Only the ship symbol is mandatory for an ECDIS. The mariner should be prompted
|
|
// to select from the following additional optional features:
|
|
// - display own-ship as:
|
|
// 1. symbol, or
|
|
// 2. scaled outline
|
|
// - select time period determining vector length for own-ship and other vessel course and speed
|
|
// vectors, (all vectors must be for the same time period),
|
|
// - display own-ship vector,
|
|
// - select ground or water stabilization for all vectors, and select whether to display the type of
|
|
// stabilization, (by arrowhead),
|
|
// - select one-minute or six-minute vector time marks,
|
|
// - select whether to show a heading line, to the edge of the display window,
|
|
// - select whether to show a beam bearing line, and if so what length (default: 10mm total
|
|
// length).
|
|
{
|
|
PRINTF("Mariner's object not drawn\n");
|
|
return NULL;
|
|
}
|
|
|
|
static GString *PASTRK01 (S57_geo *geo)
|
|
// Remarks: This conditional symbology procedure was designed to allow the mariner
|
|
// to select time labels at the pasttrack (see (3) 10.5.11.1). The procedure also
|
|
// cares for the presentation of primary and secondary pasttrack.
|
|
//
|
|
// The manufacturer should define his own data class (spatial primitive) in xyt
|
|
// (position and time) in order to represent Pastrk.
|
|
{
|
|
|
|
PRINTF("Mariner's object not drawn\n");
|
|
return NULL;
|
|
}
|
|
|
|
static GString *_QUALIN01(S57_geo *geo);
|
|
static GString *QUAPOS01 (S57_geo *geo)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
|
|
// to the spatial object, not the feature object.
|
|
//
|
|
// This procedure passes the object to procedure QUALIN01 or QUAPNT01,
|
|
// which traces back to the spatial object, retrieves any QUAPOS attributes,
|
|
// and returns the appropriate symbolization to QUAPOS01.
|
|
{
|
|
GString *quapos01 = NULL;
|
|
|
|
if (LINES_T == S57_getObjtype(geo))
|
|
quapos01 = _QUALIN01(geo);
|
|
else
|
|
quapos01 = _QUAPNT01(geo);
|
|
|
|
return quapos01;
|
|
}
|
|
|
|
static GString *_QUALIN01(S57_geo *geo)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
|
|
// only to the spatial component(s) of an object.
|
|
//
|
|
// A line object may be composed of more than one spatial object.
|
|
//
|
|
// This procedure looks at each of the spatial
|
|
// objects, and symbolizes the line according to the positional accuracy.
|
|
{
|
|
GString *qualino1 = NULL;
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = 0;
|
|
char *line = NULL;
|
|
|
|
if (NULL != quaposstr) {
|
|
quapos = atoi(quaposstr->str);
|
|
if ( 2 <= quapos && quapos < 10)
|
|
line = ";LC(LOWACC21)";
|
|
} else {
|
|
GString *objlstr = S57_getAttVal(geo, "OBJL");
|
|
int objl = (NULL == objlstr)? 0 : atoi(objlstr->str);
|
|
|
|
if (COALNE == objl) {
|
|
GString *conradstr = S57_getAttVal(geo, "CONRAD");
|
|
|
|
if (NULL != conradstr) {
|
|
if ('1' == *conradstr->str)
|
|
line = ";LS(SOLD,3,CHMGF);LS(SOLD,1,CSTLN)";
|
|
else
|
|
line = ";LS(SOLD,1,CSTLN)";
|
|
} else
|
|
line = ";LS(SOLD,1,CSTLN)";
|
|
|
|
} else //LNDARE
|
|
line = ";LS(SOLD,1,CSTLN)";
|
|
}
|
|
|
|
if (NULL != line)
|
|
qualino1 = g_string_new(line);
|
|
|
|
return qualino1;
|
|
}
|
|
|
|
static GString *_QUAPNT01(S57_geo *geo)
|
|
// Remarks: The attribute QUAPOS, which identifies low positional accuracy, is attached
|
|
// only to the spatial component(s) of an object.
|
|
//
|
|
// This procedure retrieves any QUAPOS attributes, and returns the
|
|
// appropriate symbols to the calling procedure.
|
|
{
|
|
GString *quapnt01 = NULL;
|
|
int accurate = TRUE;
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
|
|
|
|
if (NULL != quaposstr) {
|
|
if ( 2 <= quapos && quapos < 10)
|
|
accurate = FALSE;
|
|
}
|
|
|
|
if (accurate)
|
|
quapnt01 = g_string_new(";SY(LOWACC01)");
|
|
|
|
return quapnt01;
|
|
}
|
|
|
|
static GString *SLCONS03 (S57_geo *geo)
|
|
// Remarks: Shoreline construction objects which have a QUAPOS attribute on their
|
|
// spatial component indicating that their position is unreliable are symbolized
|
|
// by a special linestyle in the place of the varied linestyles normally used.
|
|
// Otherwise this procedure applies the normal symbolization.
|
|
{
|
|
GString *slcons03 = NULL;
|
|
GString *valstr = NULL;
|
|
char *cmdw = NULL; // command word
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
|
|
|
|
if (POINT_T == S57_getObjtype(geo)) {
|
|
if (NULL != quaposstr) {
|
|
if (2 <= quapos && quapos < 10)
|
|
cmdw =";SY(LOWACC01)";
|
|
}
|
|
} else {
|
|
// LINE_T and AREA_T are the same
|
|
if (NULL != quaposstr) {
|
|
if (2 <= quapos && quapos < 10)
|
|
cmdw =";LC(LOWACC01)";
|
|
} else {
|
|
valstr = S57_getAttVal(geo, "CONDTN");
|
|
|
|
if (NULL != valstr && ( '1' == *valstr->str || '2' == *valstr->str))
|
|
cmdw = ";LS(DASH,1,CSTLN)";
|
|
else {
|
|
int val = 0;
|
|
valstr = S57_getAttVal(geo, "CATSLC");
|
|
val = (NULL == valstr)? 0 : atoi(valstr->str);
|
|
|
|
if (NULL != valstr && ( 6 == val || 15 == val || 16 == val ))
|
|
cmdw = ";LS(SOLD,4,CSTLN)";
|
|
else {
|
|
valstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL != valstr && '2' == *valstr->str)
|
|
cmdw = ";LS(SOLD,2,CSTLN)";
|
|
else
|
|
if (NULL != valstr && ('3' == *valstr->str || '4' == *valstr->str))
|
|
cmdw = ";LS(DASH,2,CSTLN)";
|
|
else
|
|
cmdw = ";LS(SOLD,2,CSTLN)"; // default
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// WARNING: not explicitly specified in S-52 !!
|
|
// FIXME:this is to put AC(DEPIT) --intertidal area
|
|
// Could this be bug in OGR ?
|
|
/*
|
|
if (AREAS_T == S57_getObjtype(geo)) {
|
|
GString *seabed01 = NULL;
|
|
GString *drval1str = S57_getAttVal(geo, "DRVAL1");
|
|
double drval1 = (NULL == drval1str)? -UNKNOWN : atof(drval1str->str);
|
|
GString *drval2str = S57_getAttVal(geo, "DRVAL2");
|
|
double drval2 = (NULL == drval2str)? -UNKNOWN : atof(drval2str->str);
|
|
// NOTE: change sign of infinity (minus) to get out of bound in seabed01
|
|
|
|
|
|
PRINTF("***********drval1=%f drval2=%f \n", drval1, drval2);
|
|
seabed01 = _SEABED01(drval1, drval2);
|
|
slcons03 = g_string_new(seabed01->str);
|
|
g_string_free(seabed01, TRUE);
|
|
|
|
}
|
|
*/
|
|
|
|
if (NULL != cmdw) {
|
|
if (NULL == slcons03)
|
|
slcons03 = g_string_new(cmdw);
|
|
else
|
|
g_string_append(slcons03, cmdw);
|
|
}
|
|
|
|
return slcons03;
|
|
}
|
|
|
|
static GString *RESARE02 (S57_geo *geo)
|
|
// Remarks: A list-type attribute is used because an area of the object class RESARE may
|
|
// have more than one category (CATREA). For example an inshore traffic
|
|
// zone might also have fishing and anchoring prohibition and a prohibited
|
|
// area might also be a bird sanctuary or a mine field.
|
|
//
|
|
// This conditional procedure is set up to ensure that the categories of most
|
|
// importance to safe navigation are prominently symbolized, and to pass on
|
|
// all given information with minimum clutter. Only the most significant
|
|
// restriction is symbolized, and an indication of further limitations is given by
|
|
// a subscript "!" or "I". Further details are given under conditional
|
|
// symbology procedure RESTRN01
|
|
//
|
|
// Other object classes affected by attribute RESTRN are handled by
|
|
// conditional symbology procedure RESTRN01.
|
|
{
|
|
GString *resare02 = g_string_new("");
|
|
GString *restrnstr = S57_getAttVal(geo, "RESTRN");
|
|
char restrn[LISTSIZE] = {'\0'};
|
|
GString *catreastr = S57_getAttVal(geo, "CATREA");
|
|
char catrea[LISTSIZE] = {'\0'};
|
|
char *symb = NULL;
|
|
char *line = NULL;
|
|
char *prio = NULL;
|
|
|
|
if ( NULL != restrnstr) {
|
|
_parseList(restrnstr->str, restrn);
|
|
|
|
if (NULL != catreastr) _parseList(catreastr->str, catrea);
|
|
|
|
if (strpbrk(restrn, "\007\010\016")) {
|
|
// Continuation A
|
|
if (strpbrk(restrn, "\001\002\003\004\005\006"))
|
|
symb = ";SY(ENTRES61)";
|
|
else {
|
|
if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = ";SY(ENTRES61)";
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(ENTRES71)";
|
|
else {
|
|
if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = ";SY(ENTRES71)";
|
|
else
|
|
symb = ";SY(ENTRES51)";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = ";LC(CTYARE51)";
|
|
else
|
|
line = ";LS(DASH,2,CHMGD)";
|
|
|
|
prio = ";OP(6---)"; // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\001\002")) {
|
|
// Continuation B
|
|
if (strpbrk(restrn, "\003\004\005\006"))
|
|
symb = ";SY(ACHRES61)";
|
|
else {
|
|
if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = ";SY(ACHRES61)";
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(ACHRES71)";
|
|
else {
|
|
if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = ";SY(ACHRES71)";
|
|
else
|
|
symb = ";SY(ACHRES51)";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = ";LC(ACHRE51)";
|
|
else
|
|
line = ";LS(DASH,2,CHMGD)";
|
|
|
|
prio = ";OP(6---)"; // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\003\004\005\006")) {
|
|
// Continuation C
|
|
if (NULL != catreastr && strpbrk(catrea, "\001\010\011\014\016\023\025\031"))
|
|
symb = ";SY(FSHRES51)";
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(FSHRES71)";
|
|
else{
|
|
if (NULL != catreastr && strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = ";SY(FSHRES71)";
|
|
else
|
|
symb = ";SY(FSHRES51)";
|
|
}
|
|
}
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = ";LC(FSHRES51)";
|
|
else
|
|
line = ";LS(DASH,2,CHMGD)";
|
|
|
|
prio = ";OP(6---)"; // display prio set to 6
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(INFARE51)";
|
|
else
|
|
symb = ";SY(RSRDEF51)";
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = ";LC(CTYARE51)";
|
|
else
|
|
line = ";LS(DASH,2,CHMGD)";
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Continuation D
|
|
if (NULL != catreastr) {
|
|
if (strpbrk(catrea, "\001\010\011\014\016\023\025\031")) {
|
|
if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = ";SY(CTYARE71)";
|
|
else
|
|
symb = ";SY(CTYARE51)";
|
|
} else {
|
|
if (strpbrk(catrea, "\004\005\006\007\012\022\024\026\027\030"))
|
|
symb = ";SY(INFARE71)";
|
|
else
|
|
symb = ";SY(RSRDEF51)";
|
|
}
|
|
} else
|
|
symb = ";SY(RSRDEF51)";
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_SYMBOLIZED_BND))
|
|
line = ";LC(CTYARE51)";
|
|
else
|
|
line = ";LS(DASH,2,CHMGD)";
|
|
}
|
|
|
|
// create command word
|
|
if (NULL != prio)
|
|
g_string_append(resare02, prio);
|
|
g_string_append(resare02, line);
|
|
g_string_append(resare02, symb);
|
|
|
|
return resare02;
|
|
}
|
|
|
|
static GString *RESTRN01 (S57_geo *geo)
|
|
// Remarks: Objects subject to RESTRN01 are actually symbolised in sub-process
|
|
// RESCSP01, since the latter can also be accessed from other conditional
|
|
// symbology procedures. RESTRN01 merely acts as a "signpost" for
|
|
// RESCSP01.
|
|
//
|
|
// Object class RESARE is symbolised for the effect of attribute RESTRN in a separate
|
|
// conditional symbology procedure called RESARE02.
|
|
//
|
|
// Since many of the areas concerned cover shipping channels, the number of symbols used
|
|
// is minimised to reduce clutter. To do this, values of RESTRN are ranked for significance
|
|
// as follows:
|
|
// "Traffic Restriction" values of RESTRN:
|
|
// (1) RESTRN 7,8: entry prohibited or restricted
|
|
// RESTRN 14: IMO designated "area to be avoided" part of a TSS
|
|
// (2) RESTRN 1,2: anchoring prohibited or restricted
|
|
// (3) RESTRN 3,4,5,6: fishing or trawling prohibited or restricted
|
|
// (4) "Other Restriction" values of RESTRN are:
|
|
// RESTRN 9, 10: dredging prohibited or restricted,
|
|
// RESTRN 11,12: diving prohibited or restricted,
|
|
// RESTRN 13 : no wake area.
|
|
{
|
|
GString *restrn01str = S57_getAttVal(geo, "RESTRN");
|
|
GString *restrn01 = NULL;
|
|
|
|
if (NULL != restrn01str)
|
|
restrn01 = _RESCSP01(geo);
|
|
else
|
|
restrn01 = g_string_new(";OP(----)"); // return NOOP to silence error msg
|
|
|
|
return restrn01;
|
|
}
|
|
|
|
static GString *_RESCSP01(S57_geo *geo)
|
|
// Remarks: See procedure RESTRN01
|
|
{
|
|
GString *rescsp01 = NULL;
|
|
GString *restrnstr = S57_getAttVal(geo, "RESTRN");
|
|
char restrn[LISTSIZE] = {'\0'}; // restriction list
|
|
char *symb = NULL;
|
|
|
|
if ( NULL != restrnstr) {
|
|
_parseList(restrnstr->str, restrn);
|
|
|
|
if (strpbrk(restrn, "\007\010\016")) {
|
|
// continuation A
|
|
if (strpbrk(restrn, "\001\002\003\004\005\006"))
|
|
symb = ";SY(ENTRES61)";
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(ENTRES71)";
|
|
else
|
|
symb = ";SY(ENTRES51)";
|
|
|
|
}
|
|
} else {
|
|
if (strpbrk(restrn, "\001\002")) {
|
|
// continuation B
|
|
if (strpbrk(restrn, "\003\004\005\006"))
|
|
symb = ";SY(ACHRES61)";
|
|
else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(ACHRES71)";
|
|
else
|
|
symb = ";SY(ACHRES51)";
|
|
}
|
|
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\003\004\005\006")) {
|
|
// continuation C
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(FSHRES71)";
|
|
else
|
|
symb = ";SY(FSHRES51)";
|
|
|
|
|
|
} else {
|
|
if (strpbrk(restrn, "\011\012\013\014\015"))
|
|
symb = ";SY(INFARE51)";
|
|
else
|
|
symb = ";SY(RSRDEF51)";
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
rescsp01 = g_string_new(symb);
|
|
}
|
|
|
|
return rescsp01;
|
|
}
|
|
|
|
static GString *_SEABED01(double drval1, double drval2)
|
|
// Remarks: An area object that is part of the seabed is coloured as necessary according
|
|
// to the mariners selection of two shades, (shallow contour, safety contour,
|
|
// deep contour), or four shades (safety contour only). This requires a decision
|
|
// making process provided by this conditional symbology procedure. Note
|
|
// that this procedure is called as a sub-procedure by other conditional
|
|
// symbology procedures.
|
|
//
|
|
// Note: The requirement to show four depth shades is not mandatory. Also,
|
|
// the requirement to show the shallow pattern is not mandatory. However,
|
|
// both these features are strongly recommended.
|
|
|
|
// return: is never NULL
|
|
|
|
{
|
|
GString *seabed01 = NULL;
|
|
gboolean shallow = TRUE;
|
|
char *arecol = ";AC(DEPIT)";
|
|
|
|
if (drval1 >= 0.0 && drval2 > 0.0)
|
|
arecol = ";AC(DEPVS)";
|
|
|
|
if (TRUE == S52_getMarinerParam(S52_MAR_TWO_SHADES)){
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
arecol = ";AC(DEPDW)";
|
|
shallow = FALSE;
|
|
}
|
|
} else {
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR))
|
|
arecol = ";AC(DEPMS)";
|
|
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR)) {
|
|
arecol = ";AC(DEPMD)";
|
|
shallow = FALSE;
|
|
}
|
|
|
|
if (drval1 >= S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) &&
|
|
drval2 > S52_getMarinerParam(S52_MAR_DEEP_CONTOUR)) {
|
|
arecol = ";AC(DEPDW)";
|
|
shallow = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
seabed01 = g_string_new(arecol);
|
|
|
|
if (TRUE==S52_getMarinerParam(S52_MAR_SHALLOW_PATTERN) && TRUE==shallow)
|
|
g_string_append(seabed01, ";AP(DIAMOND1)");
|
|
|
|
return seabed01;
|
|
}
|
|
|
|
static GString *SOUNDG02 (S57_geo *geo)
|
|
// Remarks: In S-57 soundings are elements of sounding arrays rather than individual
|
|
// objects. Thus this conditional symbology procedure examines each
|
|
// sounding of a sounding array one by one. To symbolize the depth values it
|
|
// calls the procedure SNDFRM02 which in turn translates the depth values
|
|
// into a set of symbols to be shown at the soundings position.
|
|
{
|
|
guint npt = 0;
|
|
double *ppt = NULL;
|
|
|
|
if (POINT_T != S57_getObjtype(geo)) {
|
|
PRINTF("invalid object type (not M_PNT_T)\n");
|
|
//return NULL;
|
|
exit(0);
|
|
}
|
|
|
|
S57_getGeoData(geo, 0, &npt, &ppt);
|
|
|
|
return _SNDFRM02(geo, ppt[2]);
|
|
}
|
|
|
|
static GString *_SNDFRM02(S57_geo *geo, double depth_value)
|
|
// Remarks: Soundings differ from plain text because they have to be readable under all
|
|
// circumstances and their digits are placed according to special rules. This
|
|
// conditional symbology procedure accesses a set of carefully designed
|
|
// sounding symbols provided by the symbol library and composes them to
|
|
// sounding labels. It symbolizes swept depth and it also symbolizes for low
|
|
// reliability as indicated by attributes QUASOU and QUAPOS.
|
|
{
|
|
GString *sndfrm02 = g_string_new("");
|
|
char *symbol_prefix = NULL;
|
|
GString *tecsoustr = S57_getAttVal(geo, "TECSOU");
|
|
char tecsou[LISTSIZE] = {'\0'};
|
|
GString *quasoustr = S57_getAttVal(geo, "QUASOU");
|
|
char quasou[LISTSIZE] = {'\0'};
|
|
GString *statusstr = S57_getAttVal(geo, "STATUS");
|
|
char status[LISTSIZE] = {'\0'};
|
|
double leading_digit = 0.0;
|
|
|
|
// FIXME: test to fix the rounding error (!?)
|
|
depth_value += (depth_value > 0.0)? 0.01: -0.01;
|
|
leading_digit = (int) depth_value;
|
|
|
|
if (depth_value <= S52_getMarinerParam(S52_MAR_SAFETY_DEPTH))
|
|
symbol_prefix = "SOUNDS";
|
|
else
|
|
symbol_prefix = "SOUNDG";
|
|
|
|
if (NULL != tecsoustr) {
|
|
_parseList(tecsoustr->str, tecsou);
|
|
if (strpbrk(tecsou, "\006"))
|
|
g_string_sprintfa(sndfrm02, ";SY(%sB1)", symbol_prefix);
|
|
}
|
|
|
|
if (NULL != quasoustr) _parseList(quasoustr->str, quasou);
|
|
if (NULL != statusstr) _parseList(statusstr->str, status);
|
|
|
|
if (strpbrk(quasou, "\003\004\005\010\011") || strpbrk(status, "\022"))
|
|
g_string_sprintfa(sndfrm02, ";SY(%sC2)", symbol_prefix);
|
|
else {
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
|
|
|
|
if (NULL != quaposstr) {
|
|
if (2 <= quapos && quapos < 10)
|
|
g_string_sprintfa(sndfrm02, ";SY(%sC2)", symbol_prefix);
|
|
}
|
|
}
|
|
|
|
// Continuation A
|
|
if (depth_value < 10.0) {
|
|
// can be above water (negative)
|
|
int fraction = (int)ABS((depth_value - leading_digit)*10);
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)ABS(leading_digit));
|
|
g_string_sprintfa(sndfrm02, ";SY(%s5%1i)", symbol_prefix, fraction);
|
|
|
|
// above sea level (negative)
|
|
if (depth_value < 0.0)
|
|
g_string_sprintfa(sndfrm02, ";SY(%sA1)", symbol_prefix);
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
if (depth_value < 31.0) {
|
|
double fraction = depth_value - leading_digit;
|
|
|
|
if (fraction != 0.0) {
|
|
fraction = fraction * 10;
|
|
if (leading_digit >= 10.0)
|
|
g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)leading_digit/10);
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)leading_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s5%1i)", symbol_prefix, (int)fraction);
|
|
|
|
return sndfrm02;
|
|
}
|
|
}
|
|
|
|
// Continuation B
|
|
depth_value = leading_digit; // truncate to integer
|
|
if (depth_value < 100.0) {
|
|
double first_digit = leading_digit / 10;
|
|
double secnd_digit = leading_digit - (first_digit * 10);
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)first_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)secnd_digit);
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
if (depth_value < 1000.0) {
|
|
double first_digit = leading_digit / 100;
|
|
double secnd_digit = leading_digit - (first_digit * 100);
|
|
double third_digit = leading_digit - (first_digit * 100) - (secnd_digit * 10);
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)first_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)secnd_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)third_digit);
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
if (depth_value < 10000.0) {
|
|
double first_digit = leading_digit / 1000;
|
|
double secnd_digit = leading_digit - (first_digit * 1000);
|
|
double third_digit = leading_digit - (first_digit * 1000) - (secnd_digit * 100);
|
|
double last_digit = leading_digit - (first_digit * 1000) - (secnd_digit * 100) - (third_digit * 100) ;
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)first_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)secnd_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)third_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s4%1i)", symbol_prefix, (int)last_digit);
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
// Continuation C
|
|
{
|
|
double first_digit = leading_digit / 10000;
|
|
double secnd_digit = leading_digit - (first_digit * 10000);
|
|
double third_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000);
|
|
double fourth_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100) ;
|
|
double last_digit = leading_digit - (first_digit * 10000) - (secnd_digit * 1000) - (third_digit * 100) - (fourth_digit * 10) ;
|
|
|
|
g_string_sprintfa(sndfrm02, ";SY(%s3%1i)", symbol_prefix, (int)first_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s2%1i)", symbol_prefix, (int)secnd_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s1%1i)", symbol_prefix, (int)third_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s0%1i)", symbol_prefix, (int)fourth_digit);
|
|
g_string_sprintfa(sndfrm02, ";SY(%s4%1i)", symbol_prefix, (int)last_digit);
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
return sndfrm02;
|
|
}
|
|
|
|
static GString *TOPMAR01 (S57_geo *geo)
|
|
// Remarks: Topmark objects are to be symbolized through consideration of their
|
|
// platforms e.g. a buoy. Therefore this conditional symbology procedure
|
|
// searches for platforms by looking for other objects that are located at the
|
|
// same position.. Based on the finding whether the platform is rigid or
|
|
// floating, the respective upright or sloping symbol is selected and presented
|
|
// at the objects location. Buoy symbols and topmark symbols have been
|
|
// carefully designed to fit to each other when combined at the same position.
|
|
// The result is a composed symbol that looks like the traditional symbols the
|
|
// mariner is used to.
|
|
{
|
|
GString *topshpstr = S57_getAttVal(geo, "TOPSHP");
|
|
GString *topmar = NULL;
|
|
char *sy = NULL;
|
|
|
|
if (NULL == topshpstr)
|
|
sy = ";SY(QUESMRK1)";
|
|
else {
|
|
int floating = FALSE; // not a floating platform
|
|
int topshp = (NULL==topshpstr) ? 0 : atoi(topshpstr->str);
|
|
|
|
if (TRUE == _atPtPos(geo, FLOATLIST))
|
|
floating = TRUE;
|
|
else
|
|
// FIXME: this test is wierd since it doesn't affect 'floating'
|
|
if (TRUE == _atPtPos(geo, RIGIDLIST))
|
|
floating = FALSE;
|
|
|
|
|
|
if (floating) {
|
|
// floating platform
|
|
switch (topshp) {
|
|
case 1 : sy = ";SY(TOPMAR02)"; break;
|
|
case 2 : sy = ";SY(TOPMAR04)"; break;
|
|
case 3 : sy = ";SY(TOPMAR10)"; break;
|
|
case 4 : sy = ";SY(TOPMAR12)"; break;
|
|
|
|
case 5 : sy = ";SY(TOPMAR13)"; break;
|
|
case 6 : sy = ";SY(TOPMAR14)"; break;
|
|
case 7 : sy = ";SY(TOPMAR65)"; break;
|
|
case 8 : sy = ";SY(TOPMAR17)"; break;
|
|
|
|
case 9 : sy = ";SY(TOPMAR16)"; break;
|
|
case 10: sy = ";SY(TOPMAR08)"; break;
|
|
case 11: sy = ";SY(TOPMAR07)"; break;
|
|
case 12: sy = ";SY(TOPMAR14)"; break;
|
|
|
|
case 13: sy = ";SY(TOPMAR05)"; break;
|
|
case 14: sy = ";SY(TOPMAR06)"; break;
|
|
case 17: sy = ";SY(TMARDEF2)"; break;
|
|
case 18: sy = ";SY(TOPMAR10)"; break;
|
|
|
|
case 19: sy = ";SY(TOPMAR13)"; break;
|
|
case 20: sy = ";SY(TOPMAR14)"; break;
|
|
case 21: sy = ";SY(TOPMAR13)"; break;
|
|
case 22: sy = ";SY(TOPMAR14)"; break;
|
|
|
|
case 23: sy = ";SY(TOPMAR14)"; break;
|
|
case 24: sy = ";SY(TOPMAR02)"; break;
|
|
case 25: sy = ";SY(TOPMAR04)"; break;
|
|
case 26: sy = ";SY(TOPMAR10)"; break;
|
|
|
|
case 27: sy = ";SY(TOPMAR17)"; break;
|
|
case 28: sy = ";SY(TOPMAR18)"; break;
|
|
case 29: sy = ";SY(TOPMAR02)"; break;
|
|
case 30: sy = ";SY(TOPMAR17)"; break;
|
|
|
|
case 31: sy = ";SY(TOPMAR14)"; break;
|
|
case 32: sy = ";SY(TOPMAR10)"; break;
|
|
case 33: sy = ";SY(TMARDEF2)"; break;
|
|
default: sy = ";SY(TMARDEF2)"; break;
|
|
}
|
|
} else {
|
|
// not a floating platform
|
|
switch (topshp) {
|
|
case 1 : sy = ";SY(TOPMAR22)"; break;
|
|
case 2 : sy = ";SY(TOPMAR24)"; break;
|
|
case 3 : sy = ";SY(TOPMAR30)"; break;
|
|
case 4 : sy = ";SY(TOPMAR32)"; break;
|
|
|
|
case 5 : sy = ";SY(TOPMAR33)"; break;
|
|
case 6 : sy = ";SY(TOPMAR34)"; break;
|
|
case 7 : sy = ";SY(TOPMAR85)"; break;
|
|
case 8 : sy = ";SY(TOPMAR86)"; break;
|
|
|
|
case 9 : sy = ";SY(TOPMAR36)"; break;
|
|
case 10: sy = ";SY(TOPMAR28)"; break;
|
|
case 11: sy = ";SY(TOPMAR27)"; break;
|
|
case 12: sy = ";SY(TOPMAR14)"; break;
|
|
|
|
case 13: sy = ";SY(TOPMAR25)"; break;
|
|
case 14: sy = ";SY(TOPMAR26)"; break;
|
|
case 15: sy = ";SY(TOPMAR88)"; break;
|
|
case 16: sy = ";SY(TOPMAR87)"; break;
|
|
|
|
case 17: sy = ";SY(TMARDEF1)"; break;
|
|
case 18: sy = ";SY(TOPMAR30)"; break;
|
|
case 19: sy = ";SY(TOPMAR33)"; break;
|
|
case 20: sy = ";SY(TOPMAR34)"; break;
|
|
|
|
case 21: sy = ";SY(TOPMAR33)"; break;
|
|
case 22: sy = ";SY(TOPMAR34)"; break;
|
|
case 23: sy = ";SY(TOPMAR34)"; break;
|
|
case 24: sy = ";SY(TOPMAR22)"; break;
|
|
|
|
case 25: sy = ";SY(TOPMAR24)"; break;
|
|
case 26: sy = ";SY(TOPMAR30)"; break;
|
|
case 27: sy = ";SY(TOPMAR86)"; break;
|
|
case 28: sy = ";SY(TOPMAR89)"; break;
|
|
|
|
case 29: sy = ";SY(TOPMAR22)"; break;
|
|
case 30: sy = ";SY(TOPMAR86)"; break;
|
|
case 31: sy = ";SY(TOPMAR14)"; break;
|
|
case 32: sy = ";SY(TOPMAR30)"; break;
|
|
case 33: sy = ";SY(TMARDEF1)"; break;
|
|
default: sy = ";SY(TMARDEF1)"; break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
topmar = g_string_new(sy);
|
|
|
|
return topmar;
|
|
}
|
|
|
|
/*
|
|
static GString *_UDWHAZ03(S57_geo *geo, double depth_value)
|
|
// Remarks: Obstructions or isolated underwater dangers of depths less than the safety
|
|
// contour which lie within the safe waters defined by the safety contour are
|
|
// to be presented by a specific isolated danger symbol as hazardous objects
|
|
// and put in IMO category DISPLAYBASE (see (3), App.2, 1.3). This task
|
|
// is performed by this conditional symbology procedure.
|
|
{
|
|
GString *udwhaz03str = NULL;
|
|
int danger = FALSE;
|
|
double safety_contour = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
|
|
S57_geo *geoTmp = geo;
|
|
|
|
if (depth_value <= safety_contour) {
|
|
// that intersect this point/line/area for OBSTRN04
|
|
// that intersect this point/area for WRECKS02
|
|
|
|
// get area DEPARE & DRGARE that intersect this point/line/area
|
|
while (NULL != (geoTmp = S57_nextObj(geoTmp))) {
|
|
|
|
if (LINES_T == S57_getObjtype(geoTmp)) {
|
|
GString *drval2str = S57_getAttVal(geoTmp, "DRVAL2");
|
|
double drval2 = (NULL == drval2str) ? 0.0 : atof(drval2str->str);
|
|
|
|
if (drval2 < safety_contour) {
|
|
danger = TRUE;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
GString *drval1str = S57_getAttVal(geoTmp, "DRVAL1");
|
|
double drval1 = (NULL == drval1str) ? 0.0 : atof(drval1str->str);
|
|
|
|
if (drval1 >= safety_contour) {
|
|
danger = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//danger = TRUE; // true
|
|
if (TRUE == danger) {
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
if (NULL != watlevstr && ('1' == *watlevstr->str || '2' == *watlevstr->str))
|
|
udwhaz03str = g_string_new(";OP(--D14050");
|
|
else {
|
|
udwhaz03str = g_string_new(";OP(8OD14010);SY(ISODGR51)");
|
|
S57_setAtt(geo, "SCAMIN", "INFINITE");
|
|
}
|
|
}
|
|
}
|
|
|
|
S57_unlinkObj(geo);
|
|
|
|
return udwhaz03str;
|
|
}
|
|
|
|
static GString *VESSEL01 (S57_geo *geo)
|
|
// Remarks: The mariner should be prompted to select from the following options:
|
|
// - ARPA target or AIS report (overall decision or vessel by vessel) (vesrce)
|
|
// - *time-period determining vector-length for all vectors (vecper)
|
|
// - whether to show a vector (overall or vessel by vessel) (vestat)
|
|
// - *whether to symbolize vector stabilization (vecstb)
|
|
// - *whether to show one-minute or six-minute vector time marks (vecmrk)
|
|
// - whether to show heading line on AIS vessel reports (headng)
|
|
// * Note that the same vector parameters should be used for own-ship and all vessel
|
|
// vectors.
|
|
{
|
|
PRINTF("Mariner's object not drawn\n");
|
|
return NULL;
|
|
}
|
|
|
|
static GString *VRMEBL01 (S57_geo *geo)
|
|
// Remarks: This conditional symbology procedure symbolizes the three cases of range
|
|
// circle, bearing line and range/bearing line. VRM's and EBL's can be ship-centred
|
|
// or freely movable, and two line-styles are available
|
|
{
|
|
PRINTF("Mariner's object not drawn\n");
|
|
return NULL;
|
|
}
|
|
|
|
static GString *WRECKS02 (S57_geo *geo)
|
|
// Remarks: Wrecks of depths less than the safety contour which lie within the safe waters
|
|
// defined by the safety contour are to be presented by a specific isolated
|
|
// danger symbol and put in IMO category DISPLAYBASE (see (3), App.2,
|
|
// 1.3). This task is performed by the sub-procedure "UDWHAZ03" which is
|
|
// called by this symbology procedure.
|
|
{
|
|
GString *wrecks02str = NULL;
|
|
GString *sndfrm02str = NULL;
|
|
GString *udwhaz03str = NULL;
|
|
GString *quapnt01str = NULL;
|
|
double least_depth = UNKNOWN;
|
|
double depth_value = UNKNOWN;
|
|
GString *valsoustr = S57_getAttVal(geo, "VALSOU");
|
|
double valsou = UNKNOWN;
|
|
|
|
// exit if not in drawing state
|
|
if (1 == S52_state)
|
|
return NULL;
|
|
|
|
if (NULL != valsoustr) {
|
|
valsou = atof(valsoustr->str);
|
|
depth_value = valsou;
|
|
sndfrm02str = _SNDFRM02(geo, depth_value);
|
|
} else {
|
|
if (AREAS_T == S57_getObjtype(geo))
|
|
least_depth = _DEPVAL01(geo, least_depth);
|
|
|
|
if (least_depth == UNKNOWN) {
|
|
// WARNING: ambiguity removed in WRECKS03 (see update)
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
GString *catwrkstr = S57_getAttVal(geo, "CATWRK");
|
|
|
|
if (NULL == watlevstr) // default
|
|
depth_value = -15.0;
|
|
else
|
|
switch (*watlevstr->str) { // ambiguous
|
|
case '1':
|
|
case '2': depth_value = -15.0 ; break;
|
|
case '3': depth_value = 0.01; break;
|
|
case '4': depth_value = -15.0 ; break;
|
|
case '5': depth_value = 0.0 ; break;
|
|
case '6': depth_value = -15.0 ; break;
|
|
default :{
|
|
if (NULL != catwrkstr) {
|
|
switch (*catwrkstr->str) {
|
|
case '1': depth_value = 20.0; break;
|
|
case '2': depth_value = 0.0; break;
|
|
case '4':
|
|
case '5': depth_value = -15.0; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
depth_value = least_depth;
|
|
|
|
|
|
}
|
|
|
|
udwhaz03str = _UDWHAZ03(geo, depth_value);
|
|
quapnt01str = _QUAPNT01(geo);
|
|
|
|
if (POINT_T == S57_getObjtype(geo)) {
|
|
if (NULL != udwhaz03str) {
|
|
wrecks02str = g_string_new(udwhaz03str->str);
|
|
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
|
|
} else {
|
|
// Continuation A (POINT_T)
|
|
if (UNKNOWN != valsou) {
|
|
|
|
if (valsou <= 20.0) {
|
|
wrecks02str = g_string_new(";SY(DANGER01)");
|
|
if (NULL != sndfrm02str)
|
|
g_string_append(wrecks02str, sndfrm02str->str);
|
|
|
|
} else
|
|
wrecks02str = g_string_new(";SY(DANGER02)");
|
|
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(wrecks02str, udwhaz03str->str);
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
|
|
} else {
|
|
char *sym = NULL;
|
|
GString *catwrkstr = S57_getAttVal(geo, "CATWRK");
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL != catwrkstr && NULL != watlevstr) {
|
|
if ('1' == *catwrkstr->str && '3' == *watlevstr->str)
|
|
sym =";SY(WRECKS04)";
|
|
else {
|
|
if ('2' == *catwrkstr->str && '3' == *watlevstr->str)
|
|
sym = ";SY(WRECKS05)";
|
|
else {
|
|
if ('4' == *catwrkstr->str || '5' == *catwrkstr->str)
|
|
sym = ";SY(WRECKS01)";
|
|
else {
|
|
if ('1' == *watlevstr->str ||
|
|
'2' == *watlevstr->str ||
|
|
'5' == *watlevstr->str ||
|
|
'4' == *watlevstr->str ){
|
|
sym = ";SY(WRECKS01)";
|
|
} else
|
|
sym = ";SY(WRECKS05)"; // default
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wrecks02str = g_string_new(sym);
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
// Continuation B (AREAS_T)
|
|
GString *quaposstr = S57_getAttVal(geo, "QUAPOS");
|
|
int quapos = (NULL == quaposstr)? 0 : atoi(quaposstr->str);
|
|
char *line = NULL;
|
|
|
|
if (2 <= quapos && quapos < 10)
|
|
line = ";LC(LOWACC41)";
|
|
else {
|
|
if ( NULL != udwhaz03str)
|
|
line = ";LS(DOTT,2,CHBLK)";
|
|
else {
|
|
if (UNKNOWN != valsou){
|
|
if (valsou <= 20)
|
|
line = ";LS(DOTT,2,CHBLK)";
|
|
else
|
|
line = ";LS(DASH,2,CHBLK)";
|
|
} else {
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL == watlevstr)
|
|
line = ";LS(DOTT,2,CSTLN)";
|
|
else {
|
|
switch (*watlevstr->str){
|
|
case '1':
|
|
case '2': line = ";LS(SOLD,2,CSTLN)"; break;
|
|
case '4': line = ";LS(DASH,2,CSTLN)"; break;
|
|
case '3':
|
|
case '5':
|
|
|
|
default : line = ";LS(DOTT,2,CSTLN)"; break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
wrecks02str = g_string_new(line);
|
|
|
|
if (UNKNOWN != valsou) {
|
|
if (valsou <= 20) {
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(wrecks02str, udwhaz03str->str);
|
|
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
|
|
if (NULL != sndfrm02str)
|
|
g_string_append(wrecks02str, sndfrm02str->str);
|
|
|
|
} else {
|
|
// NOTE: ??? same as above ???
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(wrecks02str, udwhaz03str->str);
|
|
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
}
|
|
} else {
|
|
char *ac = NULL;
|
|
GString *watlevstr = S57_getAttVal(geo, "WATLEV");
|
|
|
|
if (NULL == watlevstr)
|
|
ac = ";AC(DEPVS)";
|
|
else
|
|
switch (*watlevstr->str) {
|
|
case '1':
|
|
case '2': ac = ";AC(CHBRN)"; break;
|
|
case '4': ac = ";AC(DEPIT)"; break;
|
|
case '5':
|
|
case '3':
|
|
default : ac = ";AC(DEPVS)"; break;
|
|
}
|
|
|
|
g_string_append(wrecks02str, ac);
|
|
|
|
if (NULL != udwhaz03str)
|
|
g_string_append(wrecks02str, udwhaz03str->str);
|
|
|
|
if (NULL != quapnt01str)
|
|
g_string_append(wrecks02str, quapnt01str->str);
|
|
}
|
|
}
|
|
|
|
if (NULL != sndfrm02str) g_string_free(sndfrm02str, TRUE);
|
|
if (NULL != udwhaz03str) g_string_free(udwhaz03str, TRUE);
|
|
if (NULL != quapnt01str) g_string_free(quapnt01str, TRUE);
|
|
|
|
return wrecks02str;
|
|
}
|
|
|
|
|
|
//--------------------------------
|
|
//
|
|
// JUMP TABLE SECTION
|
|
//
|
|
//--------------------------------
|
|
|
|
|
|
CondSymb condTable[] = {
|
|
// name call Sub-Procedure
|
|
{"CLRLIN01", CLRLIN01}, //
|
|
{"DATCVR01", DATCVR01}, //
|
|
{"DEPARE01", DEPARE01}, // _RESCSP01, _SEABED01
|
|
{"DEPCNT02", DEPCNT02}, //
|
|
{"LEGLIN02", LEGLIN02}, // str
|
|
{"LIGHTS05", LIGHTS05}, // _LITDSN01
|
|
{"OBSTRN04", OBSTRN04}, // _DEPVAL01, _QUAPNT01, _SNDFRM02, _UDWHAZ03
|
|
{"OWNSHP02", OWNSHP02}, //
|
|
{"PASTRK01", PASTRK01}, //
|
|
{"QUAPOS01", QUAPOS01}, // _QUALIN01, _QUAPNT01
|
|
{"SLCONS03", SLCONS03}, //
|
|
{"RESARE02", RESARE02}, //
|
|
{"RESTRN01", RESTRN01}, // _RESCSP01
|
|
{"SOUNDG02", SOUNDG02}, // _SNDFRM02
|
|
{"TOPMAR01", TOPMAR01}, //
|
|
{"VESSEL01", VESSEL01}, //
|
|
{"VRMEBL01", VRMEBL01}, //
|
|
{"WRECKS02", WRECKS02}, // _DEPVAL01, _QUAPNT01, _SNDFRM02, _UDWHAZ03
|
|
|
|
{"########",NULL}
|
|
};
|
|
*/
|
|
#endif
|