private static void DatumTransform(ProjectionInfo source, ProjectionInfo dest, double[] xy, double[] z, int startIndex, int numPoints) { Spheroid wgs84 = new Spheroid(Proj4Ellipsoid.WGS_1984); Datum sDatum = source.GeographicInfo.Datum; Datum dDatum = dest.GeographicInfo.Datum; /* -------------------------------------------------------------------- */ /* We cannot do any meaningful datum transformation if either */ /* the source or destination are of an unknown datum type */ /* (ie. only a +ellps declaration, no +datum). This is new */ /* behavior for PROJ 4.6.0. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.Unknown || dDatum.DatumType == DatumType.Unknown) return; /* -------------------------------------------------------------------- */ /* Short cut if the datums are identical. */ /* -------------------------------------------------------------------- */ if (sDatum.Matches(dDatum)) return; // proj4 actually allows some tollerance here if (sDatum.DatumType == dDatum.DatumType) { if (sDatum.Spheroid.EquatorialRadius == dDatum.Spheroid.EquatorialRadius) { if (Math.Abs(sDatum.Spheroid.EccentricitySquared() - dDatum.Spheroid.EccentricitySquared()) < 0.000000000050) { // The tolerence is to allow GRS80 and WGS84 to escape without being transformed at all. return; } } } double srcA = sDatum.Spheroid.EquatorialRadius; double srcEs = sDatum.Spheroid.EccentricitySquared(); double dstA = dDatum.Spheroid.EquatorialRadius; double dstEs = dDatum.Spheroid.EccentricitySquared(); /* -------------------------------------------------------------------- */ /* Create a temporary Z value if one is not provided. */ /* -------------------------------------------------------------------- */ if (z == null) { z = new double[xy.Length / 2]; } /* -------------------------------------------------------------------- */ /* If this datum requires grid shifts, then apply it to geodetic */ /* coordinates. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.GridShift) { // pj_apply_gridshift(pj_param(srcdefn->params,"snadgrids").s, 0, // point_count, point_offset, x, y, z ); GridShift.Apply(source.GeographicInfo.Datum.NadGrids, false, xy, startIndex, numPoints); srcA = wgs84.EquatorialRadius; srcEs = wgs84.EccentricitySquared(); } if (dDatum.DatumType == DatumType.GridShift) { dstA = wgs84.EquatorialRadius; dstEs = wgs84.EccentricitySquared(); } /* ==================================================================== */ /* Do we need to go through geocentric coordinates? */ /* ==================================================================== */ if (srcEs != dstEs || srcA != dstA || sDatum.DatumType == DatumType.Param3 || sDatum.DatumType == DatumType.Param7 || dDatum.DatumType == DatumType.Param3 || dDatum.DatumType == DatumType.Param7) { /* -------------------------------------------------------------------- */ /* Convert to geocentric coordinates. */ /* -------------------------------------------------------------------- */ GeocentricGeodetic gc = new GeocentricGeodetic(sDatum.Spheroid); gc.GeodeticToGeocentric(xy, z, startIndex, numPoints); /* -------------------------------------------------------------------- */ /* Convert between datums. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.Param3 || sDatum.DatumType == DatumType.Param7) { PjGeocentricToWgs84(source, xy, z, startIndex, numPoints); } if (dDatum.DatumType == DatumType.Param3 || dDatum.DatumType == DatumType.Param7) { PjGeocentricFromWgs84(dest, xy, z, startIndex, numPoints); } /* -------------------------------------------------------------------- */ /* Convert back to geodetic coordinates. */ /* -------------------------------------------------------------------- */ gc = new GeocentricGeodetic(dDatum.Spheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); } /* -------------------------------------------------------------------- */ /* Apply grid shift to destination if required. */ /* -------------------------------------------------------------------- */ if (dDatum.DatumType == DatumType.GridShift) { // pj_apply_gridshift(pj_param(dstdefn->params,"snadgrids").s, 1, // point_count, point_offset, x, y, z ); GridShift.Apply(dest.GeographicInfo.Datum.NadGrids, true, xy, startIndex, numPoints); } }
/// <summary> /// datum tranform method /// </summary> /// <param name="source"></param> /// <param name="dest"></param> /// <param name="xy"></param> /// <param name="z"></param> /// <param name="startIndex"></param> /// <param name="numPoints"></param> public void Transform(ProjectionInfo source, ProjectionInfo dest, double[] xy, double[] z, int startIndex, int numPoints) { if (_aiDts.Length == 0) { return; // "empty" datum transform } bool bCoordsAreGeocentric = false; /* -------------------------------------------------------------------- */ /* Create a temporary Z value if one is not provided. */ /* -------------------------------------------------------------------- */ if (z == null) { z = new double[xy.Length / 2]; } foreach (IDatumTransformStage idts in _aiDts) { if (idts.Method == TransformMethod.GridShift) { if (bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(idts.FromSpheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); bCoordsAreGeocentric = false; } var astrGrids = new string[1]; astrGrids[0] = "@" + idts.GridShiftTable; GridShift.Apply(astrGrids, idts.ApplyTableInverse, xy, startIndex, numPoints); } else { if (!bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(idts.FromSpheroid); gc.GeodeticToGeocentric(xy, z, startIndex, numPoints); bCoordsAreGeocentric = true; } ApplyParameterizedTransform(idts, xy, z, startIndex, numPoints); } } /* -------------------------------------------------------------------- */ /* Convert back to geodetic coordinates, if needed. */ /* -------------------------------------------------------------------- */ if (bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(_aiDts[_aiDts.Length - 1].ToSpheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); } }
/// <summary> /// /// </summary> /// <param name="xy">The xy array should be in interleaved set of xy coordinates like [x1, y1, x2, y2, ... xn, yn]</param> /// <param name="z">The z array is the array of all the z values</param> /// <param name="source"></param> /// <param name="srcZtoMeter"></param> /// <param name="dest"></param> /// <param name="dstZtoMeter"></param> /// <param name="idt"></param> /// <param name="startIndex"></param> /// <param name="numPoints"></param> public static void ReprojectPoints(double[] xy, double[] z, ProjectionInfo source, double srcZtoMeter, ProjectionInfo dest, double dstZtoMeter, IDatumTransform idt, int startIndex, int numPoints) { double toMeter = source.Unit.Meters; // Geocentric coordinates are centered at the core of the earth. Z is up toward the north pole. // The X axis goes from the center of the earth through Greenwich. // The Y axis passes through 90E. // This section converts from geocentric coordinates to geodetic ones if necessary. if (source.IsGeocentric) { if (z == null) { throw new ProjectionException(45); } for (int i = startIndex; i < numPoints; i++) { if (toMeter != 1) { xy[i * 2] *= toMeter; xy[i * 2 + 1] *= toMeter; } } GeocentricGeodetic g = new GeocentricGeodetic(source.GeographicInfo.Datum.Spheroid); g.GeocentricToGeodetic(xy, z, startIndex, numPoints); } // Transform source points to lam/phi if they are not already ConvertToLatLon(source, xy, z, srcZtoMeter, startIndex, numPoints); double fromGreenwich = source.GeographicInfo.Meridian.Longitude * source.GeographicInfo.Unit.Radians; if (fromGreenwich != 0) { for (int i = startIndex; i < numPoints; i++) { if (xy[2 * i] != double.PositiveInfinity) xy[2 * i] += fromGreenwich; } } // DATUM TRANSFORM IF NEEDED if (idt == null) { if (!source.GeographicInfo.Datum.Matches(dest.GeographicInfo.Datum)) { DatumTransform(source, dest, xy, z, startIndex, numPoints); } } else { idt.Transform(source, dest, xy, z, startIndex, numPoints); } // Adjust to new prime meridian if there is one in the destination cs fromGreenwich = dest.GeographicInfo.Meridian.Longitude * dest.GeographicInfo.Unit.Radians; if (fromGreenwich != 0) { for (int i = startIndex; i < numPoints; i++) { if (xy[i * 2] != double.PositiveInfinity) { xy[i * 2] -= fromGreenwich; } } } if (dest.IsGeocentric) { if (z == null) { throw new ProjectionException(45); } GeocentricGeodetic g = new GeocentricGeodetic(dest.GeographicInfo.Datum.Spheroid); g.GeodeticToGeocentric(xy, z, startIndex, numPoints); double frmMeter = 1 / dest.Unit.Meters; if (frmMeter != 1) { for (int i = startIndex; i < numPoints; i++) { if (xy[i * 2] != double.PositiveInfinity) { xy[i * 2] *= frmMeter; xy[i * 2 + 1] *= frmMeter; } } } } else { ConvertToProjected(dest, xy, z, dstZtoMeter, startIndex, numPoints); } }
public static void ReprojectPoints(double[] xy, double[] z, ProjectionInfo source, double srcZtoMeter, ProjectionInfo dest, double dstZtoMeter, IDatumTransform idt, int startIndex, int numPoints) { double toMeter = source.Unit.Meters; // Geocentric coordinates are centered at the core of the earth. Z is up toward the north pole. // The X axis goes from the center of the earth through Greenwich. // The Y axis passes through 90E. // This section converts from geocentric coordinates to geodetic ones if necessary. if (source.IsGeocentric) { if (z == null) { throw new ProjectionException(45); } for (int i = startIndex; i < numPoints; i++) { if (toMeter != 1) { xy[i * 2] *= toMeter; xy[i * 2 + 1] *= toMeter; } } GeocentricGeodetic g = new GeocentricGeodetic(source.GeographicInfo.Datum.Spheroid); g.GeocentricToGeodetic(xy, z, startIndex, numPoints); } // Transform source points to lam/phi if they are not already ConvertToLatLon(source, xy, z, srcZtoMeter, startIndex, numPoints); double fromGreenwich = source.GeographicInfo.Meridian.Longitude * source.GeographicInfo.Unit.Radians; if (fromGreenwich != 0) { for (int i = startIndex; i < numPoints; i++) { if (xy[2 * i] != double.PositiveInfinity) { xy[2 * i] += fromGreenwich; } } } // DATUM TRANSFORM IF NEEDED if (idt == null) { if (!source.GeographicInfo.Datum.Matches(dest.GeographicInfo.Datum)) { DatumTransform(source, dest, xy, z, startIndex, numPoints); } } else { idt.Transform(source, dest, xy, z, startIndex, numPoints); } // Adjust to new prime meridian if there is one in the destination cs fromGreenwich = dest.GeographicInfo.Meridian.Longitude * dest.GeographicInfo.Unit.Radians; if (fromGreenwich != 0) { for (int i = startIndex; i < numPoints; i++) { if (xy[i * 2] != double.PositiveInfinity) { xy[i * 2] -= fromGreenwich; } } } if (dest.IsGeocentric) { if (z == null) { throw new ProjectionException(45); } GeocentricGeodetic g = new GeocentricGeodetic(dest.GeographicInfo.Datum.Spheroid); g.GeodeticToGeocentric(xy, z, startIndex, numPoints); double frmMeter = 1 / dest.Unit.Meters; if (frmMeter != 1) { for (int i = startIndex; i < numPoints; i++) { if (xy[i * 2] != double.PositiveInfinity) { xy[i * 2] *= frmMeter; xy[i * 2 + 1] *= frmMeter; } } } } else { ConvertToProjected(dest, xy, z, dstZtoMeter, startIndex, numPoints); } }
private static void DatumTransform(ProjectionInfo source, ProjectionInfo dest, double[] xy, double[] z, int startIndex, int numPoints) { Spheroid wgs84 = new Spheroid(Proj4Ellipsoid.WGS_1984); Datum sDatum = source.GeographicInfo.Datum; Datum dDatum = dest.GeographicInfo.Datum; /* -------------------------------------------------------------------- */ /* We cannot do any meaningful datum transformation if either */ /* the source or destination are of an unknown datum type */ /* (ie. only a +ellps declaration, no +datum). This is new */ /* behavior for PROJ 4.6.0. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.Unknown || dDatum.DatumType == DatumType.Unknown) { return; } /* -------------------------------------------------------------------- */ /* Short cut if the datums are identical. */ /* -------------------------------------------------------------------- */ if (sDatum.Matches(dDatum)) { return; } // proj4 actually allows some tollerance here if (sDatum.DatumType == dDatum.DatumType) { if (sDatum.Spheroid.EquatorialRadius == dDatum.Spheroid.EquatorialRadius) { if (Math.Abs(sDatum.Spheroid.EccentricitySquared() - dDatum.Spheroid.EccentricitySquared()) < 0.000000000050) { // The tolerence is to allow GRS80 and WGS84 to escape without being transformed at all. return; } } } double srcA = sDatum.Spheroid.EquatorialRadius; double srcEs = sDatum.Spheroid.EccentricitySquared(); double dstA = dDatum.Spheroid.EquatorialRadius; double dstEs = dDatum.Spheroid.EccentricitySquared(); /* -------------------------------------------------------------------- */ /* Create a temporary Z value if one is not provided. */ /* -------------------------------------------------------------------- */ if (z == null) { z = new double[xy.Length / 2]; } /* -------------------------------------------------------------------- */ /* If this datum requires grid shifts, then apply it to geodetic */ /* coordinates. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.GridShift) { // pj_apply_gridshift(pj_param(srcdefn->params,"snadgrids").s, 0, // point_count, point_offset, x, y, z ); GridShift.Apply(source.GeographicInfo.Datum.NadGrids, false, xy, startIndex, numPoints); srcA = wgs84.EquatorialRadius; srcEs = wgs84.EccentricitySquared(); } if (dDatum.DatumType == DatumType.GridShift) { dstA = wgs84.EquatorialRadius; dstEs = wgs84.EccentricitySquared(); } /* ==================================================================== */ /* Do we need to go through geocentric coordinates? */ /* ==================================================================== */ if (srcEs != dstEs || srcA != dstA || sDatum.DatumType == DatumType.Param3 || sDatum.DatumType == DatumType.Param7 || dDatum.DatumType == DatumType.Param3 || dDatum.DatumType == DatumType.Param7) { /* -------------------------------------------------------------------- */ /* Convert to geocentric coordinates. */ /* -------------------------------------------------------------------- */ GeocentricGeodetic gc = new GeocentricGeodetic(sDatum.Spheroid); gc.GeodeticToGeocentric(xy, z, startIndex, numPoints); /* -------------------------------------------------------------------- */ /* Convert between datums. */ /* -------------------------------------------------------------------- */ if (sDatum.DatumType == DatumType.Param3 || sDatum.DatumType == DatumType.Param7) { PjGeocentricToWgs84(source, xy, z, startIndex, numPoints); } if (dDatum.DatumType == DatumType.Param3 || dDatum.DatumType == DatumType.Param7) { PjGeocentricFromWgs84(dest, xy, z, startIndex, numPoints); } /* -------------------------------------------------------------------- */ /* Convert back to geodetic coordinates. */ /* -------------------------------------------------------------------- */ gc = new GeocentricGeodetic(dDatum.Spheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); } /* -------------------------------------------------------------------- */ /* Apply grid shift to destination if required. */ /* -------------------------------------------------------------------- */ if (dDatum.DatumType == DatumType.GridShift) { // pj_apply_gridshift(pj_param(dstdefn->params,"snadgrids").s, 1, // point_count, point_offset, x, y, z ); GridShift.Apply(dest.GeographicInfo.Datum.NadGrids, true, xy, startIndex, numPoints); } }
public void GeocentricAfterDatumTest() { double[] xy = new double[2]; xy[0] = 4257349.7546790326000000; xy[1] = 401477.6657818287500000; double[] z = new double[1]; z[0] = 4716473.1891765557000000; Spheroid s = new Spheroid(Proj4Ellipsoid.WGS_1984); GeocentricGeodetic gc = new GeocentricGeodetic(s); gc.GeocentricToGeodetic(xy, z, 0, 1); }
/// <summary> /// datum tranform method /// </summary> /// <param name="source"></param> /// <param name="dest"></param> /// <param name="xy"></param> /// <param name="z"></param> /// <param name="startIndex"></param> /// <param name="numPoints"></param> public void Transform(ProjectionInfo source, ProjectionInfo dest, double[] xy, double[] z, int startIndex, int numPoints) { if (_aiDts.Length == 0) return; // "empty" datum transform bool bCoordsAreGeocentric = false; /* -------------------------------------------------------------------- */ /* Create a temporary Z value if one is not provided. */ /* -------------------------------------------------------------------- */ if (z == null) { z = new double[xy.Length / 2]; } foreach (IDatumTransformStage idts in _aiDts) { if (idts.Method == TransformMethod.GridShift) { if (bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(idts.FromSpheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); bCoordsAreGeocentric = false; } var astrGrids = new string[1]; astrGrids[0] = "@" + idts.GridShiftTable; GridShift.Apply(astrGrids, idts.ApplyTableInverse, xy, startIndex, numPoints); } else { if (!bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(idts.FromSpheroid); gc.GeodeticToGeocentric(xy, z, startIndex, numPoints); bCoordsAreGeocentric = true; } ApplyParameterizedTransform(idts, xy, z, startIndex, numPoints); } } /* -------------------------------------------------------------------- */ /* Convert back to geodetic coordinates, if needed. */ /* -------------------------------------------------------------------- */ if (bCoordsAreGeocentric) { var gc = new GeocentricGeodetic(_aiDts[_aiDts.Length - 1].ToSpheroid); gc.GeocentricToGeodetic(xy, z, startIndex, numPoints); } }