S57_geo *S57_ogrLoadObject(const char *objname, void *feature) { return_if_null(objname); return_if_null(feature); // debug //PRINTF("DEBUG: start loading object (%s:%X)\n", objname, feature); S57_geo *geoData = _ogrLoadObject(objname, feature, NULL); if (NULL == geoData) return NULL; if (0 != strcmp(WORLD_BASENM, objname)) { S57_setName(geoData, objname); } _setAtt(geoData, feature); // debug //if (207 == S57_getGeoID(geoData)) { // S57_dumpData(geoData, FALSE); //} //PRINTF("DEBUG: finish loading object (%s)\n", objname); return geoData; }
S57_geo *S57_ogrLoadObject(const char *objname, void *feature) { return_if_null(objname); return_if_null(feature); // debug //PRINTF("DEBUG: start loading object (%s:%X)\n", objname, feature); S57_geo *geoData = _ogrLoadObject(objname, feature, NULL); if (NULL == geoData) return NULL; // FIXME: world has no name! //if (0 != g_strcmp0(WORLD_BASENM, objname)) { S57_setName(geoData, objname); //} _setAtt(geoData, feature); //PRINTF("DEBUG: finish loading object (%s)\n", objname); return geoData; }
static S57_geo *_ogrLoadObject(const char *objname, void *feature, OGRGeometryH hGeomNext) { S57_geo *geoData = NULL; OGRGeometryH hGeom = NULL; OGRwkbGeometryType eType = wkbNone; if (NULL != feature) hGeom = OGR_F_GetGeometryRef((OGRFeatureH)feature); else hGeom = hGeomNext; if (NULL != hGeom) eType = OGR_G_GetGeometryType(hGeom); else eType = wkbNone; // DSIS switch (eType) { // POINT case wkbPoint25D: case wkbPoint: { geocoord *pointxyz = g_new(geocoord, 3); pointxyz[0] = OGR_G_GetX(hGeom, 0); pointxyz[1] = OGR_G_GetY(hGeom, 0); pointxyz[2] = OGR_G_GetZ(hGeom, 0); geoData = S57_setPOINT(pointxyz); _setExtent(geoData, hGeom); break; } // LINE case wkbLineString25D: case wkbLineString: { int count = OGR_G_GetPointCount(hGeom); // NOTE: when S52_USE_SUPP_LINE_OVERLAP then Edge might have 0 node /* so this code fail if (count < 2) { PRINTF("WARNING: a line with less than 2 points!?\n"); g_assert(0); return NULL; } */ geocoord *linexyz = NULL; if (0 != count) linexyz = g_new(geocoord, 3*count); for (int node=0; node<count; ++node) { linexyz[node*3+0] = OGR_G_GetX(hGeom, node); linexyz[node*3+1] = OGR_G_GetY(hGeom, node); linexyz[node*3+2] = OGR_G_GetZ(hGeom, node); } geoData = S57_setLINES(count, linexyz); _setExtent(geoData, hGeom); break; } // AREA case wkbPolygon25D: case wkbPolygon: { // Note: S57 area have CW outer ring and CCW inner ring guint nRingCount = OGR_G_GetGeometryCount(hGeom); guint *ringxyznbr; geocoord **ringxyz; double area = 0; ringxyznbr = g_new(guint, nRingCount); ringxyz = g_new(geocoord *, nRingCount); // NOTE: to check winding on an open area //for (i = n-1, j = 0; j < n; i = j, j++) { // ai = x[i] * y[j] - x[j] * y[i]; //} for (guint iRing=0; iRing<nRingCount; ++iRing) { OGRGeometryH hRing; guint vert_count = _getGeoPtCount(hGeom, iRing, &hRing); ringxyznbr[iRing] = vert_count; // skip this ring if no vertex if (0 == vert_count) { // FIXME: what should be done here, // FIX: S52 - discard this ring or the object or the layer or the whole chart (update) // FIX: GDAL/OGR - is it a bug in the reader or in the chart it self (S57) // FIX: or this is an empty Geo PRINTF("WARNING: wkbPolygon, empty ring (%s)\n", objname); g_assert(0); continue; } ringxyz[iRing] = g_new(geocoord, vert_count*3*sizeof(geocoord)); // check if last vertex is NOT the first vertex (ie ring not close) if ((OGR_G_GetX(hRing, 0) != OGR_G_GetX(hRing, vert_count-1)) || (OGR_G_GetY(hRing, 0) != OGR_G_GetY(hRing, vert_count-1)) ) { PRINTF("ERROR: S-57 ring (AREA) not closed (%s)\n", objname); g_assert(0); continue; // Note: to compute area of an open poly //double area = 0; //for (guint i=vert_count-1, j=0; j<vert_count; i=j, ++j) { // double x1 = OGR_G_GetX(hRing, i); // double y1 = OGR_G_GetY(hRing, i); // double x2 = OGR_G_GetX(hRing, j); // double y2 = OGR_G_GetY(hRing, j); // area += (x1*y2) - (x2*y1); //} } for (guint i=0; (i+1)<vert_count; i++) { double x1 = OGR_G_GetX(hRing, i ); double y1 = OGR_G_GetY(hRing, i ); double x2 = OGR_G_GetX(hRing, i+1); double y2 = OGR_G_GetY(hRing, i+1); area += (x1*y2) - (x2*y1); } // CW if area is < 0, else CCW //PRINTF("AREA(ring=%i/%i): %s (%s)\n", iRing, nRingCount, (area <= 0.0) ? "CW" : "CCW", objname); // CCW winding if (area > 0.0) { // if first ring reverse winding to CW if (0 == iRing) { // debug //PRINTF("DEBUG: reversing S-57 outer ring to CW (%s)\n", objname); //g_assert(0); for (guint node=0; node<vert_count; ++node) { ringxyz[iRing][node*3+0] = OGR_G_GetX(hRing, vert_count - node-1); ringxyz[iRing][node*3+1] = OGR_G_GetY(hRing, vert_count - node-1); ringxyz[iRing][node*3+2] = OGR_G_GetZ(hRing, vert_count - node-1); } } else { for (guint node=0; node<vert_count; ++node) { ringxyz[iRing][node*3+0] = OGR_G_GetX(hRing, node); ringxyz[iRing][node*3+1] = OGR_G_GetY(hRing, node); ringxyz[iRing][node*3+2] = OGR_G_GetZ(hRing, node); } } } else { // CW winding if (0 == iRing) { for (guint node=0; node<vert_count; ++node) { ringxyz[iRing][node*3+0] = OGR_G_GetX(hRing, node); ringxyz[iRing][node*3+1] = OGR_G_GetY(hRing, node); ringxyz[iRing][node*3+2] = OGR_G_GetZ(hRing, node); } } else { // if NOT first ring reverse winding (CCW) //PRINTF("DEBUG: reversing S-57 inner ring to CCW (%s)\n", objname); //g_assert(0); for (guint node=0; node<vert_count; ++node) { ringxyz[iRing][node*3+0] = OGR_G_GetX(hRing, vert_count - node-1); ringxyz[iRing][node*3+1] = OGR_G_GetY(hRing, vert_count - node-1); ringxyz[iRing][node*3+2] = OGR_G_GetZ(hRing, vert_count - node-1); } } } } // for loop //geoData = S57_setAREAS(nRingCount, ringxyznbr, ringxyz, (area <= 0.0) ? S57_AW_CW : S57_AW_CCW); geoData = S57_setAREAS(nRingCount, ringxyznbr, ringxyz); _setExtent(geoData, hGeom); if (0 == g_strcmp0(WORLD_BASENM, objname)) { // Note: loading shapefile as a 'marfea' use a transparent fill so NODATA // is still visible (seem better than 'mnufea' wich has no colour fill) S57_setName(geoData, "marfea"); // pslb3_2.pdf (p. II-22): Mariners' Object Class: Manufacturers' feature // Note that manufacturers' areas, whether non-chart or chart areas, should not use area colour fill. //S57_setName(geoData, "mnufea"); } break; } #ifdef S52_USE_WORLD // shapefile area case wkbMultiPolygon: { guint nPolyCount = OGR_G_GetGeometryCount(hGeom); for (guint iPoly=0; iPoly<nPolyCount; ++iPoly) { OGRGeometryH hGeomNext = OGR_G_GetGeometryRef(hGeom, iPoly); // recursion S57_geo *geo = _ogrLoadObject(objname, NULL, hGeomNext); if (NULL == geoData) geoData = geo; else S57_setNextPoly(geoData, geo); } break; } #endif case wkbGeometryCollection: case wkbMultiLineString: { PRINTF("WARNING: wkbGeometryCollection & wkbMultiLineString not handled \n"); g_assert(0); // land here if GDAL/OGR was patched multi-line break; } case wkbNone: // DSID layer get here geoData = S57_set_META(); break; // META_T case wkbMultiPoint: // ogr SPLIT_MULTIPOINT prob !! PRINTF("DEBUG: Multi-Pass!!!\n"); //PRINTF("ERROR: set env var OGR_S57_OPTIONS to SPLIT_MULTIPOINT:ON\n"); //PRINTF("FIXME: or wkbMultiLineString found!\n"); //g_assert_not_reached(); // MultiLineString (need this for line removal) //geoData = S57_set_META(); //GvCollectionShape *collection = (GvCollectionShape *) shape; //int nCollection = gv_shape_collection_get_count(shape); break; default: // FIXME: find a decent default (see openev/gvshapes.h)!!! PRINTF("WKB type not handled = %i %0x\n", eType, eType); g_assert(0); } // debug //PRINTF("name: %s\n", objname); return geoData; }