Unverified Commit 06940339 authored by Kevin Di Lallo's avatar Kevin Di Lallo Committed by GitHub
Browse files

Merge pull request #259 from pastorsx/sp_dev_gis_engine_api

new GIS engine API DistanceTo and WithinRange endoints
parents fdaafddd e32a7542
Loading
Loading
Loading
Loading
+170 −0
Original line number Diff line number Diff line
@@ -249,6 +249,73 @@ paths:
          description: "Not found"
        500:
          description: "Internal server error"
  /geodata/{assetName}/distanceTo:
    post:
      tags:
      - "Geospatial Data"
      summary: "Get distance between geospatial data points"
      description: "Get distance between geospatial data for the given asset and another\
        \ asset or geospatial coordinates"
      operationId: "getDistanceGeoDataByName"
      produces:
      - "application/json"
      parameters:
      - name: "assetName"
        in: "path"
        description: "Name of geospatial asset"
        required: true
        type: "string"
        x-exportParamName: "AssetName"
      - in: "body"
        name: "targetPoint"
        description: "Parameters of geospatial assets"
        required: true
        schema:
          $ref: "#/definitions/TargetPoint"
        x-exportParamName: "TargetPoint"
      responses:
        200:
          description: "OK"
          schema:
            $ref: "#/definitions/Distance"
        404:
          description: "Not found"
        500:
          description: "Internal server error"
  /geodata/{assetName}/withinRange:
    post:
      tags:
      - "Geospatial Data"
      summary: "Returns if a geospatial data points is within a specified distance\
        \ from a location"
      description: "Get geospatial data for the given asset and if it is within range\
        \ of another asset or geospatial coordinates"
      operationId: "getWithinRangeByName"
      produces:
      - "application/json"
      parameters:
      - name: "assetName"
        in: "path"
        description: "Name of geospatial asset"
        required: true
        type: "string"
        x-exportParamName: "AssetName"
      - in: "body"
        name: "targetRange"
        description: "Parameters of geospatial assets"
        required: true
        schema:
          $ref: "#/definitions/TargetRange"
        x-exportParamName: "TargetRange"
      responses:
        200:
          description: "OK"
          schema:
            $ref: "#/definitions/WithinRange"
        404:
          description: "Not found"
        500:
          description: "Internal server error"
definitions:
  AutomationStateList:
    type: "object"
@@ -283,6 +350,50 @@ definitions:
    example:
      active: true
      type: "MOBILITY"
  TargetPoint:
    type: "object"
    properties:
      assetName:
        type: "string"
        description: "Asset name of a second element for query purpose. If present,\
          \ latitude and longitude are ignored."
      latitude:
        type: "number"
        format: "float"
        description: "Latitude of a second element for query purpose. Taken into account\
          \ only if AssetName is not present."
      longitude:
        type: "number"
        format: "float"
        description: "Longitude of a second element for query purpose. Taken into\
          \ account only if AssetName is not present."
    description: "Parameters for distance query purpose."
    example:
      latitude: 0.8008282
      assetName: "assetName"
      longitude: 6.0274563
  Distance:
    type: "object"
    required:
    - "distance"
    properties:
      distance:
        type: "number"
        format: "float"
        description: "Distance between two points (in meters)"
      latitude:
        type: "number"
        format: "float"
        description: "Destination asset latitude"
      longitude:
        type: "number"
        format: "float"
        description: "Destination asset longitude"
    description: "Distance response"
    example:
      distance: 0.8008282
      latitude: 6.0274563
      longitude: 1.4658129
  GeoDataAssetList:
    type: "object"
    properties:
@@ -295,6 +406,9 @@ definitions:
  GeoDataAsset:
    allOf:
    - type: "object"
      required:
      - "assetName"
      - "assetType"
      properties:
        assetName:
          type: "string"
