diff --git a/ProjNet.IO.Wkt.Tests/Core/WktParserTests.cs b/ProjNet.IO.Wkt.Tests/Core/WktParserTests.cs
new file mode 100644
index 0000000..41a1dc2
--- /dev/null
+++ b/ProjNet.IO.Wkt.Tests/Core/WktParserTests.cs
@@ -0,0 +1,124 @@
+using NUnit.Framework;
+using Pidgin;
+using ProjNet.IO.Wkt.Core;
+
+namespace ProjNet.IO.Wkt.Tests.Core;
+
+public class WktParserTests
+{
+
+ [Test]
+ public void TestUnsignedIntegerParser()
+ {
+ // Arrange
+ string parserText01 = $@"210677";
+
+ // Act
+ uint parserResult01 = WktParser.UnsignedIntegerParser.ParseOrThrow(parserText01);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(210677));
+ }
+
+ [Test]
+ public void TestSignedIntegerParser()
+ {
+ // Arrange
+ string parserText01 = $@"+210677";
+ string parserText02 = $@"-210677";
+ string parserText03 = $@"210677";
+
+ // Act
+ int parserResult01 = WktParser.SignedIntegerParser.ParseOrThrow(parserText01);
+ int parserResult02 = WktParser.SignedIntegerParser.ParseOrThrow(parserText02);
+ int parserResult03 = WktParser.SignedIntegerParser.ParseOrThrow(parserText03);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(210677));
+ Assert.That(parserResult02, Is.EqualTo(-210677));
+ Assert.That(parserResult03, Is.EqualTo(210677));
+ }
+
+
+ [Test]
+ public void TestSignedNumericLiteralParser()
+ {
+ // Arrange
+ string parserText01 = "-100.333333333333";
+ string parserText02 = "+100.333333333333";
+ string parserText03 = "100.333333333333";
+ string parserText04 = ".333333333333";
+
+ // Act
+ double parserResult01 = WktParser.SignedNumericLiteralParser.ParseOrThrow(parserText01);
+ double parserResult02 = WktParser.SignedNumericLiteralParser.ParseOrThrow(parserText02);
+ double parserResult03 = WktParser.SignedNumericLiteralParser.ParseOrThrow(parserText03);
+ double parserResult04 = WktParser.SignedNumericLiteralParser.ParseOrThrow(parserText04);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(-100.333333333333));
+ Assert.That(parserResult02, Is.EqualTo(100.333333333333));
+ Assert.That(parserResult03, Is.EqualTo(100.333333333333));
+ Assert.That(parserResult04, Is.EqualTo(0.333333333333));
+ }
+
+ [Test]
+ public void TestExactNumericLiteralParser()
+ {
+ // Arrange
+ string parserText01 = $@"21.043";
+ string parserText02 = $@"0.043";
+ string parserText03 = $@".043";
+
+ // Act
+ double parserResult01 = WktParser.ExactNumericLiteralParser.ParseOrThrow(parserText01);
+ double parserResult02 = WktParser.ExactNumericLiteralParser.ParseOrThrow(parserText02);
+ double parserResult03 = WktParser.ExactNumericLiteralParser.ParseOrThrow(parserText03);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(21.043d));
+ Assert.That(parserResult02, Is.EqualTo(0.043d));
+ Assert.That(parserResult03, Is.EqualTo(0.043d));
+ }
+
+ [Test]
+ public void TestApproximateNumericLiteralParser()
+ {
+ // Arrange
+ string parserText01 = $@"21.04E-3";
+ string parserText02= $@"21.04E+3";
+ string parserText03 = $@"21.04E3";
+ string parserText04 = $@"0.04E3";
+ string parserText05 = $@".04E3";
+
+ // Act
+ double parserResult01 = WktParser.ApproximateNumericLiteralParser.ParseOrThrow(parserText01);
+ double parserResult02 = WktParser.ApproximateNumericLiteralParser.ParseOrThrow(parserText02);
+ double parserResult03 = WktParser.ApproximateNumericLiteralParser.ParseOrThrow(parserText03);
+ double parserResult04 = WktParser.ApproximateNumericLiteralParser.ParseOrThrow(parserText04);
+ double parserResult05 = WktParser.ApproximateNumericLiteralParser.ParseOrThrow(parserText05);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(0.02104d));
+ Assert.That(parserResult02, Is.EqualTo(21040d));
+ Assert.That(parserResult03, Is.EqualTo(21040d));
+ Assert.That(parserResult04, Is.EqualTo(40d));
+ Assert.That(parserResult05, Is.EqualTo(40d));
+ }
+
+ [Test]
+ public void TestQuotedNameParser()
+ {
+ // Arrange
+ string str01 = "MyTextString";
+ string parserText01 = $"\"{str01}\"";
+
+ // Act
+ string parserResult01 = WktParser.QuotedNameParser.ParseOrThrow(parserText01);
+
+ // Assert
+ Assert.That(parserResult01, Is.EqualTo(str01));
+ }
+
+
+}
diff --git a/ProjNet4GeoAPI.sln b/ProjNet4GeoAPI.sln
index 1da9334..0da5ecc 100644
--- a/ProjNet4GeoAPI.sln
+++ b/ProjNet4GeoAPI.sln
@@ -15,6 +15,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjNET.Tests", "test\ProjN
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjNet.Benchmark", "src\ProjNet.Benchmark\ProjNet.Benchmark.csproj", "{1E5D1CC5-8CFE-4C9D-9553-900469C57D6C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjNet.IO.Wkt", "src\ProjNet.IO.Wkt\ProjNet.IO.Wkt.csproj", "{50AAB59B-25FB-4E36-A31A-B22C62B2105E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjNet.IO.Wkt.Tests", "ProjNet.IO.Wkt.Tests\ProjNet.IO.Wkt.Tests.csproj", "{3E23D15C-56F1-4431-B241-FC17D2F54BBF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +37,14 @@ Global
{1E5D1CC5-8CFE-4C9D-9553-900469C57D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E5D1CC5-8CFE-4C9D-9553-900469C57D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E5D1CC5-8CFE-4C9D-9553-900469C57D6C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50AAB59B-25FB-4E36-A31A-B22C62B2105E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50AAB59B-25FB-4E36-A31A-B22C62B2105E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50AAB59B-25FB-4E36-A31A-B22C62B2105E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50AAB59B-25FB-4E36-A31A-B22C62B2105E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3E23D15C-56F1-4431-B241-FC17D2F54BBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3E23D15C-56F1-4431-B241-FC17D2F54BBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3E23D15C-56F1-4431-B241-FC17D2F54BBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3E23D15C-56F1-4431-B241-FC17D2F54BBF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/ProjNet.IO.Wkt/AssemblyInfo.cs b/src/ProjNet.IO.Wkt/AssemblyInfo.cs
new file mode 100644
index 0000000..9e13281
--- /dev/null
+++ b/src/ProjNet.IO.Wkt/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly:InternalsVisibleTo("ProjNet.IO.Wkt.Tests")]
diff --git a/src/ProjNet.IO.Wkt/Core/DefaultWktOutputFormatter.cs b/src/ProjNet.IO.Wkt/Core/DefaultWktOutputFormatter.cs
new file mode 100644
index 0000000..91d1dba
--- /dev/null
+++ b/src/ProjNet.IO.Wkt/Core/DefaultWktOutputFormatter.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace ProjNet.IO.Wkt.Core
+{
+ ///
+ /// DefaultWktOutputFormatter - Keeping output compact with original delimiters.
+ ///
+ public class DefaultWktOutputFormatter : IWktOutputFormatter
+ {
+ private int indentCounter = 0;
+
+ ///
+ public string Newline { get; } = null;
+ ///
+ public char? LeftDelimiter { get; } = null;
+ ///
+ public char? RightDelimiter { get; } = null;
+
+ ///
+ public string Separator { get; } = null;
+
+ ///
+ /// Indent chars. E.g. tab or spaces. Default null.
+ ///
+ public string Indent { get; } = null;
+
+ ///
+ public string ExtraWhitespace { get; } = null;
+
+
+ ///
+ /// Constructor with support for optional overriding the settings.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public DefaultWktOutputFormatter(
+ string newline = null,
+ char? leftDelimiter = null,
+ char? rightDelimiter = null,
+ string indent = null,
+ string extraWhitespace = null)
+ {
+ Newline = newline;
+ LeftDelimiter = leftDelimiter;
+ RightDelimiter = rightDelimiter;
+ Indent = indent;
+ ExtraWhitespace = extraWhitespace;
+ }
+
+
+ ///
+ public IWktOutputFormatter AppendKeyword(string text, StringBuilder result, bool indent = true)
+ {
+ if (indent)
+ this.AppendIndent(result);
+
+ result.Append(text);
+
+ this.IncreaseIndentCounter();
+
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendSeparator(StringBuilder result, bool keepInside = false)
+ {
+ string s = Separator ?? ",";
+ result.Append(s);
+ if (!keepInside)
+ {
+ this.AppendNewline(result);
+ }
+
+ return this;
+ }
+
+
+ ///
+ public IWktOutputFormatter Append(string text, StringBuilder result)
+ {
+ result.Append(text);
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter Append(long l, StringBuilder result)
+ {
+ result.Append(l);
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter Append(double d, StringBuilder result)
+ {
+ result.Append(d.ToString(CultureInfo.InvariantCulture));
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendNewline(StringBuilder result)
+ {
+ if (!string.IsNullOrEmpty(Newline))
+ {
+ result.Append(Newline);
+ }
+
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendQuotedText(string text, StringBuilder result)
+ {
+ result.Append($"\"{text}\"");
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendLeftDelimiter(char original, StringBuilder result)
+ {
+ if (LeftDelimiter != null)
+ result.Append(LeftDelimiter);
+ else
+ result.Append(original);
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendRightDelimiter(char original, StringBuilder result)
+ {
+ //this.AppendIndent(result);
+
+ if (RightDelimiter != null)
+ result.Append(RightDelimiter);
+ else
+ result.Append(original);
+
+ this.DecreaseIndentCounter();
+ //this.AppendNewline(result);
+
+ return this;
+ }
+
+ ///
+ public IWktOutputFormatter AppendExtraWhitespace(StringBuilder result)
+ {
+ if (!string.IsNullOrEmpty(ExtraWhitespace))
+ {
+ result.Append(ExtraWhitespace);
+ }
+
+ return this;
+ }
+
+ ///
+ /// Increasing the indentCounter.
+ ///
+ ///
+ public IWktOutputFormatter IncreaseIndentCounter()
+ {
+ indentCounter++;
+ return this;
+ }
+
+ ///
+ /// Decreasing the indentCounter.
+ ///
+ ///
+ public IWktOutputFormatter DecreaseIndentCounter()
+ {
+ indentCounter--;
+ return this;
+ }
+
+
+ ///
+ /// AppendIndent repeat Indent according to internal indentCounter.
+ ///
+ ///
+ ///
+ public IWktOutputFormatter AppendIndent(StringBuilder result)
+ {
+ if (!string.IsNullOrEmpty(Indent))
+ {
+ for (int i = 1; i <= indentCounter; i++)
+ {
+ result.Append(Indent);
+ }
+ }
+
+ return this;
+ }
+ }
+}
diff --git a/src/ProjNet.IO.Wkt/Core/IWktBuilder.cs b/src/ProjNet.IO.Wkt/Core/IWktBuilder.cs
new file mode 100644
index 0000000..34723b6
--- /dev/null
+++ b/src/ProjNet.IO.Wkt/Core/IWktBuilder.cs
@@ -0,0 +1,435 @@
+using System.Collections.Generic;
+using Pidgin;
+
+namespace ProjNet.IO.Wkt.Core
+{
+ ///
+ /// Interface for building/creating all Wkt related objects.
+ ///
+ public interface IWktBuilder
+ {
+ ///
+ /// Building the Authority object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildAuthority(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ int code,
+ char rightDelimiter
+ );
+
+ ///
+ /// Build the Axis object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildAxis(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ string direction,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the Extension object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildExtension(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ string direction,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the ToWgs84 object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildToWgs84(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ double dxShift,
+ double dyShift,
+ double dzShift,
+ double exRotation,
+ double eyRotation,
+ double ezRotation,
+ double ppmScaling,
+ string description,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the Projection object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildProjection(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ object authority,
+ char rightDelimiter);
+
+
+
+ ///
+ /// Build the (Projection) Parameter.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildProjectionParameter(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double value,
+ char rightDelimiter);
+
+ ///
+ /// Build the Ellipsoid object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildEllipsoid(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double semiMajorAxis,
+ double inverseFlattening,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the Spheroid object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildSpheroid(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double semiMajorAxis,
+ double inverseFlattening,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the primemeridian object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildPrimeMeridian(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double longitude,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build a Unit object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildUnit(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double factor,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build a LinearUnit object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildLinearUnit(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double factor,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build an AngularUnit object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildAngularUnit(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ double factor,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the Datum object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildDatum(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ object spheroid,
+ object toWgs84,
+ object authority,
+ char rightDelimiter);
+
+
+ ///
+ /// Build the GeographicCoordinateSystem object.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ object BuildGeographicCoordinateSystem(
+ int offset,
+ string keyword,
+ char leftDelimiter,
+ string name,
+ object datum,
+ object meridian,
+ object unit,
+ IEnumerable