ossimProjection* ossimGdalProjectionFactory::createProjection(const ossimFilename& filename, ossim_uint32 entryIdx)const { ossimKeywordlist kwl; if(ossimString(filename).trim().empty()) return 0; // ossimRefPtr<ossimImageHandler> h = new ossimGdalTileSource; GDALDatasetH h = GDALOpen(filename.c_str(), GA_ReadOnly); GDALDriverH driverH = 0; ossimProjection* proj = 0; if(h) { driverH = GDALGetDatasetDriver( h ); ossimString driverName( driverH ? GDALGetDriverShortName( driverH ) : "" ); // use OSSIM's projection loader for NITF // if(driverName == "NITF") { GDALClose(h); return 0; } if(entryIdx != 0) { char** papszMetadata = GDALGetMetadata( h, "SUBDATASETS" ); //--- // ??? (drb) Should this be: // if ( entryIdx >= CSLCount(papszMetadata) ) close... //--- if( papszMetadata&&(CSLCount(papszMetadata) < static_cast<ossim_int32>(entryIdx)) ) { ossimNotify(ossimNotifyLevel_WARN) << "ossimGdalProjectionFactory::createProjection: We don't support multi entry handlers through the factory yet, only through the handler!"; GDALClose(h); return 0; } else { GDALClose(h); return 0; } } ossimString wkt(GDALGetProjectionRef( h )); double geoTransform[6]; bool transOk = GDALGetGeoTransform( h, geoTransform ) == CE_None; bool wktTranslatorOk = wkt.empty()?false:wktTranslator.toOssimKwl(wkt, kwl); if(!wktTranslatorOk) { ossim_uint32 gcpCount = GDALGetGCPCount(h); if(gcpCount > 3) { ossim_uint32 idx = 0; const GDAL_GCP* gcpList = GDALGetGCPs(h); ossimTieGptSet tieSet; if(gcpList) { for(idx = 0; idx < gcpCount; ++idx) { ossimDpt dpt(gcpList[idx].dfGCPPixel, gcpList[idx].dfGCPLine); ossimGpt gpt(gcpList[idx].dfGCPY, gcpList[idx].dfGCPX, gcpList[idx].dfGCPZ); tieSet.addTiePoint(new ossimTieGpt(gpt, dpt, .5)); } //ossimPolynomProjection* tempProj = new ossimPolynomProjection; ossimBilinearProjection* tempProj = new ossimBilinearProjection; //tempProj->setupOptimizer("1 x y x2 xy y2 x3 y3 xy2 x2y z xz yz"); tempProj->optimizeFit(tieSet); proj = tempProj; } } } if ( transOk && proj==0 ) { ossimString proj_type(kwl.find(ossimKeywordNames::TYPE_KW)); ossimString datum_type(kwl.find(ossimKeywordNames::DATUM_KW)); ossimString units(kwl.find(ossimKeywordNames::UNITS_KW)); if ( proj_type.trim().empty() && (driverName == "MrSID" || driverName == "JP2MrSID") ) { bool bClose = true; // ESH 04/2008, #54: if no rotation factors use geographic system if( geoTransform[2] == 0.0 && geoTransform[4] == 0.0 ) { ossimString projTag( GDALGetMetadataItem( h, "IMG__PROJECTION_NAME", "" ) ); if ( projTag.contains("Geographic") ) { bClose = false; kwl.add(ossimKeywordNames::TYPE_KW, "ossimEquDistCylProjection", true); proj_type = kwl.find( ossimKeywordNames::TYPE_KW ); // Assign units if set in Metadata ossimString unitTag( GDALGetMetadataItem( h, "IMG__HORIZONTAL_UNITS", "" ) ); if ( unitTag.contains("dd") ) // decimal degrees { units = "degrees"; } else if ( unitTag.contains("dm") ) // decimal minutes { units = "minutes"; } else if ( unitTag.contains("ds") ) // decimal seconds { units = "seconds"; } } } if ( bClose == true ) { GDALClose(h); return 0; } } // Pixel-is-point of pixel-is area affects the location of the tiepoint since OSSIM is // always pixel-is-point so 1/2 pixel shift may be necessary: if((driverName == "MrSID") || (driverName == "JP2MrSID") || (driverName == "AIG")) { const char* rasterTypeStr = GDALGetMetadataItem( h, "GEOTIFF_CHAR__GTRasterTypeGeoKey", "" ); ossimString rasterTypeTag( rasterTypeStr ); // If the raster type is pixel_is_area, shift the tie point by // half a pixel to locate it at the pixel center. if ((driverName == "AIG") || (rasterTypeTag.contains("RasterPixelIsArea"))) { geoTransform[0] += fabs(geoTransform[1]) / 2.0; geoTransform[3] -= fabs(geoTransform[5]) / 2.0; } } else { // Conventionally, HFA stores the pixel alignment type for each band. Here assume all // bands are the same. Consider only the first band: GDALRasterBandH bBand = GDALGetRasterBand( h, 1 ); char** papszMetadata = GDALGetMetadata( bBand, NULL ); if (CSLCount(papszMetadata) > 0) { for(int i = 0; papszMetadata[i] != NULL; i++ ) { ossimString metaStr = papszMetadata[i]; metaStr.upcase(); if (metaStr.contains("AREA_OR_POINT")) { ossimString pixel_is_point_or_area = metaStr.split("=")[1]; pixel_is_point_or_area.upcase(); if (pixel_is_point_or_area.contains("AREA")) { // Need to shift the tie point so that pixel is point: geoTransform[0] += fabs(geoTransform[1]) / 2.0; geoTransform[3] -= fabs(geoTransform[5]) / 2.0; } break; } } } } kwl.remove(ossimKeywordNames::UNITS_KW); ossimDpt gsd(fabs(geoTransform[1]), fabs(geoTransform[5])); ossimDpt tie(geoTransform[0], geoTransform[3]); ossimUnitType savedUnitType = static_cast<ossimUnitType>(ossimUnitTypeLut::instance()->getEntryNumber(units)); ossimUnitType unitType = savedUnitType; if(unitType == OSSIM_UNIT_UNKNOWN) unitType = OSSIM_METERS; if((proj_type == "ossimLlxyProjection") || (proj_type == "ossimEquDistCylProjection")) { // ESH 09/2008 -- Add the orig_lat and central_lon if the image // is using geographic coordsys. This is used to convert the // gsd to linear units. // Half the number of pixels in lon/lat directions int nPixelsLon = GDALGetRasterXSize(h)/2.0; int nPixelsLat = GDALGetRasterYSize(h)/2.0; // Shift from image corner to center in lon/lat double shiftLon = nPixelsLon * fabs(gsd.x); double shiftLat = -nPixelsLat * fabs(gsd.y); // lon/lat of center pixel of the image double centerLon = tie.x + shiftLon; double centerLat = tie.y + shiftLat; kwl.add(ossimKeywordNames::ORIGIN_LATITUDE_KW, centerLat, true); kwl.add(ossimKeywordNames::CENTRAL_MERIDIAN_KW, centerLon, true); kwl.add(ossimKeywordNames::TIE_POINT_LAT_KW, tie.y, true); kwl.add(ossimKeywordNames::TIE_POINT_LON_KW, tie.x, true); kwl.add(ossimKeywordNames::DECIMAL_DEGREES_PER_PIXEL_LAT, gsd.y, true); kwl.add(ossimKeywordNames::DECIMAL_DEGREES_PER_PIXEL_LON, gsd.x, true); if(savedUnitType == OSSIM_UNIT_UNKNOWN) { unitType = OSSIM_DEGREES; } } kwl.add(ossimKeywordNames::PIXEL_SCALE_XY_KW, gsd.toString(), true); kwl.add(ossimKeywordNames::PIXEL_SCALE_UNITS_KW, units, true); kwl.add(ossimKeywordNames::TIE_POINT_XY_KW, tie.toString(), true); kwl.add(ossimKeywordNames::TIE_POINT_UNITS_KW, units, true); std::stringstream mString; // store as a 4x4 matrix mString << ossimString::toString(geoTransform[1], 20) << " " << ossimString::toString(geoTransform[2], 20) << " " << 0 << " " << ossimString::toString(geoTransform[0], 20) << " " << ossimString::toString(geoTransform[4], 20) << " " << ossimString::toString(geoTransform[5], 20) << " " << 0 << " " << ossimString::toString(geoTransform[3], 20) << " " << 0 << " " << 0 << " " << 1 << " " << 0 << " " << 0 << " " << 0 << " " << 0 << " " << 1; kwl.add(ossimKeywordNames::IMAGE_MODEL_TRANSFORM_MATRIX_KW, mString.str().c_str(), true); //--- // SPECIAL CASE: ArcGrid in British National Grid //--- if(driverName == "AIG" && datum_type == "OSGB_1936") { ossimFilename prj_file = filename.path() + "/prj.adf"; if(prj_file.exists()) { ossimKeywordlist prj_kwl(' '); prj_kwl.addFile(prj_file); ossimString proj = prj_kwl.find("Projection"); // Reset projection and Datum correctly for BNG. if(proj.upcase().contains("GREATBRITAIN")) { kwl.add(ossimKeywordNames::TYPE_KW, "ossimBngProjection", true); ossimString datum = prj_kwl.find("Datum"); if(datum != "") { if(datum == "OGB_A") datum = "OGB-A"; else if(datum == "OGB_B") datum = "OGB-B"; else if(datum == "OGB_C") datum = "OGB-C"; else if(datum == "OGB_D") datum = "OGB-D"; else if(datum == "OGB_M") datum = "OGB-M"; else if(datum == "OGB_7") datum = "OGB-7"; kwl.add(ossimKeywordNames::DATUM_KW, datum, true); } } } } } if(traceDebug()) { ossimNotify(ossimNotifyLevel_DEBUG) << "ossimGdalProjectionFactory: createProjection KWL = \n " << kwl << std::endl; } GDALClose(h); proj = ossimProjectionFactoryRegistry::instance()->createProjection(kwl); } return proj; }
ossimProjection* ossimMrSidReader::getGeoProjection() { if (theReader == 0) return 0; // A local KWL will be filled as items are read from the support data. At the end, // the projection factory will be provided with the populated KWL to instantiate proper // map projection. No prefix needed. ossimKeywordlist kwl; // Add the lines and samples. kwl.add(ossimKeywordNames::NUMBER_LINES_KW, getNumberOfLines(0)); kwl.add(ossimKeywordNames::NUMBER_SAMPLES_KW, getNumberOfSamples(0)); ossimString proj_type; ossimString datum_type; ossimString scale_units; ossimString tie_pt_units = "meters"; ossim_uint32 code = 0; ossim_uint32 gcsCode = 0; ossim_uint32 pcsCode = 0; const LTIGeoCoord& geo = theReader->getGeoCoord(); LTIMetadataDatabase metaDb = theReader->getMetadata(); const char* projStr = geo.getWKT(); // Can only handle non-rotated images since only projection object returned (no 2d transform): if( (geo.getXRot() != 0.0) || (geo.getYRot() != 0.0)) return 0; bool gcsFound = getMetadataElement(metaDb, "GEOTIFF_NUM::2048::GeographicTypeGeoKey", &gcsCode); bool pcsFound = getMetadataElement(metaDb, "GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey", &pcsCode); if (gcsFound && pcsCode == false) { code = gcsCode; kwl.add(ossimKeywordNames::TYPE_KW, "ossimEquDistCylProjection"); proj_type = "ossimEquDistCylProjection"; kwl.add(ossimKeywordNames::GCS_CODE_KW, code); tie_pt_units = "degrees"; // Assign units if set in Metadata char unitStr[200]; if (getMetadataElement(metaDb, "GEOTIFF_CHAR::GeogAngularUnitsGeoKey", &unitStr, sizeof(unitStr)) == true) { ossimString unitTag(unitStr); if ( unitTag.contains("Angular_Degree") ) // decimal degrees scale_units = "degrees"; else if ( unitTag.contains("Angular_Minute") ) // decimal minutes scale_units = "minutes"; else if ( unitTag.contains("Angular_Second") ) // decimal seconds scale_units = "seconds"; } } else { if (!pcsFound) { pcsFound = getMetadataElement(metaDb, "GEOTIFF_NUM::3074::ProjectionGeoKey", &code); } else { code = pcsCode; } if (pcsFound) { kwl.add(ossimKeywordNames::PCS_CODE_KW, code); tie_pt_units = "meters"; char unitStr[200]; if (getMetadataElement(metaDb, "GEOTIFF_CHAR::ProjLinearUnitsGeoKey", &unitStr, sizeof(unitStr))) { ossimString unitTag(unitStr); if ( unitTag.contains("Linear_Meter") ) scale_units = "meters"; else if ( unitTag.contains("Linear_Foot") ) scale_units = "feet"; else if ( unitTag.contains("Linear_Foot_US_Survey") ) scale_units = "us_survey_feet"; } } } char rasterTypeStr[200]; strcpy( rasterTypeStr, "unnamed" ); double topLeftX = geo.getX(); // AMBIGUOUS! OLK 5/10 double topLeftY = geo.getY(); // AMBIGUOUS! OLK 5/10 if (getMetadataElement(metaDb, "GEOTIFF_CHAR::GTRasterTypeGeoKey", &rasterTypeStr, sizeof(rasterTypeStr)) == true) { ossimString rasterTypeTag(rasterTypeStr); // If the raster type is pixel_is_area, shift the tie point by // half a pixel to locate it at the pixel center. if ( rasterTypeTag.contains("RasterPixelIsPoint") ) { topLeftX -= geo.getXRes() / 2.0; // AMBIGUOUS -- DOESN'T MATCH COMMENT! OLK 5/10 topLeftY += geo.getYRes() / 2.0; // AMBIGUOUS! OLK 5/10 } } ossimDpt gsd(fabs(geo.getXRes()), fabs(geo.getYRes())); ossimDpt tie(topLeftX, topLeftY); // CANNOT HANDLE 2D TRANSFORMS -- ONLY REAL PROJECTIONS. (OLK 5/10) //std::stringstream mString; //// store as a 4x4 matrix //mString << ossimString::toString(geo.getXRes(), 20) // << " " << ossimString::toString(geo.getXRot(), 20) // << " " << 0 << " " // << ossimString::toString(geo.getX(), 20) // << " " << ossimString::toString(geo.getYRot(), 20) // << " " << ossimString::toString(geo.getYRes(), 20) // << " " << 0 << " " // << ossimString::toString(geo.getY(), 20) // << " " << 0 << " " << 0 << " " << 1 << " " << 0 // << " " << 0 << " " << 0 << " " << 0 << " " << 1; //kwl.add(ossimKeywordNames::IMAGE_MODEL_TRANSFORM_MATRIX_KW, mString.str().c_str()); // if meta data does not have the code info, try to read from .aux file if (code == 0) { ossimFilename auxFile = theImageFile; auxFile.setExtension("aux"); ossimAuxFileHandler auxHandler; if (auxFile.exists() && auxHandler.open(auxFile)) { ossimString proj_name = auxHandler.getProjectionName(); ossimString datum_name = auxHandler.getDatumName(); ossimString unitType = auxHandler.getUnitType(); // HACK: Geographic projection is specified in non-WKT format. Intercepting here. OLK 5/10 // TODO: Need projection factory that can handle miscellaneous non-WKT specs as they are // encountered. if (proj_name.contains("Geographic")) { kwl.add(ossimKeywordNames::TYPE_KW, "ossimEquDistCylProjection", false); scale_units = "degrees"; tie_pt_units = "degrees"; } else { // pass along MrSid's projection name and pray it can be resolved: kwl.add(ossimKeywordNames::PROJECTION_KW, proj_name, false); if (unitType.empty()) { if (proj_name.downcase().contains("feet")) { scale_units = "feet"; tie_pt_units = "feet"; } } else { scale_units = unitType; tie_pt_units = unitType; } } // HACK: WGS-84 is specified in non-WKT format. Intercepting here. OLK 5/10 // TODO: Need datum factory that can handle miscellaneous non-WKT specs as they are // encountered. if (datum_name.contains("WGS") && datum_name.contains("84")) kwl.add(ossimKeywordNames::GCS_CODE_KW, "EPSG:4326"); else kwl.add(ossimKeywordNames::DATUM_KW, datum_name, false); } } kwl.add(ossimKeywordNames::PIXEL_SCALE_XY_KW, gsd.toString()); kwl.add(ossimKeywordNames::PIXEL_SCALE_UNITS_KW, scale_units); kwl.add(ossimKeywordNames::TIE_POINT_XY_KW, tie.toString()); kwl.add(ossimKeywordNames::TIE_POINT_UNITS_KW, tie_pt_units); ossimProjection* proj = ossimProjectionFactoryRegistry::instance()->createProjection(kwl); return proj; }