Source: uGisUtil/uGisGeoSpatialUtil.js

( function() {
	"use strict";

	/**
	 * uGisMapPlatForm 지형 공간 유틸리티.
	 * 
	 * 지형 공간 정보 처리에 필요한 유틸리티 객체.
	 * 
	 * @namespace
	 */
	ugmp.util.uGisGeoSpatialUtil = ( function() {

		return {
			toRadians : this.toRadians,
			toDegrees : this.toDegrees,
			getGeomCenter : this.getGeomCenter,
			getLargestPolygon : this.getLargestPolygon,
			getLargestLineString : this.getLargestLineString,
			lineToArcTransForm : this.lineToArcTransForm,
			getRadianBtwPoints : this.getRadianBtwPoints,
			getDegreeBtwPoints : this.getDegreeBtwPoints,
			getDistanceBtwPotins : this.getDistanceBtwPotins
		}

	} );


	/**
	 * Radian을 Degree로 변환한다.
	 * 
	 * @param degree {Number} Degree(도).
	 * 
	 * @return {Number} Radian(라디안).
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.toRadians = function(degree_) {
		return degree_ / 180.0 * Math.PI;
	};


	/**
	 * Degree를 Radian으로 변환한다.
	 * 
	 * @param radian {Number} Radian(라디안).
	 * 
	 * @return {Number} Degree(도).
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.toDegrees = function(radian_) {
		return radian_ * 180.0 / Math.PI;
	};


	/**
	 * 두 점 사이의 Radian(라디안)을 구한다.
	 * 
	 * @param coordinate1 {Array.<Number>} 점1 [x, y].
	 * @param coordinate2 {Array.<Number>} 점2 [x, y].
	 * 
	 * @return {Number} 두 점 사이의 Radian(라디안).
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getRadianBtwPoints = function(coordinate1, coordinate2) {
		var pX1 = coordinate1[ 0 ];
		var pY1 = coordinate1[ 1 ];
		var pX2 = coordinate2[ 0 ];
		var pY2 = coordinate2[ 1 ];

		return Math.atan2( pY2 - pY1, pX2 - pX1 );
	};


	/**
	 * 두 점 사이의 Degree(도)를 구한다.
	 * 
	 * @param coordinate1 {Array.<Number>} 점1 [x, y].
	 * @param coordinate2 {Array.<Number>} 점2 [x, y].
	 * 
	 * @return {Number} 두 점 사이의 Degree(도).
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getDegreeBtwPoints = function(coordinate1, coordinate2) {
		var radian = this.getRadianBtwPoints( coordinate1, coordinate2 );

		return this.toDegrees( radian );
	};


	/**
	 * 두 점 사이의 거리를 구한다.
	 * 
	 * @param coordinate1 {Array.<Number>} 점1 [x, y].
	 * @param coordinate2 {Array.<Number>} 점2 [x, y].
	 * 
	 * @return {Number} 두 점 사이의 거리.
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getDistanceBtwPotins = function(c1, c2) {
		return Math.sqrt( Math.pow( ( c1[ 0 ] - c2[ 0 ] ), 2 ) + Math.pow( ( c1[ 1 ] - c2[ 1 ] ), 2 ) );
	};


	/**
	 * 일반 라인을 호 형태의 라인으로 변환한다.
	 * 
	 * -featureList는 피처의 속성이 `ol.geom.LineString`또는 `ol.geom.MultiLineString`이다.
	 * 
	 * @param originCRS {String} 피처 원본 좌표계.
	 * @param featureList {Array.<ol.Feature.<ol.geom.LineString|ol.geom.MultiLineString>>} 변활할 피처 리스트.
	 * 
	 * @return reData {Array.<ol.Feature.<ol.geom.LineString>>} 변환된 호 형태의 피처 리스트.
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.lineToArcTransForm = function(originCRS_, featureList_) {
		var _self = this;
		var reData = [];
		var transFormFeatures = [];

		( function() {
			var features = featureList_.slice();

			for ( var i = 0; i < features.length; i++ ) {
				var geom = features[ i ].getGeometry();

				if ( !geom ) {
					continue;
				}

				if ( geom instanceof ol.geom.LineString ) {
					transFormFeatures.push( new ol.Feature( {
						geometry : geom
					} ) );
				} else if ( geom instanceof ol.geom.MultiLineString ) {
					var lineStrings = geom.getLineStrings();
					for ( var j = 0; j < lineStrings.length; j++ ) {
						transFormFeatures.push( new ol.Feature( {
							geometry : lineStrings[ j ]
						} ) );
					}
				}
			}

			_transFormArc();

		} )();


		function _transFormArc() {
			for ( var j = 0; j < transFormFeatures.length; j++ ) {
				var customCoordinates = [];
				var coords = transFormFeatures[ j ].getGeometry().getCoordinates();

				for ( var i = 0; i < coords.length - 1; i++ ) {
					var from = coords[ i ];
					var to = coords[ i + 1 ];
					var dist = _self.getDistanceBtwPotins( from, to );
					var midPoint = _draw_curve( from, to, ( dist / 5 ) );

					var line = {
						type : "Feature",
						properties : {},
						geometry : {
							type : "LineString",
							coordinates : [ from, midPoint, to ]
						}
					};

					var curved = turf.bezier( line, 3000, 1.5 );
					customCoordinates = customCoordinates.concat( curved[ "geometry" ][ "coordinates" ] );
				}

				var newFeature = new ol.Feature( {
					geometry : new ol.geom.LineString( customCoordinates )
				} );

				reData.push( newFeature );
			}
		}


		function _draw_curve(from_, to_, dist_) {
			// Find midpoint J
			var Ax = from_[ 0 ];
			var Ay = from_[ 1 ];
			var Bx = to_[ 0 ];
			var By = to_[ 1 ];

			var Jx = Ax + ( Bx - Ax ) / 5 * 3;
			var Jy = Ay + ( By - Ay ) / 5 * 3;

			var a = Bx - Ax;
			var b = By - Ay;
			var asign = ( a < 0 ? -1 : 1 );
			var bsign = ( b < 0 ? -1 : 1 );
			var theta = Math.atan( b / a );

			// Find the point that's perpendicular to J on side
			var costheta = asign * Math.cos( theta );
			var sintheta = asign * Math.sin( theta );

			// Find c and d
			var c = dist_ * sintheta;
			var d = dist_ * costheta;

			// Use c and d to find Kx and Ky
			var Kx = Jx - c;
			var Ky = Jy + d;

			return [ Kx, Ky ];
		}

		return reData;
	};


	/**
	 * MultiLineString의 가장 큰 LineString을 가져온다.
	 * 
	 * @param geom_ {ol.geom.MultiLineString} MultiLineString.
	 * 
	 * @return {LineString} 가장 큰 LineString.
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getLargestLineString = function(geom_) {
		if ( !geom_ || geom_.getType() !== ol.geom.GeometryType.MULTI_LINE_STRING ) return false;

		return geom_.getLineStrings().reduce( function(left, right) {
			return left.getLength() > right.getLength() ? left : right;
		} );
	};


	/**
	 * MultiPolygon의 가장 큰 Polygon을 가져온다.
	 * 
	 * @param geom_ {ol.geom.MultiPolygon} MultiPolygon.
	 * 
	 * @return {Polygon} 가장 큰 Polygon.
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getLargestPolygon = function(geom_) {
		if ( !geom_ || geom_.getType() !== ol.geom.GeometryType.MULTI_POLYGON ) return false;

		return geom_.getPolygons().reduce( function(left, right) {
			return left.getArea() > right.getArea() ? left : right;
		} );
	};


	/**
	 * Geometry의 중심점을 가져온다.
	 * 
	 * @param geom {ol.geom.Geometry} Geometry.
	 * 
	 * @return {Array.<Number>} 중심점[x, y].
	 */
	ugmp.util.uGisGeoSpatialUtil.prototype.getGeomCenter = function(geom_) {
		if ( !geom_ || !geom_ instanceof ol.geom.Geometry ) return false;

		var coordinate = [];
		var geometry = geom_;
		var geometryType = geometry.getType();

		switch ( geometryType ) {
			case ol.geom.GeometryType.POINT :
			case ol.geom.GeometryType.MULTI_POINT :
				coordinate = geometry.getFlatCoordinates();
				break;

			case ol.geom.GeometryType.CIRCLE :
				coordinate = geometry.getCenter();

				break;
			case ol.geom.GeometryType.LINE_STRING :
				coordinate = geometry.getFlatMidpoint();
				break;

			case ol.geom.GeometryType.MULTI_LINE_STRING :
				coordinate = this.getLargestLineString( geometry ).getFlatMidpoint();
				break;

			case ol.geom.GeometryType.POLYGON :
				coordinate = geometry.getFlatInteriorPoint();
				break;

			case ol.geom.GeometryType.MULTI_POLYGON :
				// coordinate = this.getLargestPolygon( geometry ).getInteriorPoint().getCoordinates();
				coordinate = this.getLargestPolygon( geometry ).getFlatInteriorPoint();
				break;
		}

		return coordinate;
	};


	ugmp.util.uGisGeoSpatialUtil = new ugmp.util.uGisGeoSpatialUtil();

} )();