Repository: GEOSwift/GEOSwift (swift)

Issue:
WKT decimals precision
Hi,
there's a problem with the .wkt() function.
For example :
- I have a GeoJSON file with one point, with coordinates   x : -0.4225977, y : 46.3406448
- the GeoJSON object stores coordinates with a Double format. In debugger, values are x : -0.4225977**0000000002**, y : 46,3406448
- the string generated with wkt() contains the debugger values instead of the real ones
I think the generated string from my real data is twice the size it should be :(

Pull request:
Fixes #196

Also,

* Prepare release 6.1.0
* Simplify instructions for git workflow (eliminate `develop` branch)

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e707f7e4..3e5e4a95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 6.1.0
+
+* [#197](https://github.com/GEOSwift/GEOSwift/pull/197)
+    * Expose options to configure WKT writing (Fixes
+      [#196](https://github.com/GEOSwift/GEOSwift/issues/196))
+
 ## 6.0.0
 
 * [#187](https://github.com/GEOSwift/GEOSwift/pull/187)
diff --git a/GEOSwift.podspec b/GEOSwift.podspec
index f7a1978b..f6d6f883 100644
--- a/GEOSwift.podspec
+++ b/GEOSwift.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name = 'GEOSwift'
-  s.version = '6.0.0'
+  s.version = '6.1.0'
   s.swift_version = '5.1'
   s.cocoapods_version = '>= 1.4.0'
   s.summary = 'The Swift Geometry Engine.'
diff --git a/GEOSwift/GEOS/WKTConvertible.swift b/GEOSwift/GEOS/WKTConvertible.swift
index 00a45374..a886eef5 100644
--- a/GEOSwift/GEOS/WKTConvertible.swift
+++ b/GEOSwift/GEOS/WKTConvertible.swift
@@ -3,6 +3,8 @@ import geos
 
 public protocol WKTConvertible {
     func wkt() throws -> String
+
+    func wkt(useFixedPrecision: Bool, roundingPrecision: Int32) throws -> String
 }
 
 protocol WKTConvertibleInternal: WKTConvertible, GEOSObjectConvertible {}
@@ -10,7 +12,19 @@ protocol WKTConvertibleInternal: WKTConvertible, GEOSObjectConvertible {}
 extension WKTConvertibleInternal {
     public func wkt() throws -> String {
         let context = try GEOSContext()
-        let writer = try WKTWriter(context: context)
+        let writer = try WKTWriter(
+            context: context,
+            useFixedPrecision: .geosDefault,
+            roundingPrecision: .geosDefault)
+        return try writer.write(self)
+    }
+
+    public func wkt(useFixedPrecision: Bool, roundingPrecision: Int32) throws -> String {
+        let context = try GEOSContext()
+        let writer = try WKTWriter(
+            context: context,
+            useFixedPrecision: .custom(useFixedPrecision),
+            roundingPrecision: .custom(roundingPrecision))
         return try writer.write(self)
     }
 }
@@ -29,12 +43,22 @@ private final class WKTWriter {
     private let context: GEOSContext
     private let writer: OpaquePointer
 
-    init(context: GEOSContext) throws {
+    init(context: GEOSContext,
+         useFixedPrecision: UseFixedPrecision,
+         roundingPrecision: RoundingPrecision) throws {
         guard let writer = GEOSWKTWriter_create_r(context.handle) else {
             throw GEOSError.libraryError(errorMessages: context.errors)
         }
         self.context = context
         self.writer = writer
+
+        if case let .custom(value) = useFixedPrecision {
+            GEOSWKTWriter_setTrim_r(context.handle, writer, value ? 1 : 0)
+        }
+
+        if case let .custom(value) = roundingPrecision {
+            GEOSWKTWriter_setRoundingPrecision_r(context.handle, writer, value)
+        }
     }
 
     deinit {
@@ -49,4 +73,14 @@ private final class WKTWriter {
         defer { chars.deallocate() }
         return String(cString: chars)
     }
+
+    enum UseFixedPrecision {
+        case geosDefault
+        case custom(Bool)
+    }
+
+    enum RoundingPrecision {
+        case geosDefault
+        case custom(Int32)
+    }
 }
diff --git a/GEOSwift/Info.plist b/GEOSwift/Info.plist
index 2b0458d7..2de1d6ea 100644
--- a/GEOSwift/Info.plist
+++ b/GEOSwift/Info.plist
@@ -15,7 +15,7 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>6.0.0</string>
+	<string>6.1.0</string>
 	<key>CFBundleVersion</key>
 	<string>1</string>
 </dict>
diff --git a/README.md b/README.md
index f46f1b42..f8adebc8 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ at least controversial. Use of geos without dynamic linking is discouraged.
 
 1. Add the following to your Cartfile:
 
-        github "GEOSwift/GEOSwift" ~> 6.0.0
+        github "GEOSwift/GEOSwift" ~> 6.1.0
 
 2. Finish updating your project by following the [typical Carthage
 workflow](https://github.com/Carthage/Carthage#quick-start).
@@ -61,7 +61,7 @@ workflow](https://github.com/Carthage/Carthage#quick-start).
 
 1. Update the top-level dependencies in your `Package.swift` to include:
 
-        .package(url: "https://github.com/GEOSwift/GEOSwift.git", from: "6.0.0")
+        .package(url: "https://github.com/GEOSwift/GEOSwift.git", from: "6.1.0")
 
 2. Update the target dependencies in your `Package.swift` to include
 
@@ -139,12 +139,12 @@ found inside `GEOSwiftMapKit` workspace. Open the workspace in Xcode, build the
 To make a contribution:
 
 * Fork the repo
-* Start from the `develop` branch and create a branch with a name that describes
+* Start from the `master` branch and create a branch with a name that describes
   your contribution
 * Run `$ carthage update`
 * Sign in to travis-ci.org (if you've never signed in before, CI won't run to
   verify your pull request)
-* Push your branch and create a pull request to develop
+* Push your branch and create a pull request to `master`
 * One of the maintainers will review your code and may request changes
 * If your pull request is accepted, one of the maintainers should update the
   changelog before merging it


Test patch:
diff --git a/GEOSwiftTests/GEOS/WKTTests.swift b/GEOSwiftTests/GEOS/WKTTests.swift
index e48f0aba..8c72e4ec 100644
--- a/GEOSwiftTests/GEOS/WKTTests.swift
+++ b/GEOSwiftTests/GEOS/WKTTests.swift
@@ -89,4 +89,166 @@ final class WKTTests: XCTestCase {
         verifyInitWithEmptyWKT(type: GeometryCollection.self)
         verifyInitWithEmptyWKT(type: Geometry.self)
     }
+
+    func verifyWKTOptions<T>(wktConvertible: T,
+                             useFixedPrecision: Bool,
+                             roundingPrecision: Int32,
+                             expectedWKT: String,
+                             line: UInt = #line) where T: WKTConvertible {
+        let wktString = try? wktConvertible.wkt(
+            useFixedPrecision: useFixedPrecision,
+            roundingPrecision: roundingPrecision)
+
+        XCTAssertEqual(wktString, expectedWKT, line: line)
+    }
+
+    func testWKTOptionsWithoutFixedPrecisionAndALongFraction() {
+        let point = Point(x: 1.11111111111111111, y: 987654321.1234567890)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (1.1111111111111112 987654321.1234568357467651)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (1 987654321)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (1.1 987654321.1)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (1.11111 987654321.12346)")
+    }
+
+    func testWKTOptionsWithoutFixedPrecisionAndAShortFraction() {
+        let point = Point(x: 1, y: 987654321.1)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (1.0000000000000000 987654321.1000000238418579)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (1 987654321)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (1.0 987654321.1)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (1.00000 987654321.10000)")
+    }
+
+    func testWKTOptionsWithoutFixedPrecisionAndFractionalValues() {
+        let point = Point(x: 0.1, y: 0.0000001)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (0.1000000000000000 0.0000001000000000)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (0 0)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (0.1 0.0)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: false,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (0.10000 0.00000)")
+    }
+
+    func testWKTOptionsWithFixedPrecisionAndALongFraction() {
+        let point = Point(x: 1.11111111111111111, y: 987654321.1234567890)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (1.111111111111111 987654321.1234568)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (1 1e+09)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (1 1e+09)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (1.1111 9.8765e+08)")
+    }
+
+    func testWKTOptionsWithFixedPrecisionAndAShortFraction() {
+        let point = Point(x: 1, y: 987654321.1)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (1 987654321.1)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (1 1e+09)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (1 1e+09)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (1 9.8765e+08)")
+    }
+
+    func testWKTOptionsWithFixedPrecisionAndFractionalValues() {
+        let point = Point(x: 0.1, y: 0.000000123456)
+
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: -1,
+            expectedWKT: "POINT (0.1 1.23456e-07)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 0,
+            expectedWKT: "POINT (0.1 1e-07)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 1,
+            expectedWKT: "POINT (0.1 1e-07)")
+        verifyWKTOptions(
+            wktConvertible: point,
+            useFixedPrecision: true,
+            roundingPrecision: 5,
+            expectedWKT: "POINT (0.1 1.2346e-07)")
+    }
 }