@@ -320,6 +434,62 @@ definitions:
          - "CLOUD"
    - $ref: "#/definitions/GeoData"
    description: "List of geospatial data"
  TargetRange:
    type: "object"
    required:
    - "radius"
    properties:
      assetName:
        type: "string"
        description: "Asset name of a second element for query purpose. If present,\
          \ latitude and longitude are ignored."
      latitude:
        type: "number"
        format: "float"
        description: "Latitude of a second element for query purpose. Taken into account\
          \ only if AssetName is not present."
      longitude:
        type: "number"
        format: "float"
        description: "Longitude of a second element for query purpose. Taken into\
          \ account only if AssetName is not present."
      radius:
        type: "number"
        format: "float"
        description: "Radius (in meters) around the location."
      accuracy:
        type: "number"
        format: "float"
        description: "Accuracy of the location (in meters)."
    description: "Parameters for within range query purpose."
    example:
      latitude: 0.8008282
      assetName: "assetName"
      accuracy: 5.962134
      radius: 1.4658129
      longitude: 6.0274563
  WithinRange:
    type: "object"
    required:
    - "within"
    properties:
      latitude:
        type: "number"
        format: "float"
        description: "Destination asset latitude"
      longitude:
        type: "number"
        format: "float"
        description: "Destination asset longitude"
      within:
        type: "boolean"
        description: "Within range result (e.g. true = within range, false = beyond\
          \ range)"
    description: "Within range response"
    example:
      within: true
      latitude: 0.8008282
      longitude: 6.0274563
  GeoData:
    type: "object"
    properties:
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ To see how to make this your own, look here:
[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md)

- API version: 1.0.0
- Build date: 2021-04-27T13:27:39.348-04:00
- Build date: 2021-06-02T13:11:19.569-04:00


### Running the server
+8 −0
Original line number Diff line number Diff line
@@ -36,10 +36,18 @@ func GetAssetData(w http.ResponseWriter, r *http.Request) {
	geGetAssetData(w, r)
}

func GetDistanceGeoDataByName(w http.ResponseWriter, r *http.Request) {
	geGetDistanceGeoDataByName(w, r)
}

func GetGeoDataByName(w http.ResponseWriter, r *http.Request) {
	geGetGeoDataByName(w, r)
}

func GetWithinRangeByName(w http.ResponseWriter, r *http.Request) {
	geGetWithinRangeGeoDataByName(w, r)
}

func UpdateGeoDataByName(w http.ResponseWriter, r *http.Request) {
	geUpdateGeoDataByName(w, r)
}
+248 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import (
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
@@ -1147,6 +1148,253 @@ func geGetAssetData(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, string(jsonResponse))
}

func convertJsonToPoint(jsonData string) *Point {

	var obj Point
	err := json.Unmarshal([]byte(jsonData), &obj)
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return &obj
}

