diff --git a/src/ProjNet/CoordinateSystems/CoordinateSystemFactory.cs b/src/ProjNet/CoordinateSystems/CoordinateSystemFactory.cs
index 28d831d..d9e0b69 100644
--- a/src/ProjNet/CoordinateSystems/CoordinateSystemFactory.cs
+++ b/src/ProjNet/CoordinateSystems/CoordinateSystemFactory.cs
@@ -5,7 +5,7 @@
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
-//
+//
// ProjNet 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
@@ -13,12 +13,13 @@
// You should have received a copy of the GNU Lesser General Public License
// along with ProjNet; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Collections.Generic;
using System.Text;
using ProjNet.IO.CoordinateSystems;
+using ProjNet.IO.Wkt;
namespace ProjNet.CoordinateSystems
{
@@ -26,15 +27,15 @@ namespace ProjNet.CoordinateSystems
/// Builds up complex objects from simpler objects or values.
///
///
- /// CoordinateSystemFactory allows applications to make coordinate systems that
+ /// CoordinateSystemFactory allows applications to make coordinate systems that
/// is very flexible, whereas the other factories are easier to use.
/// So this Factory can be used to make 'special' coordinate systems.
- /// For example, the EPSG authority has codes for USA state plane coordinate systems
- /// using the NAD83 datum, but these coordinate systems always use meters. EPSG does not
+ /// For example, the EPSG authority has codes for USA state plane coordinate systems
+ /// using the NAD83 datum, but these coordinate systems always use meters. EPSG does not
/// have codes for NAD83 state plane coordinate systems that use feet units. This factory
/// lets an application create such a hybrid coordinate system.
///
- public class CoordinateSystemFactory
+ public class CoordinateSystemFactory
{
///
/// Creates an instance of this class
@@ -64,6 +65,12 @@ public CoordinateSystem CreateFromWkt(string WKT)
return info as CoordinateSystem;
}
+ public CoordinateSystem CreateFromWktNew(string WKT)
+ {
+ var info = WktToProjBuilder.ParseAndBuild(WKT);
+ return info as CoordinateSystem;
+ }
+
///
/// Creates a [NOT IMPLEMENTED].
@@ -83,11 +90,11 @@ public CompoundCoordinateSystem CreateCompoundCoordinateSystem(string name, Coor
///
/// Creates a .
///
- /// The units of the axes in the fitted coordinate system will be
+ /// The units of the axes in the fitted coordinate system will be
/// inferred from the units of the base coordinate system. If the affine map
/// performs a rotation, then any mixed axes must have identical units. For
- /// example, a (lat_deg,lon_deg,height_feet) system can be rotated in the
- /// (lat,lon) plane, since both affected axes are in degrees. But you
+ /// example, a (lat_deg,lon_deg,height_feet) system can be rotated in the
+ /// (lat,lon) plane, since both affected axes are in degrees. But you
/// should not rotate this coordinate system in any other plane.
/// Name of coordinate system
/// Base coordinate system
@@ -122,9 +129,9 @@ public FittedCoordinateSystem CreateFittedCoordinateSystem(string name, Coordina
/// Creates a local coordinate system.
///
///
- /// The dimension of the local coordinate system is determined by the size of
- /// the axis array. All the axes will have the same units. If you want to make
- /// a coordinate system with mixed units, then you can make a compound
+ /// The dimension of the local coordinate system is determined by the size of
+ /// the axis array. All the axes will have the same units. If you want to make
+ /// a coordinate system with mixed units, then you can make a compound
/// coordinate system from different local coordinate systems.
///
/// Name of local coordinate system
@@ -219,9 +226,9 @@ public IProjection CreateProjection(string name, string wktProjectionClass, List
/// Creates from ellipsoid and Bursa-World parameters.
///
///
- /// Since this method contains a set of Bursa-Wolf parameters, the created
+ /// Since this method contains a set of Bursa-Wolf parameters, the created
/// datum will always have a relationship to WGS84. If you wish to create a
- /// horizontal datum that has no relationship with WGS84, then you can
+ /// horizontal datum that has no relationship with WGS84, then you can
/// either specify a horizontalDatumType of , or create it via WKT.
///
/// Name of ellipsoid
@@ -294,7 +301,7 @@ public ILocalDatum CreateLocalDatum(string name, DatumType datumType)
///
/// Name of datum
/// Type of datum
- /// Vertical datum
+ /// Vertical datum
public VerticalDatum CreateVerticalDatum(string name, DatumType datumType)
{
if (string.IsNullOrWhiteSpace(name))
@@ -322,7 +329,7 @@ public VerticalCoordinateSystem CreateVerticalCoordinateSystem(string name, Vert
}
///
- /// Creates a from a datum,
+ /// Creates a from a datum,
/// linear unit and .
///
/// Name of geocentric coordinate system
diff --git a/src/ProjNet/IO/Wkt/WktCrs.g4 b/src/ProjNet/IO/Wkt/WktCrs.g4
new file mode 100644
index 0000000..103b652
--- /dev/null
+++ b/src/ProjNet/IO/Wkt/WktCrs.g4
@@ -0,0 +1,275 @@
+/*
+ [The "BSD licence"] Copyright (c) 2023 Nikolay Fiykov All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * For parsing propeties file (like GeoTools epsg.properties), use starting rule "propsFile". For parsing single WKT CRS definition, use starting rule "wkt".
+ */
+
+// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
+// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
+
+grammar WktCrs;
+
+
+propsFile
+ : propRow* EOF
+ ;
+
+propRow
+ : commentLine
+ | epsgDefLine
+ ;
+
+commentLine
+ : COMMENT_LINE
+ ;
+
+epsgDefLine
+ : epsgCode EQ wkt
+ ;
+
+wkt
+ : compdcs
+ | projcs
+ | geogcs
+ | vertcs
+ | geoccs
+ | localcs
+ | fittedcs
+ ;
+
+fittedcs
+ : 'FITTED_CS' LPAR name COMMA paramsmt COMMA projcs (COMMA authority)? RPAR
+ ;
+
+paramsmt
+ : 'PARAM_MT' LPAR name (COMMA parameter)+ RPAR
+ ;
+
+compdcs
+ : 'COMPD_CS' LPAR name COMMA (projcs | geogcs) COMMA vertcs COMMA authority RPAR
+ ;
+
+projcs
+ : 'PROJCS' LPAR name COMMA geogcs COMMA projection COMMA (parameter COMMA)+ unit COMMA ((extension COMMA) | (axis COMMA))* authority RPAR
+ ;
+
+geoccs
+ : 'GEOCCS' LPAR name COMMA datum COMMA primem COMMA unit COMMA (axis COMMA)+ authority RPAR
+ ;
+
+geogcs
+ : 'GEOGCS' LPAR name COMMA datum COMMA primem COMMA unit (COMMA axis)* (COMMA authority)? RPAR
+ ;
+
+vertcs
+ : 'VERT_CS' LPAR name COMMA vertdatum COMMA unit COMMA axis COMMA authority RPAR
+ ;
+
+localcs
+ : 'LOCAL_CS' LPAR name COMMA localdatum COMMA unit COMMA (axis COMMA)+ authority RPAR
+ ;
+
+datum
+ : 'DATUM' LPAR name COMMA spheroid ((COMMA towgs84) | (COMMA authority))* RPAR
+ ;
+
+vertdatum
+ : 'VERT_DATUM' LPAR name COMMA type COMMA authority RPAR
+ ;
+
+localdatum
+ : 'LOCAL_DATUM' LPAR name COMMA type (COMMA authority)? RPAR
+ ;
+
+spheroid
+ : 'SPHEROID' LPAR name COMMA semiMajorAxis COMMA inverseFlattening (COMMA authority)? RPAR
+ ;
+
+towgs84
+ : 'TOWGS84' LPAR dx COMMA dy COMMA dz (COMMA ex COMMA ey COMMA ez (COMMA ppm)?)? RPAR
+ ;
+
+extension
+ : 'EXTENSION' LPAR name COMMA projtext RPAR
+ ;
+
+authority
+ : 'AUTHORITY' LPAR authorityName COMMA code RPAR
+ ;
+
+primem
+ : 'PRIMEM' LPAR name COMMA longitude (COMMA unit)? (COMMA authority)? RPAR
+ ;
+
+unit
+ : 'UNIT' LPAR name COMMA conversionFactor (COMMA authority)? RPAR
+ ;
+
+axis
+ : 'AXIS' LPAR name COMMA axisOrient RPAR
+ ;
+
+projection
+ : 'PROJECTION' LPAR name (COMMA authority)? RPAR
+ ;
+
+parameter
+ : 'PARAMETER' LPAR name COMMA value RPAR
+ ;
+
+authorityName
+ : '"EPSG"'
+ | '"ESRI"'
+ ;
+
+axisOrient
+ : 'EAST'
+ | 'WEST'
+ | 'NORTH'
+ | 'SOUTH'
+ | 'NORTH_EAST'
+ | 'NORTH_WEST'
+ | 'UP'
+ | 'DOWN'
+ | 'OTHER'
+ | 'GEOCENTRIC_X'
+ | 'GEOCENTRIC_Y'
+ | 'GEOCENTRIC_Z'
+ | name
+ ;
+
+epsgCode
+ : PKEY
+ | NUMBER
+ ;
+
+name
+ : TEXT
+ ;
+
+number
+ : NUMBER
+ ;
+
+type
+ : NUMBER
+ ;
+
+semiMajorAxis
+ : NUMBER
+ ;
+
+inverseFlattening
+ : NUMBER
+ ;
+
+dx
+ : NUMBER
+ ;
+
+dy
+ : NUMBER
+ ;
+
+dz
+ : NUMBER
+ ;
+
+ex
+ : NUMBER
+ ;
+
+ey
+ : NUMBER
+ ;
+
+ez
+ : NUMBER
+ ;
+
+ppm
+ : NUMBER
+ ;
+
+projtext
+ : TEXT
+ ;
+
+code
+ : TEXT
+ | NUMBER
+ ;
+
+longitude
+ : NUMBER
+ ;
+
+conversionFactor
+ : NUMBER
+ ;
+
+value
+ : NUMBER
+ ;
+
+NUMBER
+ : PM? INT ('.' INT)? EXP?
+ ;
+
+TEXT
+ : '"' ('""' | ~'"')* '"'
+ ;
+
+PKEY
+ : [A-Z] [0-9A-Z]+
+ ;
+
+COMMENT_LINE
+ : '#' ~[\r\n]*
+ ;
+
+WS
+ : [ \r\n\t]+ -> skip
+ ;
+
+COMMA
+ : ','
+ ;
+
+LPAR
+ : '['
+ | '('
+ ;
+
+RPAR
+ : ']'
+ | ')'
+ ;
+
+EQ
+ : '='
+ ;
+
+fragment INT
+ : [0-9]+
+ ;
+
+fragment EXP
+ : [Ee] PM? INT
+ ;
+
+fragment PM
+ : '+'
+ | '-'
+ ;
\ No newline at end of file
diff --git a/src/ProjNet/IO/Wkt/WktToProjBuilder.cs b/src/ProjNet/IO/Wkt/WktToProjBuilder.cs
new file mode 100644
index 0000000..7f444fd
--- /dev/null
+++ b/src/ProjNet/IO/Wkt/WktToProjBuilder.cs
@@ -0,0 +1,1144 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using Antlr4.Runtime;
+using Antlr4.Runtime.Atn;
+using Antlr4.Runtime.Misc;
+using ProjNet.CoordinateSystems;
+using ProjNet.CoordinateSystems.Transformations;
+
+namespace ProjNet.IO.Wkt
+{
+ ///
+ /// WktToProjBuilder
+ ///
+ public partial class WktToProjBuilder
+ {
+ private readonly CoordinateSystemFactory factory;
+
+ ///
+ /// Constructor.
+ ///
+ public WktToProjBuilder()
+ {
+ factory = new CoordinateSystemFactory();
+ }
+
+
+ internal class Authority
+ {
+ public string Name { get; set; }
+
+ public int Code { get; set; }
+ }
+
+
+ internal class NameVisitor : WktCrsBaseVisitor
+ {
+ public static readonly NameVisitor Instance = new NameVisitor();
+
+ public override string VisitName(WktCrsParser.NameContext context)
+ {
+ return context.GetText().Trim(new char[] {'\"', ' '});
+ }
+ }
+
+
+ internal class ValueVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ValueVisitor Instance = new ValueVisitor();
+
+ public override double VisitValue(WktCrsParser.ValueContext context)
+ {
+ string valueStr = context.GetText();
+ if (double.TryParse(valueStr, NumberStyles.Any, CultureInfo.InvariantCulture, out double d))
+ return d;
+
+ return double.NaN;
+ }
+ }
+
+
+ ///
+ /// LongitudeVisitor
+ ///
+ public class LongitudeVisitor : WktCrsBaseVisitor
+ {
+ ///
+ /// VisitLongitude
+ ///
+ ///
+ ///
+ public override double VisitLongitude(WktCrsParser.LongitudeContext context)
+ {
+ string valueStr = context.GetText();
+ if (double.TryParse(valueStr, NumberStyles.Any, CultureInfo.InvariantCulture, out double d))
+ return d;
+
+ return double.NaN;
+ }
+ }
+
+ internal class AuthorityNameVisitor : WktCrsBaseVisitor
+ {
+ public static readonly AuthorityNameVisitor Instance = new AuthorityNameVisitor();
+
+ public override string VisitAuthorityName(WktCrsParser.AuthorityNameContext context)
+ {
+ return context.GetText().Trim(new char[] {'\"', ' '});
+ }
+ }
+
+
+ internal class AuthorityCodeVisitor : WktCrsBaseVisitor
+ {
+ public static readonly AuthorityCodeVisitor Instance = new AuthorityCodeVisitor();
+
+ public override int VisitCode(WktCrsParser.CodeContext context)
+ {
+ if (!context.IsEmpty)
+ {
+ string codeStr = context.GetText();
+ codeStr = codeStr.Trim(new char[] {' ', '\"'});
+ if (codeStr.Contains("_"))
+ {
+ codeStr = codeStr.Substring(0, codeStr.IndexOf('_'));
+ }
+
+ if (!string.IsNullOrWhiteSpace(codeStr) && int.TryParse(codeStr, NumberStyles.Any,
+ CultureInfo.InvariantCulture, out int nmbr))
+ {
+ return nmbr;
+ }
+ }
+
+ return -1;
+ }
+ }
+
+
+ internal class ProjTextVisitor : WktCrsBaseVisitor
+ {
+ public override string VisitProjtext(WktCrsParser.ProjtextContext context)
+ {
+ string str = context.GetText();
+ str = str.Trim(new char[] {' ', '\"'});
+ return str;
+ }
+ }
+
+ internal class AxisOrientVisitor : WktCrsBaseVisitor
+ {
+ public override AxisOrientationEnum VisitAxisOrient(WktCrsParser.AxisOrientContext context)
+ {
+
+ if (!context.IsEmpty)
+ {
+ string direction = context.GetText().Trim(new char[] {' ', '\"'});
+ if (Enum.TryParse(direction, true, out AxisOrientationEnum enumVal))
+ {
+ return enumVal;
+ }
+ }
+
+ return AxisOrientationEnum.Other;
+ }
+ }
+
+
+ internal class AuthorityVisitor : WktCrsBaseVisitor
+ {
+ public static readonly AuthorityVisitor Instance = new AuthorityVisitor();
+
+ public override Authority VisitAuthority([NotNull] WktCrsParser.AuthorityContext context)
+ {
+ string authName = string.Empty;
+ var authNameCtx = context.authorityName();
+ if (authNameCtx != null)
+ {
+ var visitor = AuthorityNameVisitor.Instance;
+ authName = visitor.VisitAuthorityName(authNameCtx);
+ }
+
+ int code = -1;
+ var authCodeCtx = context.code();
+ if (authCodeCtx != null)
+ {
+ var visitor = AuthorityCodeVisitor.Instance;
+ code = visitor.VisitCode(authCodeCtx);
+ }
+
+ return new Authority {Name = authName, Code = code};
+ }
+ }
+
+ internal class AxisVisitor : WktCrsBaseVisitor
+ {
+ public static readonly AxisVisitor Instance = new AxisVisitor();
+
+ public override AxisInfo VisitAxis(WktCrsParser.AxisContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ var orient = AxisOrientationEnum.Other;
+ var axisOrientCtx = context.axisOrient();
+ if (axisOrientCtx != null)
+ {
+ var visitor = new AxisOrientVisitor();
+ orient = visitor.VisitAxisOrient(axisOrientCtx);
+ }
+
+ return new AxisInfo(name, orient);
+ }
+ }
+
+ internal class ExtensionVisitor : WktCrsBaseVisitor<(string, string)>
+ {
+ public static readonly ExtensionVisitor Instance = new ExtensionVisitor();
+
+ public override (string, string) VisitExtension([NotNull] WktCrsParser.ExtensionContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ string projText = string.Empty;
+ var projCtx = context.projtext();
+ if (projCtx != null)
+ {
+ var visitor = new ProjTextVisitor();
+ projText = visitor.VisitProjtext(projCtx);
+ }
+
+ // No ProjNet object for Extension so returning a tuple.
+ return (name, projText);
+ }
+ }
+
+
+ internal class ToWgs84Visitor : WktCrsBaseVisitor
+ {
+ public static readonly ToWgs84Visitor Instance = new ToWgs84Visitor();
+
+ public override Wgs84ConversionInfo VisitTowgs84(WktCrsParser.Towgs84Context context)
+ {
+ double dx = 0.0d;
+ var dxCtx = context.dx();
+ if (!dxCtx.IsEmpty && double.TryParse(dxCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double dxResult))
+ dx = dxResult;
+
+ double dy = 0.0d;
+ var dyCtx = context.dy();
+ if (!dyCtx.IsEmpty && double.TryParse(dyCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double dyResult))
+ dy = dyResult;
+
+ double dz = 0.0d;
+ var dzCtx = context.dz();
+ if (!dzCtx.IsEmpty && double.TryParse(dzCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double dzResult))
+ dz = dzResult;
+
+ double ex = 0.0d;
+ var exCtx = context.ex();
+ if (!exCtx.IsEmpty && double.TryParse(exCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double exResult))
+ ex = exResult;
+
+ double ey = 0.0d;
+ var eyCtx = context.ey();
+ if (!eyCtx.IsEmpty && double.TryParse(eyCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double eyResult))
+ ey = eyResult;
+
+ double ez = 0.0d;
+ var ezCtx = context.ez();
+ if (!ezCtx.IsEmpty && double.TryParse(ezCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double ezResult))
+ ez = ezResult;
+
+ double ppm = 0.0d;
+ var ppmCtx = context.ppm();
+ if (ppmCtx.IsEmpty && double.TryParse(ppmCtx.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double ppmResult))
+ ppm = ppmResult;
+
+ return new Wgs84ConversionInfo(dx, dy, dz, ex, ey, ez, ppm);
+ }
+ }
+
+
+ internal class ProjectionVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ProjectionVisitor Instance = new ProjectionVisitor();
+
+ public override Projection VisitProjection(WktCrsParser.ProjectionContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ return new Projection(name, new List(), name, authority?.Name,
+ authority != null ? authority.Code : -1, string.Empty, string.Empty, string.Empty);
+ }
+ }
+
+ internal class ProjectionParameterVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ProjectionParameterVisitor Instance = new ProjectionParameterVisitor();
+
+ public override ProjectionParameter VisitParameter(WktCrsParser.ParameterContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ double value = double.NaN;
+ var valueCtx = context.value();
+ if (valueCtx != null)
+ {
+ var visitor = ValueVisitor.Instance;
+ value = visitor.VisitValue(valueCtx);
+ }
+
+ return new ProjectionParameter(name, value);
+ }
+ }
+
+ internal class ParameterVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ParameterVisitor Instance = new ParameterVisitor();
+
+ public override Parameter VisitParameter(WktCrsParser.ParameterContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ double value = double.NaN;
+ var valueCtx = context.value();
+ if (valueCtx != null)
+ {
+ var visitor = ValueVisitor.Instance;
+ value = visitor.VisitValue(valueCtx);
+ }
+
+ return new Parameter(name, value);
+ }
+ }
+
+ internal class SemiMajorAxisVisitor : WktCrsBaseVisitor
+ {
+ public static readonly SemiMajorAxisVisitor Instance = new SemiMajorAxisVisitor();
+
+ public override double VisitSemiMajorAxis(WktCrsParser.SemiMajorAxisContext context)
+ {
+ if (!context.IsEmpty && double.TryParse(context.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double d))
+ return d;
+ return double.NaN;
+ }
+ }
+
+ internal class InverseFlatteningVisitor : WktCrsBaseVisitor
+ {
+ public static readonly InverseFlatteningVisitor Instance = new InverseFlatteningVisitor();
+
+ public override double VisitInverseFlattening(WktCrsParser.InverseFlatteningContext context)
+ {
+ if (!context.IsEmpty && double.TryParse(context.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double d))
+ return d;
+ return double.NaN;
+ }
+ }
+
+
+ internal class SpheroidVisitor : WktCrsBaseVisitor
+ {
+ public static readonly SpheroidVisitor Instance = new SpheroidVisitor();
+
+ public override Ellipsoid VisitSpheroid(WktCrsParser.SpheroidContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ double semiMajorAxis = double.NaN;
+ var smaCtx = context.semiMajorAxis();
+ if (smaCtx != null)
+ {
+ var visitor = new SemiMajorAxisVisitor();
+ semiMajorAxis = visitor.VisitSemiMajorAxis(smaCtx);
+ }
+
+ double inverseFlattening = double.NaN;
+ var invfCtx = context.inverseFlattening();
+ if (invfCtx != null)
+ {
+ var visitor = new InverseFlatteningVisitor();
+ inverseFlattening = visitor.VisitInverseFlattening(invfCtx);
+ }
+
+ Authority authority = null;
+ var authCtx = context.authority();
+ if (authCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.Visit(authCtx);
+ }
+
+ return new Ellipsoid(semiMajorAxis, 0.0, inverseFlattening, true, LinearUnit.Metre, name,
+ authority?.Name, authority != null ? authority.Code : -1, string.Empty, string.Empty, string.Empty);
+
+ }
+ }
+
+
+ internal class ConversionFactorVisitor : WktCrsBaseVisitor
+ {
+ public override double VisitConversionFactor(WktCrsParser.ConversionFactorContext context)
+ {
+ if (!context.IsEmpty && double.TryParse(context.GetText(), NumberStyles.Any,
+ CultureInfo.InvariantCulture, out double d))
+ return d;
+ return double.NaN;
+ }
+ }
+
+
+ internal class DatumVisitor : WktCrsBaseVisitor
+ {
+ public static readonly DatumVisitor Instance = new DatumVisitor();
+
+ private readonly CoordinateSystemFactory factory = new CoordinateSystemFactory();
+
+ public override HorizontalDatum VisitDatum(WktCrsParser.DatumContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ Ellipsoid spheroid = null;
+ var spheroidCtx = context.spheroid();
+ if (spheroidCtx != null)
+ {
+ var visitor = SpheroidVisitor.Instance;
+ spheroid = visitor.VisitSpheroid(spheroidCtx);
+ }
+
+ Wgs84ConversionInfo wgs84 = null;
+ var towgs84Ctx = context.towgs84();
+ if (towgs84Ctx != null && towgs84Ctx.Length>0)
+ {
+ var visitor = new ToWgs84Visitor();
+ wgs84 = visitor.VisitTowgs84(towgs84Ctx[0]);
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null && authorityCtx.Length>0)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx[0]);
+ }
+
+ var result = this.factory.CreateHorizontalDatum(
+ name, DatumType.HD_Geocentric, ellipsoid: spheroid, toWgs84: wgs84);
+
+ if (authority != null)
+ {
+ result.Authority = authority.Name;
+ result.AuthorityCode = authority.Code;
+ }
+
+ return result;
+ }
+ }
+
+ internal class UnitVisitor : WktCrsBaseVisitor
+ {
+ public override Unit VisitUnit(WktCrsParser.UnitContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ double factor = double.NaN;
+ var cfCtx = context.conversionFactor();
+ if (cfCtx != null)
+ {
+ var visitor = new ConversionFactorVisitor();
+ factor = visitor.VisitConversionFactor(cfCtx);
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ return new Unit(factor, name, authority?.Name, authority != null ? authority.Code : -1, string.Empty,
+ string.Empty, string.Empty);
+ }
+ }
+
+ internal class PrimemVisitor : WktCrsBaseVisitor
+ {
+ public static readonly PrimemVisitor Instance = new PrimemVisitor();
+
+ private readonly CoordinateSystemFactory factory = new CoordinateSystemFactory();
+
+ public override PrimeMeridian VisitPrimem(WktCrsParser.PrimemContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ double longitude = double.NaN;
+ var ltCtx = context.longitude();
+ if (ltCtx != null)
+ {
+ var visitor = new LongitudeVisitor();
+ longitude = visitor.VisitLongitude(ltCtx);
+ }
+
+ var au = AngularUnit.Degrees;
+ var unitCtx = context.unit();
+ if (unitCtx != null)
+ {
+ var visitor = new UnitVisitor();
+ var unit = visitor.VisitUnit(unitCtx);
+ if (unit != null && unit.Name.Equals("degree"))
+ {
+ au = new AngularUnit(unit.ConversionFactor, unit.Name, unit.Authority, unit.AuthorityCode,
+ string.Empty, string.Empty, string.Empty);
+ }
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ var result = this.factory.CreatePrimeMeridian(name, angularUnit: au, longitude: longitude);
+
+ if (authority is Authority authObj)
+ {
+ result.AuthorityCode = authObj.Code;
+ result.Authority = authObj.Name;
+ }
+
+ return result;
+ }
+ }
+
+
+ internal class GeographicCoordinateSystemVisitor : WktCrsBaseVisitor
+ {
+ public static readonly GeographicCoordinateSystemVisitor Instance = new GeographicCoordinateSystemVisitor();
+
+ private readonly CoordinateSystemFactory factory = new CoordinateSystemFactory();
+
+ public override GeographicCoordinateSystem VisitGeogcs(WktCrsParser.GeogcsContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ var au = AngularUnit.Degrees;
+ var unitCtx = context.unit();
+ if (unitCtx != null)
+ {
+ var visitor = new UnitVisitor();
+ var unit = visitor.VisitUnit(unitCtx);
+ if (unit != null && unit.Name.Equals("degree"))
+ {
+ au = new AngularUnit(unit.ConversionFactor, unit.Name, unit.Authority, unit.AuthorityCode,
+ string.Empty, string.Empty, string.Empty);
+ }
+ }
+
+ HorizontalDatum datum = null;
+ var datumCtx = context.datum();
+ if (datumCtx != null)
+ {
+ var visitor = DatumVisitor.Instance;
+ datum = visitor.VisitDatum(datumCtx);
+ }
+
+ PrimeMeridian pm = null;
+ var pmCtx = context.primem();
+ if (pmCtx != null)
+ {
+ var visitor = PrimemVisitor.Instance;
+ pm = visitor.VisitPrimem(pmCtx);
+ }
+
+ //This is default axis values if not specified.
+ var axVisitor = new AxisVisitor();
+ var axisCtx = context.axis();
+ var ax1 = axisCtx.Length > 0
+ ? axVisitor.VisitAxis(axisCtx[0])
+ : new AxisInfo("Lon", AxisOrientationEnum.East);
+ var ax2 = axisCtx.Length > 1
+ ? axVisitor.VisitAxis(axisCtx[1])
+ : new AxisInfo("Lat", AxisOrientationEnum.North);
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ var result = this.factory.CreateGeographicCoordinateSystem(name, au, (HorizontalDatum) datum,
+ (PrimeMeridian) pm, axis0: ax1, axis1: ax2);
+
+ if (authority is Authority authObj)
+ {
+ result.AuthorityCode = authObj.Code;
+ result.Authority = authObj.Name;
+ }
+
+ return result;
+ }
+ }
+
+ internal class GeocentricCoordinateSystemVisitor : WktCrsBaseVisitor
+ {
+ public static readonly GeocentricCoordinateSystemVisitor Instance = new GeocentricCoordinateSystemVisitor();
+
+ private readonly CoordinateSystemFactory factory = new CoordinateSystemFactory();
+
+ public override GeocentricCoordinateSystem VisitGeoccs(WktCrsParser.GeoccsContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ HorizontalDatum datum = null;
+ var datumCtx = context.datum();
+ if (datumCtx != null)
+ {
+ var visitor = DatumVisitor.Instance;
+ datum = visitor.VisitDatum(datumCtx);
+ }
+
+ PrimeMeridian meridian = null;
+ var pmCtx = context.primem();
+ if (pmCtx != null)
+ {
+ var visitor = PrimemVisitor.Instance;
+ meridian = visitor.VisitPrimem(pmCtx);
+ }
+
+ var lu = (LinearUnit) null;
+ var unitCtx = context.unit();
+ if (unitCtx != null)
+ {
+ var visitor = new UnitVisitor();
+ var u = visitor.VisitUnit(unitCtx);
+ if (u != null)
+ {
+ lu = new LinearUnit(u.ConversionFactor, u.Name, u.Authority, u.AuthorityCode, string.Empty,
+ string.Empty, string.Empty);
+ }
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ var result =
+ this.factory.CreateGeocentricCoordinateSystem(name, (HorizontalDatum) datum, lu,
+ (PrimeMeridian) meridian);
+
+ if (authority is Authority authObj)
+ {
+ result.AuthorityCode = authObj.Code;
+ result.Authority = authObj.Name;
+ }
+
+ return result;
+ }
+ }
+
+
+ internal class ProjectedCoordinateSystemVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ProjectedCoordinateSystemVisitor Instance = new ProjectedCoordinateSystemVisitor();
+
+ public override ProjectedCoordinateSystem VisitProjcs(WktCrsParser.ProjcsContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ GeographicCoordinateSystem gcs = null;
+ var gcsCtx = context.geogcs();
+ if (gcsCtx != null)
+ {
+ var visitor = GeographicCoordinateSystemVisitor.Instance;
+ gcs = visitor.VisitGeogcs(gcsCtx);
+ }
+
+ var lu = (LinearUnit) null;
+ var unitCtx = context.unit();
+ if (unitCtx != null)
+ {
+ var visitor = new UnitVisitor();
+ var u = visitor.VisitUnit(unitCtx);
+ if (u != null)
+ {
+ lu = new LinearUnit(u.ConversionFactor, u.Name, u.Authority, u.AuthorityCode, string.Empty,
+ string.Empty, string.Empty);
+ }
+ }
+
+ Projection p = null;
+ var projCtx = context.projection();
+ if (projCtx != null)
+ {
+ var visitor = new ProjectionVisitor();
+ p = visitor.VisitProjection(projCtx);
+ }
+
+
+ var axVisitor = new AxisVisitor();
+ var axisCtx = context.axis();
+ var ax1 = axisCtx.Length > 0
+ ? axVisitor.VisitAxis(axisCtx[0])
+ : new AxisInfo("X", AxisOrientationEnum.East);
+ var ax2 = axisCtx.Length > 1
+ ? axVisitor.VisitAxis(axisCtx[1])
+ : new AxisInfo("Y", AxisOrientationEnum.North);
+ var aa = new List {ax1, ax2};
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ var result = new ProjectedCoordinateSystem(gcs.HorizontalDatum, gcs, lu, p,
+ aa, name, authority?.Name, authority != null ? authority.Code : -1, string.Empty, string.Empty,
+ string.Empty);
+
+ return result;
+ }
+ }
+
+ internal class ParamsMathTransformVisitor : WktCrsBaseVisitor
+ {
+ public static readonly ParamsMathTransformVisitor Instance = new ParamsMathTransformVisitor();
+
+ public override AffineTransform VisitParamsmt(WktCrsParser.ParamsmtContext context)
+ {
+ string name = "";
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ var parameters = new List();
+ var paramCtx = context.parameter();
+ if (paramCtx != null)
+ {
+ var visitor = new ParameterVisitor();
+ parameters = paramCtx.Select(pc => visitor.VisitParameter(pc)).ToList();
+ }
+
+ if (name.Equals("Affine", StringComparison.InvariantCultureIgnoreCase) && parameters.Any())
+ {
+ /*
+ PARAM_MT[
+ "Affine",
+ PARAMETER["num_row",3],
+ PARAMETER["num_col",3],
+ PARAMETER["elt_0_0", 0.883485346527455],
+ PARAMETER["elt_0_1", -0.468458794848877],
+ PARAMETER["elt_0_2", 3455869.17937689],
+ PARAMETER["elt_1_0", 0.468458794848877],
+ PARAMETER["elt_1_1", 0.883485346527455],
+ PARAMETER["elt_1_2", 5478710.88035753],
+ PARAMETER["elt_2_2", 1]
+ ]
+ */
+
+
+ var p = parameters;
+ var rowParam = p.FirstOrDefault(x => x.Name == "num_row");
+ var colParam = p.FirstOrDefault(x => x.Name == "num_col");
+
+ if (rowParam == null)
+ {
+ throw new ArgumentNullException(nameof(rowParam),
+ "Affine transform does not contain 'num_row' parameter");
+ }
+
+ if (colParam == null)
+ {
+ throw new ArgumentNullException(nameof(colParam),
+ "Affine transform does not contain 'num_col' parameter");
+ }
+
+ int rowVal = (int) rowParam.Value;
+ int colVal = (int) colParam.Value;
+
+ if (rowVal <= 0)
+ {
+ throw new ArgumentException("Affine transform contains invalid value of 'num_row' parameter");
+ }
+
+ if (colVal <= 0)
+ {
+ throw new ArgumentException("Affine transform contains invalid value of 'num_col' parameter");
+ }
+
+ //creates working matrix;
+ double[,] matrix = new double[rowVal, colVal];
+
+ //simply process matrix values - no elt_ROW_COL parsing
+ foreach (var param in p)
+ {
+ if (param == null || param.Name == null)
+ {
+ continue;
+ }
+
+ switch (param.Name)
+ {
+ case "num_row":
+ case "num_col":
+ break;
+ case "elt_0_0":
+ matrix[0, 0] = param.Value;
+ break;
+ case "elt_0_1":
+ matrix[0, 1] = param.Value;
+ break;
+ case "elt_0_2":
+ matrix[0, 2] = param.Value;
+ break;
+ case "elt_0_3":
+ matrix[0, 3] = param.Value;
+ break;
+ case "elt_1_0":
+ matrix[1, 0] = param.Value;
+ break;
+ case "elt_1_1":
+ matrix[1, 1] = param.Value;
+ break;
+ case "elt_1_2":
+ matrix[1, 2] = param.Value;
+ break;
+ case "elt_1_3":
+ matrix[1, 3] = param.Value;
+ break;
+ case "elt_2_0":
+ matrix[2, 0] = param.Value;
+ break;
+ case "elt_2_1":
+ matrix[2, 1] = param.Value;
+ break;
+ case "elt_2_2":
+ matrix[2, 2] = param.Value;
+ break;
+ case "elt_2_3":
+ matrix[2, 3] = param.Value;
+ break;
+ case "elt_3_0":
+ matrix[3, 0] = param.Value;
+ break;
+ case "elt_3_1":
+ matrix[3, 1] = param.Value;
+ break;
+ case "elt_3_2":
+ matrix[3, 2] = param.Value;
+ break;
+ case "elt_3_3":
+ matrix[3, 3] = param.Value;
+ break;
+ }
+ }
+
+ //use "matrix" constructor to create transformation matrix
+ return new AffineTransform(matrix);
+ }
+
+ return null;
+ }
+ }
+
+
+ internal class FittedCoordinateSystemVisitor : WktCrsBaseVisitor
+ {
+ public static readonly FittedCoordinateSystemVisitor Instance = new FittedCoordinateSystemVisitor();
+
+ public override FittedCoordinateSystem VisitFittedcs(WktCrsParser.FittedcsContext context)
+ {
+ string name = string.Empty;
+ var nameCtx = context.name();
+ if (nameCtx != null)
+ {
+ var visitor = NameVisitor.Instance;
+ name = visitor.VisitName(nameCtx);
+ }
+
+ MathTransform mathTransform = null;
+ var pmtCtx = context.paramsmt();
+ if (pmtCtx != null)
+ {
+ var visitor = new ParamsMathTransformVisitor();
+ mathTransform = visitor.VisitParamsmt(pmtCtx);
+ }
+
+ ProjectedCoordinateSystem baseCS = null;
+ var projcsCtx = context.projcs();
+ if (projcsCtx != null)
+ {
+ var visitor = new ProjectedCoordinateSystemVisitor();
+ baseCS = visitor.VisitProjcs(projcsCtx);
+ }
+
+ Authority authority = null;
+ var authorityCtx = context.authority();
+ if (authorityCtx != null)
+ {
+ var visitor = AuthorityVisitor.Instance;
+ authority = visitor.VisitAuthority(authorityCtx);
+ }
+
+ var result = new FittedCoordinateSystem(baseCS, mathTransform, name, authority?.Name,
+ authority != null ? authority.Code : -1, string.Empty, string.Empty, string.Empty);
+
+ return result;
+ }
+ }
+
+
+ internal class WktCrsVisitor : WktCrsBaseVisitor
+ {
+ public static readonly WktCrsVisitor Instance = new WktCrsVisitor();
+
+ public override CoordinateSystem VisitWkt(WktCrsParser.WktContext context)
+ {
+ var projcsCtx = context.projcs();
+ if (projcsCtx != null)
+ {
+ var visitor = ProjectedCoordinateSystemVisitor.Instance;
+ return visitor.VisitProjcs(projcsCtx);
+ }
+
+ var gcsCtx = context.geogcs();
+ if (gcsCtx != null)
+ {
+ var visitor = GeographicCoordinateSystemVisitor.Instance;
+ return visitor.VisitGeogcs(gcsCtx);
+ }
+
+ var ccsCtx = context.geoccs();
+ if (ccsCtx != null)
+ {
+ var visitor = GeocentricCoordinateSystemVisitor.Instance;
+ return visitor.VisitGeoccs(ccsCtx);
+ }
+
+ //if (context.compdcs() != null)
+ //return (CoordinateSystem) Visit(context.compdcs());
+ var fcsCtx = context.fittedcs();
+ if (fcsCtx != null)
+ {
+ var visitor = FittedCoordinateSystemVisitor.Instance;
+ return visitor.VisitFittedcs(fcsCtx);
+ }
+ /*
+ else if (context.localcs()!=null)
+ return (CoordinateSystem) Visit(context.localcs());
+ else if (context.vertcs()!=null)
+ return (CoordinateSystem) Visit(context.vertcs());
+ */
+
+ return base.VisitWkt(context);
+ }
+ }
+
+ private static WktCrsLexer cachedLexer = null;
+ private static WktCrsParser cachedParser = null;
+
+
+ ///
+ /// ParseAndBuild
+ ///
+ ///
+ ///
+ public static CoordinateSystem ParseAndBuild(string input)
+ {
+ try
+ {
+ var stream = CharStreams.fromString(input);
+ var lexer = cachedLexer;
+ if (lexer == null)
+ {
+ lexer = new WktCrsLexer(stream);
+ cachedLexer = lexer;
+ }
+ else
+ {
+ lexer.SetInputStream(stream);
+ }
+
+ var tokens = new CommonTokenStream(lexer);
+
+ var parser = cachedParser;
+ if (parser == null)
+ {
+ parser = new WktCrsParser(tokens);
+ parser.BuildParseTree = true;
+ cachedParser = parser;
+ }
+ else
+ {
+ //parser.BuildParseTree = false;
+ parser.TokenStream = tokens;
+ }
+
+ parser.Interpreter.PredictionMode = Antlr4.Runtime.Atn.PredictionMode.SLL;
+
+ bool doProfile = false;
+ parser.Profile = doProfile;
+
+ var wktCtx = parser.wkt();
+ if (wktCtx != null)
+ {
+ var result = WktCrsVisitor.Instance.VisitWkt(wktCtx);
+
+ if (doProfile)
+ {
+ Console.WriteLine("Profile results: \n" + GetProfileInfo(parser));
+ }
+
+ return result;
+ }
+ }
+ catch (RecognitionException)
+ {
+ return null;
+ }
+ catch (ParseCanceledException)
+ {
+ return null;
+ }
+ return null;
+ }
+
+
+ private static string GetProfileInfo(WktCrsParser parser)
+ {
+ var sb = new StringBuilder();
+ sb.AppendFormat("{0,-35}", "rule");
+ sb.AppendFormat("{0,-15}", "time");
+ sb.AppendFormat("{0,-15}", "invocations");
+ sb.AppendFormat("{0,-15}", "lookahead");
+ sb.AppendFormat("{0,-15}", "lookahead(max)");
+ sb.AppendFormat("{0,-15}", "ambiguities");
+ sb.AppendFormat("{0,-15}", "errors");
+ sb.AppendLine();
+ foreach (var decisionInfo in parser.ParseInfo.getDecisionInfo())
+ {
+ var ds = parser.Atn.GetDecisionState(decisionInfo.decision);
+ string rule = parser.RuleNames[ds.ruleIndex];
+ if (decisionInfo.timeInPrediction > 0)
+ {
+ sb.AppendFormat("{0,-35}", rule);
+ sb.AppendFormat("{0,-15}", decisionInfo.timeInPrediction);
+ sb.AppendFormat("{0,-15}", decisionInfo.invocations);
+ sb.AppendFormat("{0,-15}", decisionInfo.SLL_TotalLook);
+ sb.AppendFormat("{0,-15}", decisionInfo.SLL_MaxLook);
+ sb.AppendFormat("{0,-15}", decisionInfo.ambiguities.Count);
+ sb.AppendFormat("{0,-15}", decisionInfo.errors.Count);
+ sb.AppendLine();
+ }
+ }
+
+ return sb.ToString();
+ }
+
+ }
+}
diff --git a/src/ProjNet/ProjNET.csproj b/src/ProjNet/ProjNET.csproj
index e5cfcda..442da61 100644
--- a/src/ProjNet/ProjNET.csproj
+++ b/src/ProjNet/ProjNET.csproj
@@ -25,7 +25,19 @@ Proj.NET performs point-to-point coordinate conversions between geodetic coordin
-
+
+ false
+ true
+ false
+ ProjNet.IO.Wkt
+ true
+
+
+
+
+
+
+
diff --git a/test/ProjNet.Tests/WKT/WktToProjBuilderTests.cs b/test/ProjNet.Tests/WKT/WktToProjBuilderTests.cs
new file mode 100644
index 0000000..f78cf18
--- /dev/null
+++ b/test/ProjNet.Tests/WKT/WktToProjBuilderTests.cs
@@ -0,0 +1,185 @@
+using System;
+using NUnit.Framework;
+using ProjNet.CoordinateSystems;
+using ProjNet.IO.Wkt;
+
+namespace ProjNET.Tests.WKT;
+
+public class WktToProjBuilderTests
+{
+
+ private readonly CoordinateSystemFactory _coordinateSystemFactory = new CoordinateSystemFactory();
+
+ private readonly WktToProjBuilder _wktBuilder = new WktToProjBuilder();
+
+
+ [Test]
+ public void TestProjectedCoordinateSystem_EPSG_2918()
+ {
+ const string wkt = "PROJCS[\"NAD83(HARN) / Texas Central (ftUS)\", "+
+ "GEOGCS[\"NAD83(HARN)\", " +
+ "DATUM[\"NAD83_High_Accuracy_Regional_Network\", "+
+ "SPHEROID[\"GRS 1980\", 6378137, 298.257222101, AUTHORITY[\"EPSG\", \"7019\"]], "+
+ "TOWGS84[725, 685, 536, 0, 0, 0, 0], " +
+ "AUTHORITY[\"EPSG\", \"6152\"]], "+
+ "PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\", \"8901\"]], "+
+ "UNIT[\"degree\", 0.0174532925199433, AUTHORITY[\"EPSG\", \"9122\"]], "+
+ "AUTHORITY[\"EPSG\", \"4152\"]], "+
+ "PROJECTION[\"Lambert_Conformal_Conic_2SP\"], " +
+ "PARAMETER[\"standard_parallel_1\", 31.883333333333], " +
+ "PARAMETER[\"standard_parallel_2\", 30.1166666667], " +
+ "PARAMETER[\"latitude_of_origin\", 29.6666666667], " +
+ "PARAMETER[\"central_meridian\", -100.333333333333], " +
+ "PARAMETER[\"false_easting\", 2296583.333], " +
+ "PARAMETER[\"false_northing\", 9842500], " +
+ "UNIT[\"US survey foot\", 0.304800609601219, AUTHORITY[\"EPSG\", \"9003\"]], "+
+ "AUTHORITY[\"EPSG\", \"2918\"]]";
+
+ var cs = WktToProjBuilder.ParseAndBuild(wkt);
+
+ Assert.IsNotNull(cs);
+ }
+
+
+ ///
+ /// This test reads in a file with 2671 pre-defined coordinate systems and projections,
+ /// and tries to parse them.
+ ///
+ [Test]
+ public void ParseAllWKTs()
+ {
+ int parseCount = 0;
+ foreach (var wkt in SRIDReader.GetSrids())
+ {
+ var cs1 = _coordinateSystemFactory.CreateFromWkt(wkt.Wkt);
+ Assert.IsNotNull(cs1, "Could not parse WKT: " + wkt);
+ var cs2 = _coordinateSystemFactory.CreateFromWkt(wkt.Wkt.Replace("[", "(").Replace("]", ")"));
+ Assert.That(cs1.EqualParams(cs2), Is.True);
+ parseCount++;
+ }
+ Assert.That(parseCount, Is.GreaterThan(2671), "Not all WKT was parsed");
+ }
+
+ ///
+ /// This test reads in a file with 2671 pre-defined coordinate systems and projections,
+ /// and tries to parse them.
+ ///
+ [Test]
+ public void ParseAllWKTs_ANTLR()
+ {
+ int parseCount = 0;
+ foreach (var wkt in SRIDReader.GetSrids())
+ {
+ var cs1 = WktToProjBuilder.ParseAndBuild(wkt.Wkt);
+ Assert.IsNotNull(cs1, "Could not parse WKT: " + wkt.Wkt);
+ var cs2 = WktToProjBuilder.ParseAndBuild(wkt.Wkt.Replace("[", "(").Replace("]", ")"));
+ Assert.IsNotNull(cs2, "Could not parse WKT: " + wkt.Wkt);
+ Assert.That(cs1.EqualParams(cs2), Is.True);
+ parseCount++;
+ }
+ Assert.That(parseCount, Is.GreaterThan(2671), "Not all WKT was parsed");
+ }
+
+
+
+ [Test]
+ public void ParseProjCSWithExtension()
+ {
+ string wkt = "PROJCS[\"Google Maps Global Mercator\"," +
+ "GEOGCS[\"WGS 84\"," +
+ "DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]]," +
+ "AUTHORITY[\"EPSG\",\"6326\"]]," +
+ "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]]," +
+ "UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]]," +
+ "AUTHORITY[\"EPSG\",\"4326\"]]," +
+ "PROJECTION[\"Mercator_2SP\"]," +
+ "PARAMETER[\"standard_parallel_1\",0]," +
+ "PARAMETER[\"latitude_of_origin\",0]," +
+ "PARAMETER[\"central_meridian\",0]," +
+ "PARAMETER[\"false_easting\",0]," +
+ "PARAMETER[\"false_northing\",0]," +
+ "UNIT[\"Meter\",1]," +
+ "EXTENSION[\"PROJ4\",\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs\"]," +
+ "AUTHORITY[\"EPSG\",\"900913\"]]";
+
+ var cs1 = WktToProjBuilder.ParseAndBuild(wkt);
+
+ Assert.IsNotNull(cs1);
+ }
+
+
+ [Test]
+ public void ParseProjCSWithoutExtension()
+ {
+ string wkt = "PROJCS[\"Google Maps Global Mercator\"," +
+ "GEOGCS[\"WGS 84\"," +
+ "DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]]," +
+ "AUTHORITY[\"EPSG\",\"6326\"]]," +
+ "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]]," +
+ "UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]]," +
+ "AUTHORITY[\"EPSG\",\"4326\"]]," +
+ "PROJECTION[\"Mercator_2SP\"]," +
+ "PARAMETER[\"standard_parallel_1\",0]," +
+ "PARAMETER[\"latitude_of_origin\",0]," +
+ "PARAMETER[\"central_meridian\",0]," +
+ "PARAMETER[\"false_easting\",0]," +
+ "PARAMETER[\"false_northing\",0]," +
+ "UNIT[\"Meter\",1]," +
+ "AUTHORITY[\"EPSG\",\"900913\"]]";
+
+ var cs1 = WktToProjBuilder.ParseAndBuild(wkt);
+
+ Assert.IsNotNull(cs1);
+ }
+
+
+ [Test]
+ public void TestFittedCoordinateSystemWkt ()
+ {
+ var fac = new CoordinateSystemFactory ();
+ FittedCoordinateSystem fcs = null;
+ string wkt = "FITTED_CS[\"Local coordinate system MNAU (based on Gauss-Krueger)\"," +
+ "PARAM_MT[\"Affine\"," +
+ "PARAMETER[\"num_row\",3],PARAMETER[\"num_col\",3],PARAMETER[\"elt_0_0\", 0.883485346527455],PARAMETER[\"elt_0_1\", -0.468458794848877],PARAMETER[\"elt_0_2\", 3455869.17937689],PARAMETER[\"elt_1_0\", 0.468458794848877],PARAMETER[\"elt_1_1\", 0.883485346527455],PARAMETER[\"elt_1_2\", 5478710.88035753],PARAMETER[\"elt_2_2\", 1]]," +
+ "PROJCS[\"DHDN / Gauss-Kruger zone 3\"," +
+ "GEOGCS[\"DHDN\"," +
+ "DATUM[\"Deutsches_Hauptdreiecksnetz\"," +
+ "SPHEROID[\"Bessel 1841\", 6377397.155, 299.1528128, AUTHORITY[\"EPSG\", \"7004\"]]," +
+ "TOWGS84[612.4, 77, 440.2, -0.054, 0.057, -2.797, 0.525975255930096]," +
+ "AUTHORITY[\"EPSG\", \"6314\"]]," +
+ "PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\", \"8901\"]]," +
+ "UNIT[\"degree\", 0.0174532925199433, AUTHORITY[\"EPSG\", \"9122\"]]," +
+ "AUTHORITY[\"EPSG\", \"4314\"]]," +
+ "PROJECTION[\"Transverse_Mercator\"]," +
+ "PARAMETER[\"latitude_of_origin\", 0]," +
+ "PARAMETER[\"central_meridian\", 9]," +
+ "PARAMETER[\"scale_factor\", 1]," +
+ "PARAMETER[\"false_easting\", 3500000]," +
+ "PARAMETER[\"false_northing\", 0]," +
+ "UNIT[\"metre\", 1, AUTHORITY[\"EPSG\", \"9001\"]]," +
+ "AUTHORITY[\"EPSG\", \"31467\"]]" +
+ "]";
+
+
+ try
+ {
+ //fcs = fac.CreateFromWkt (wkt) as FittedCoordinateSystem;
+ fcs = WktToProjBuilder.ParseAndBuild(wkt) as FittedCoordinateSystem;
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail ("Could not create fitted coordinate system from:\r\n" + wkt + "\r\n" + ex.Message);
+ }
+
+ Assert.That(fcs, Is.Not.Null);
+ Assert.That(fcs.ToBase(), Is.Not.Null.Or.Empty);
+ Assert.That(fcs.BaseCoordinateSystem, Is.Not.Null);
+
+ Assert.AreEqual ("Local coordinate system MNAU (based on Gauss-Krueger)", fcs.Name);
+ //Assert.AreEqual ("CUSTOM", fcs.Authority);
+ //Assert.AreEqual (123456, fcs.AuthorityCode);
+
+ Assert.AreEqual ("EPSG", fcs.BaseCoordinateSystem.Authority);
+ Assert.AreEqual (31467, fcs.BaseCoordinateSystem.AuthorityCode);
+ }
+}