/**
This file is created by Yu Dong (2023).
License : Apache 2.0
FileName : Polyline.cj
Author : Yu Dong
Version : 0.0.1
Date : 20230424
Note : First Commit
*/
/**
* @file
* Polyline
*/
package gistools.geometry
import std.math.*
import std.convert.*
import std.collection.*
import encoding.json.*
import encoding.json.stream.*
import serialization.serialization.*
import gistools.*
import gistools.base.*
/**
* Polyline
*
* @author Yu Dong
* @since 0.38.2
*/
public class Polyline <: Geometry & Serializable<Polyline>{
// the coordinates of the Polyline
public var coordinates : ArrayList<Coordinate>
/**
* The Property is to get the x coordinates
*
* @since 0.38.2
*/
public prop xs : ArrayList<Float64> {
get() {
ArrayList(coordinates.size, { i =>
coordinates[i].x
})
}
}
/**
* The Property is to get the y coordinates
*
* @since 0.38.2
*/
public prop ys : ArrayList<Float64> {
get() {
ArrayList(coordinates.size, { i =>
coordinates[i].y
})
}
}
/**
* The Function is init constructor
*
* @since 0.38.2
*/
public init() {
this.coordinates = ArrayList<Coordinate>()
this.spatialReference = SpatialReference.unknown()
}
/**
* The Function is init constructor
*
* @param coordinates of ArrayList<Coordinate>
*
* @since 0.38.2
*/
public init(coordinates : ArrayList<Coordinate>) {
if (coordinates.size < 2) {
throw Exception("the size of Coordinates is less than 2. ")
}
this.coordinates = coordinates
this.spatialReference = SpatialReference.unknown()
}
/**
* The Function is init constructor
*
* @param coordinates of ArrayList<Coordinate>
* @param sr of SpatialReference
*
* @since 0.38.2
*/
public init(coordinates : ArrayList<Coordinate>, sr : SpatialReference) {
if (coordinates.size < 2) {
throw Exception("the size of Coordinates is less than 2. ")
}
this.coordinates = coordinates
this.spatialReference = sr
}
/**
* The Function is to create polyline by array of coordinates
*
* @param arr of ArrayList<Array<Float64>>
*
* @return Type of ?Polyline
* @since 0.38.2
*/
public static func fromArray(arr : ArrayList<Array<Float64>>) : ?Polyline {
try {
let coors = ArrayList<Coordinate>(arr.size, { i =>
Coordinate.fromArray(arr[i]).getOrThrow()
})
Polyline(coors)
} catch (e : Exception){
NullPolyline()
}
}
/**
* The Function is to create null polyline object
*
* @return Type of Polyline
* @since 0.38.2
*/
public static func NullPolyline() : Polyline {
Polyline()
}
/**
* The Function is to determine whether the polyline is Null
*
* @return Type of Bool
* @since 0.38.2
*/
public func isNull() : Bool {
coordinates.size == 0
}
/**
* The Function is to String
*
* @return Type of String
* @since 0.38.2
*/
public func toString() {
if(coordinates.size == 0) {
return "Polyline[ ] sr:${spatialReference}"
}
var coorStr = ""
for (coor in coordinates) {
coorStr += "(${coor.x}, ${coor.y}) "
}
"Polyline[${coorStr}] sr:${spatialReference}"
}
/**
* The Function is to JSON
*
* @return Type of JsonValue
* @since 0.38.2
*/
public func toJson(): JsonValue {
serialize().toJson()
}
/**
* The Function is to transfrom from data model to json value
* NaN (Not a number) is not acceptable
*
* @param jv of JsonValue
*
* @return Type of DataModel
* @since 0.38.2
*/
public static func fromJson(jv: JsonValue): DataModel {
try {
let geometry = jv.asObject().get("geometry").getOrThrow().asObject()
let geometry_type = geometry.get("type").getOrThrow().asString().getValue()
if (geometry_type != "Polyline") {
return DataModelNull()
}
let wkid = match(geometry.get("spatialReference")) {
case Some(v) => Int64.parse(v.toString())
case None => 0
}
let coordinates = (geometry.get("coordinates").getOrThrow() as JsonArray).getOrThrow()
let coordinates_dm_list = ArrayList<DataModel>(coordinates.size(), { i =>
let coordinate = (coordinates[i] as JsonArray).getOrThrow()
let x = Float64.parse(coordinate[0].toString())
let y = Float64.parse(coordinate[1].toString())
DataModelSeq(ArrayList<DataModel>([DataModelFloat(x), DataModelFloat(y)]))
})
let coordinates_dm = DataModelSeq(coordinates_dm_list)
var geometry_dm = DataModelStruct()
.add(field<String>("type", "Polyline"))
.add(Field("coordinates", coordinates_dm))
if (wkid != 0) {
geometry_dm = geometry_dm.add(field<Int64>("spatialReference", wkid))
}
DataModelStruct().add(Field("geometry", geometry_dm))
}catch (e : Exception) {
DataModelNull()
}
}
/**
* The Function is to serialize the polyline object to data model
*
* @return Type of DataModel
* @since 0.38.2
*/
public func serialize(): DataModel {
let coordinates_dm_list = ArrayList<DataModel>(coordinates.size, { i =>
let x = coordinates[i].x
let y = coordinates[i].y
DataModelSeq(ArrayList<DataModel>([DataModelFloat(x), DataModelFloat(y)]))
})
let coordinates_dm = DataModelSeq(coordinates_dm_list)
var geometry_dm = DataModelStruct()
.add(field<String>("type", "Polyline"))
.add(Field("coordinates", coordinates_dm))
if (!spatialReference.isUnknown() && (spatialReference.wkid != 0)) {
geometry_dm = geometry_dm.add(field<Int64>("spatialReference", spatialReference.wkid))
}
DataModelStruct().add(Field("geometry", geometry_dm))
}
/**
* The Function is to deserialize data model to the polyline object
*
* @param dm of DataModel
*
* @return Type of DataModel
* @since 0.38.2
*/
public static func deserialize(dm: DataModel): Polyline {
try {
let geometry = ((dm as DataModelStruct).getOrThrow().get("geometry") as DataModelStruct).getOrThrow()
let geometry_type = String.deserialize(geometry.get("type"))
if (geometry_type != "Polyline") {
throw Exception()
}
let coordinates = (geometry.get("coordinates") as DataModelSeq).getOrThrow().getItems()
let coordinates_arr = ArrayList<Coordinate>(coordinates.size, { i =>
let coordinate = (coordinates[i] as DataModelSeq).getOrThrow().getItems()
let x = Float64.deserialize(coordinate[0])
let y = Float64.deserialize(coordinate[1])
Coordinate(x, y)
})
match(geometry.get("spatialReference") as DataModelInt) {
case Some(v) => Polyline(coordinates_arr, SpatialReference.fromWKID(v.getValue()) ?? SpatialReference.unknown())
case None => Polyline(coordinates_arr)
}
} catch (e : Exception) {
Polyline.NullPolyline()
}
}
/**
* The Function is to compute the polyline length
*
* @return Type of Float64
* @since 0.38.2
*/
public func length() : Float64 {
CoordinateEngine.length(this.coordinates.toArray())
}
}
/**
* implemtentation of CoordinateTransformer<Polyline>
*
* @author Yu Dong
* @since 0.38.2
*/
extend Polyline <: CoordinateTransformer<Polyline> {
/**
* The Function is to transfrom polyline to GCJ-02
*
* @return Type of ?Polyline
* @since 0.38.2
*/
public func toGCJ02() : ?Polyline {
if (spatialReference.isWGS1984()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.WGS84ToGCJ02(coordinates[i])
}), SpatialReference.gcj02())
}
if (spatialReference.isBD09()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.BD09ToGCJ02(coordinates[i])
}), SpatialReference.gcj02())
}
None
}
/**
* The Function is to transfrom polyline to BD-09
*
* @return Type of ?Polyline
* @since 0.38.2
*/
public func toBD09() : ?Polyline {
if (spatialReference.isWGS1984()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.WGS84ToBD09(coordinates[i])
}), SpatialReference.bd09())
}
if (spatialReference.isGCJ02()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.GCJ02ToBD09(coordinates[i])
}), SpatialReference.bd09())
}
None
}
/**
* The Function is to transfrom polyline to WGS 1984
*
* @return Type of ?Polyline
* @since 0.38.2
*/
public func toWGS1984() : ?Polyline {
if (spatialReference.isGCJ02()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.GCJ02ToWGS84(coordinates[i])
}), SpatialReference.wgs84())
}
if (spatialReference.isBD09()) {
return Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.BD09ToWGS84(coordinates[i])
}), SpatialReference.wgs84())
}
None
}
/**
* The Function is to project polyline to Mercator
*
* @return Type of ?Polyline
* @since 0.38.2
*/
public func projectToMercator() : ?Polyline {
if (this.spatialReference.isProjected()) {
return None
}
Polyline(ArrayList<Coordinate>(coordinates.size, {i =>
CoordinateEngine.GeographicToMercator(coordinates[i])
}), ProjectedSpatialReference.WebMercator(
(this.spatialReference as GeographicSpatialReference) ?? GeographicSpatialReference.Unknown
)
)
}
}