func geGetDistanceGeoDataByName(w http.ResponseWriter, r *http.Request) {
	// Get asset name from request path parameters
	vars := mux.Vars(r)
	assetName := vars["assetName"]
	log.Debug("Get Distance GeoData for asset: ", assetName)

	// Make sure scenario is active
	if ge.activeModel.GetScenarioName() == "" {
		err := errors.New("No active scenario")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	srcAsset := ge.assets[assetName]
	if srcAsset == nil {
		err := errors.New("Asset not in scenario")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	srcLongStr := ""
	srcLatStr := ""
	position, err := ge.gisCache.GetPosition("*", assetName)
	if err != nil {
		err := errors.New("Asset has no geo location")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	srcLongStr = strconv.FormatFloat(float64(position.Longitude), 'f', -1, 32)
	srcLatStr = strconv.FormatFloat(float64(position.Latitude), 'f', -1, 32)

	// Retrieve Distance parameters from request body
	var distanceParam TargetPoint
	if r.Body == nil {
		err := errors.New("Request body is missing")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	decoder := json.NewDecoder(r.Body)
	err = decoder.Decode(&distanceParam)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	dstLong := float32(0.0)
	dstLat := float32(0.0)
	dstLongStr := ""
	dstLatStr := ""

	if distanceParam.AssetName != "" {

		dstAsset := ge.assets[distanceParam.AssetName]
		if dstAsset == nil {
			err := errors.New("Destination asset not in scenario")
			log.Error(err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		// Find second asset in active scenario model
		position, err = ge.gisCache.GetPosition("*", distanceParam.AssetName)

		if err != nil {
			err := errors.New("Destination asset has no geo location")
			log.Error(err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		dstLong = position.Longitude
		dstLat = position.Latitude

		dstLongStr = strconv.FormatFloat(float64(position.Longitude), 'f', -1, 32)
		dstLatStr = strconv.FormatFloat(float64(position.Latitude), 'f', -1, 32)

	} else {
		dstLong = distanceParam.Longitude
		dstLat = distanceParam.Latitude
		dstLongStr = strconv.FormatFloat(float64(distanceParam.Longitude), 'f', -1, 32)
		dstLatStr = strconv.FormatFloat(float64(distanceParam.Latitude), 'f', -1, 32)
	}

	srcCoordinates := "(" + srcLongStr + " " + srcLatStr + ")"
	dstCoordinates := "(" + dstLongStr + " " + dstLatStr + ")"

	distance, err := ge.assetMgr.GetDistanceBetweenPoints(srcCoordinates, dstCoordinates)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Create Response to return
	var resp Distance
	resp.Distance = distance
	resp.Longitude = dstLong
	resp.Latitude = dstLat

	// Format response
	jsonResponse, err := json.Marshal(&resp)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send response
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, string(jsonResponse))
}

func geGetWithinRangeGeoDataByName(w http.ResponseWriter, r *http.Request) {

	// Get asset name from request path parameters
	vars := mux.Vars(r)
	assetName := vars["assetName"]
	log.Debug("Get Within Range GeoData for asset: ", assetName)

	// Make sure scenario is active
	if ge.activeModel.GetScenarioName() == "" {
		err := errors.New("No active scenario")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	srcAsset := ge.assets[assetName]
	if srcAsset == nil {
		err := errors.New("Asset not in scenario")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	srcLongStr := ""
	srcLatStr := ""
	if srcAsset.geoData != nil {
		srcPosition := srcAsset.geoData.position
		srcPoint := convertJsonToPoint(srcPosition)
		srcLongStr = strconv.FormatFloat(float64(srcPoint.Coordinates[0]), 'f', -1, 32)
		srcLatStr = strconv.FormatFloat(float64(srcPoint.Coordinates[1]), 'f', -1, 32)
	} else {
		err := errors.New("Asset has no geo location")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Retrieve Within Range parameters from request body
	var withinRangeParam TargetRange
	if r.Body == nil {
		err := errors.New("Request body is missing")
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&withinRangeParam)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	dstLong := float32(0.0)
	dstLat := float32(0.0)
	dstLongStr := ""
	dstLatStr := ""
	if withinRangeParam.AssetName != "" {

		// Find second asset in active scenario model
		dstAsset := ge.assets[withinRangeParam.AssetName]
		if dstAsset == nil {
			err := errors.New("Destination asset not in scenario")
			log.Error(err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if dstAsset.geoData != nil {
			dstPosition := dstAsset.geoData.position
			dstPoint := convertJsonToPoint(dstPosition)
			dstLong = dstPoint.Coordinates[0]
			dstLat = dstPoint.Coordinates[1]
			dstLongStr = strconv.FormatFloat(float64(dstPoint.Coordinates[0]), 'f', -1, 32)
			dstLatStr = strconv.FormatFloat(float64(dstPoint.Coordinates[1]), 'f', -1, 32)
		} else {
			err := errors.New("Destination asset has no geo location")
			log.Error(err.Error())
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

	} else {
		dstLong = withinRangeParam.Longitude
		dstLat = withinRangeParam.Latitude
		dstLongStr = strconv.FormatFloat(float64(withinRangeParam.Longitude), 'f', -1, 32)
		dstLatStr = strconv.FormatFloat(float64(withinRangeParam.Latitude), 'f', -1, 32)
	}

	srcCoordinates := "(" + srcLongStr + " " + srcLatStr + ")"
	dstCoordinates := "(" + dstLongStr + " " + dstLatStr + ")"
	radius := strconv.FormatFloat(float64(withinRangeParam.Radius), 'f', -1, 32)

	withinRange, err := ge.assetMgr.GetWithinRangeBetweenPoints(srcCoordinates, dstCoordinates, radius)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Create Response to return
	var resp WithinRange
	resp.Within = withinRange
	resp.Longitude = dstLong
	resp.Latitude = dstLat

	// Format response
	jsonResponse, err := json.Marshal(&resp)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send response
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, string(jsonResponse))
}

func geGetGeoDataByName(w http.ResponseWriter, r *http.Request) {
	// Get asset name from request path parameters
	vars := mux.Vars(r)
+38 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2020  InterDigital Communications, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the \"License\");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an \"AS IS\" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * AdvantEDGE GIS Engine REST API
 *
 * This API allows to control geo-spatial behavior and simulation. <p>**Micro-service**<br>[meep-gis-engine](https://github.com/InterDigitalInc/AdvantEDGE/tree/master/go-apps/meep-gis-engine) <p>**Type & Usage**<br>Platform runtime interface to control geo-spatial behavior and simulation <p>**Details**<br>API details available at _your-AdvantEDGE-ip-address/api_
 *
 * API version: 1.0.0
 * Contact: AdvantEDGE@InterDigital.com
 * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
 */

package server

// Distance response
type Distance struct {

	// Distance between two points (in meters)
	Distance float32 `json:"distance"`

	// Destination asset latitude
	Latitude float32 `json:"latitude,omitempty"`

	// Destination asset longitude
	Longitude float32 `json:"longitude,omitempty"`
}
Loading