Ddongyu1009init
cdf6f0e0创建于 2024年9月6日历史提交
/**
  This file is created by Yu Dong (2023).
  License  : Apache 2.0
  FileName : Point.cj
  Author   : Yu Dong
  Version  : 0.0.1
  Date     : 20230424
  Note     : First Commit
 */

/**
 * @file
 * Point
 */
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.*

/**
 * Point 
 *  
 * @author Yu Dong
 * @since 0.38.2
 */
public class Point <: Geometry & Serializable<Point>{

    // the coordinate of the point
    public var coordinate : Coordinate


    /**
     * The Property is to get the x coordinate
     *
     * @since 0.38.2
     */
    public mut prop x : Float64 {
        get() {coordinate.x}
        set(v) {coordinate.x = v}
    }

    /**
     * The Property is to get the y coordinate
     *
     * @since 0.38.2
     */
    public mut prop y : Float64 {
        get() {coordinate.y}
        set(v) {coordinate.y = v}
    }

    /**
     * The Function is init constructor
     *
     * @since 0.38.2
     */
    public init() {
        this.coordinate = Coordinate(Float64.NaN, Float64.NaN)
        this.spatialReference = SpatialReference.unknown()
    }

    /**
     * The Function is init constructor
     *
     * @param coordinate of Coordinate
     *
     * @since 0.38.2
     */
    public init(coordinate : Coordinate) {
        this.coordinate = coordinate
        this.spatialReference = SpatialReference.unknown()
    }

    /**
     * The Function is init constructor
     *
     * @param coordinate of Coordinate
     * @param sr of SpatialReference
     *
     * @since 0.38.2
     */
    public init(coordinate : Coordinate, sr : SpatialReference) {
        this.coordinate = coordinate
        this.spatialReference = sr
    }

    /**
     * The Function is init constructor
     *
     * @param x of Float64
     * @param y of Float64
     *
     * @since 0.38.2
     */
    public init(x : Float64, y : Float64) {
        this.coordinate = Coordinate(x, y)
        this.spatialReference = SpatialReference.unknown()
    }

    /**
     * The Function is init constructor
     *
     * @param x of Float64
     * @param y of Float64
     * @param sr of SpatialReference
     *
     * @since 0.38.2
     */
    public init(x : Float64, y : Float64, sr : SpatialReference) {
        this.coordinate = Coordinate(x, y)
        this.spatialReference = sr
    }

    /**
     * The Function is to create null point object
     *
     * @return Type of Point
     * @since 0.38.2
     */
    public static func NullPoint() : Point {
        Point()
    }

    /**
     * The Function is to determine whether the Point is Null
     *
     * @return Type of Bool
     * @since 0.38.2
     */
    public func isNull() : Bool {
        x.isNaN() || y.isNaN()
    }

    /**
     * The Function is to String
     *
     * @return Type of String
     * @since 0.38.2
     */
    public func toString() {
        "Point(${x},${y}) sr:${spatialReference}"
    }


    /**
     * 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 != "Point") {
                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 x = Float64.parse(coordinates[0].toString()) 
            let y = Float64.parse(coordinates[1].toString()) 

            let coordinates_dm = DataModelSeq(ArrayList<DataModel>([DataModelFloat(x), DataModelFloat(y)]))
            var geometry_dm = DataModelStruct()
                .add(field<String>("type", "Point"))
                .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 JSON
     *
     * @return Type of JsonValue
     * @since 0.38.2
     */
    public func toJson(): JsonValue  {
        serialize().toJson()
    }

    /**
     * The Function is to serialize the point object to data model
     *
     * @return Type of DataModel
     * @since 0.38.2
     */
    public func serialize(): DataModel {
        let coordinates_dm = DataModelSeq(ArrayList<DataModel>([DataModelFloat(x), DataModelFloat(y)]))
        var geometry_dm = DataModelStruct()
            .add(field<String>("type", "Point"))
            .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 point object
     *
     * @param dm of DataModel
     *
     * @return Type of DataModel
     * @since 0.38.2
     */
    static public func deserialize(dm: DataModel): Point {
        try {
            let geometry = ((dm as DataModelStruct).getOrThrow().get("geometry") as DataModelStruct).getOrThrow()
            let geometry_type = String.deserialize(geometry.get("type"))
            if (geometry_type != "Point") {
                throw Exception()
            }
            let coordinates = (geometry.get("coordinates") as DataModelSeq).getOrThrow().getItems()
            let x = Float64.deserialize(coordinates[0])
            let y = Float64.deserialize(coordinates[1])
            match(geometry.get("spatialReference") as DataModelInt) {
                case Some(v) => Point(x, y, SpatialReference.fromWKID(v.getValue()) ?? SpatialReference.unknown())
                case None => Point(x, y)
            }
        } catch (e : Exception) {
            Point.NullPoint()
        }
    }

    /**
     * The Function is to compute the distance of 2 points
     *
     * @param point of Point
     *
     * @return Type of Float64
     * @since 0.38.2
     */
    public func distance(point : Point) : Float64{
        CoordinateEngine.distance(this.coordinate, point.coordinate)
    }
}

/**
 * implemtentation of CoordinateTransformer<Point>
 *  
 * @author Yu Dong
 * @since 0.38.2
 */
extend Point <: CoordinateTransformer<Point> {


    /**
     * The Function is to transfrom point to GCJ-02
     *
     * @return Type of ?Point
     * @since 0.38.2
     */
    public func toGCJ02() : ?Point {
        if (spatialReference.isWGS1984()) {
            return Point(CoordinateEngine.WGS84ToGCJ02(coordinate), SpatialReference.gcj02())
        }
        if (spatialReference.isBD09()) {
            return Point(CoordinateEngine.BD09ToGCJ02(coordinate), SpatialReference.gcj02())
        }
        None
    }

    /**
     * The Function is to transfrom point to BD-09
     *
     * @return Type of ?Point
     * @since 0.38.2
     */
    public func toBD09() : ?Point {
        
        if (spatialReference.isWGS1984()) {
            return Point(CoordinateEngine.WGS84ToBD09(coordinate), SpatialReference.bd09())
        }
        if (spatialReference.isGCJ02()) {
            return Point(CoordinateEngine.GCJ02ToBD09(coordinate), SpatialReference.bd09())
        }
        None
    }

    /**
     * The Function is to transfrom point to WGS 1984
     *
     * @return Type of ?Point
     * @since 0.38.2
     */
    public func toWGS1984() : ?Point {

        if (spatialReference.isBD09()) {
            return Point(CoordinateEngine.BD09ToWGS84(coordinate), SpatialReference.bd09())
        }
        if (spatialReference.isGCJ02()) {
            return Point(CoordinateEngine.GCJ02ToWGS84(coordinate), SpatialReference.bd09())
        }
        None
    }

    /**
     * The Function is to project point to Mercator
     *
     * @return Type of ?Point
     * @since 0.38.2
     */
    public func projectToMercator() : ?Point { 
        if (this.spatialReference.isProjected()) {
            return None
        }
        Point(CoordinateEngine.GeographicToMercator(coordinate), 
                    ProjectedSpatialReference.WebMercator((this.spatialReference as GeographicSpatialReference) ?? GeographicSpatialReference.Unknown))
    }
    
}