Skip to content

Commit 633bd90

Browse files
authored
Merge pull request #74 from Esri/john0005/CalculateDistance
Calculate Distance 3D
2 parents 0b5b3db + 2bbe9f3 commit 633bd90

File tree

10 files changed

+376
-1
lines changed

10 files changed

+376
-1
lines changed
268 KB
Loading

scene/calculate-distance/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#Calculate Distance 3D
2+
Demonstrates how to calculate the distance, in meters, between two Graphics in 3D space.
3+
4+
##How to use the sample
5+
Once the SceneView has loaded the Graphic's animation will begin. The distance between the two Graphics will be displayed at the top of the application and will be updated when the Graphic's animation starts.
6+
7+
![](CalculateDistance3D.PNG)
8+
9+
10+
##How it works
11+
To calculate the distance between two `Graphic`s in 3D space:
12+
13+
1. Create a `GraphicsOverlay` and attach it to the `SceneView`.
14+
1. Create the two graphics and add to graphics overlay.
15+
- supply each graphic with a `Point`, starting location, and `SimpleMarkerSymbol`
16+
1. Convert each graphic's point to the Cartesian coordinate system
17+
1. Create a JavaFX Point3D from the Cartesian x,y, and z value.
18+
1. Then get the distance between each of the JavaFX Point3Ds, `Point3D.distance(Point3D)`.
19+
20+
##Features
21+
- ArcGISScene
22+
- Graphic
23+
- GraphicsOverlay
24+
- SceneView
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
apply plugin: 'java'
2+
apply plugin: 'application'
3+
apply plugin: 'com.esri.arcgisruntime.java'
4+
5+
buildscript {
6+
repositories {
7+
maven {
8+
url 'https://esri.bintray.com/arcgis'
9+
}
10+
}
11+
dependencies {
12+
classpath 'com.esri.arcgisruntime:gradle-arcgis-java-plugin:0.9.0'
13+
}
14+
}
15+
16+
run {
17+
mainClassName = 'com.esri.samples.scene.CalculateDistance'
18+
}

scene/calculate-distance/settings.gradle

Whitespace-only changes.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2016 Esri.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.esri.samples.scene;
17+
18+
import java.io.IOException;
19+
20+
import javafx.application.Application;
21+
import javafx.fxml.FXMLLoader;
22+
import javafx.scene.Parent;
23+
import javafx.scene.Scene;
24+
import javafx.stage.Stage;
25+
26+
public class CalculateDistance3D extends Application {
27+
28+
private static CalculateDistance3DController controller;
29+
30+
@Override
31+
public void start(Stage stage) throws IOException {
32+
// set up the scene
33+
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/CalculateDistance.fxml"));
34+
Parent root = loader.load();
35+
controller = loader.getController();
36+
Scene scene = new Scene(root);
37+
38+
// set up the stage
39+
stage.setTitle("Calculate a 3D Distance");
40+
stage.setWidth(800);
41+
stage.setHeight(700);
42+
stage.setScene(scene);
43+
stage.show();
44+
}
45+
46+
/**
47+
* Stops and releases all resources used in application.
48+
*/
49+
@Override
50+
public void stop() {
51+
controller.terminate();
52+
}
53+
54+
/**
55+
* Opens and runs application.
56+
*
57+
* @param args arguments passed to this application
58+
*/
59+
public static void main(String[] args) {
60+
61+
Application.launch(args);
62+
}
63+
}
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
* Copyright 2016 Esri.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.esri.samples.scene;
17+
18+
import javafx.animation.Animation;
19+
import javafx.animation.KeyFrame;
20+
import javafx.animation.Timeline;
21+
import javafx.beans.property.LongProperty;
22+
import javafx.beans.property.SimpleLongProperty;
23+
import javafx.fxml.FXML;
24+
import javafx.geometry.Point3D;
25+
import javafx.scene.control.Label;
26+
import javafx.util.Duration;
27+
28+
import com.esri.arcgisruntime.geometry.Point;
29+
import com.esri.arcgisruntime.geometry.SpatialReference;
30+
import com.esri.arcgisruntime.geometry.SpatialReferences;
31+
import com.esri.arcgisruntime.mapping.ArcGISScene;
32+
import com.esri.arcgisruntime.mapping.ArcGISTiledElevationSource;
33+
import com.esri.arcgisruntime.mapping.Basemap;
34+
import com.esri.arcgisruntime.mapping.Surface;
35+
import com.esri.arcgisruntime.mapping.view.Camera;
36+
import com.esri.arcgisruntime.mapping.view.DrawStatus;
37+
import com.esri.arcgisruntime.mapping.view.DrawStatusChangedEvent;
38+
import com.esri.arcgisruntime.mapping.view.DrawStatusChangedListener;
39+
import com.esri.arcgisruntime.mapping.view.Graphic;
40+
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
41+
import com.esri.arcgisruntime.mapping.view.LayerSceneProperties.SurfacePlacement;
42+
import com.esri.arcgisruntime.mapping.view.SceneView;
43+
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
44+
45+
public class CalculateDistance3DController {
46+
47+
@FXML
48+
private Label txtDistance;
49+
private LongProperty distance;
50+
private Timeline animation;
51+
// distance to move graphics each key frame
52+
private double xOffset = -0.1;
53+
54+
@FXML
55+
private SceneView sceneView;
56+
private Point redPoint;
57+
private Point greenPoint;
58+
private SimpleMarkerSymbol redSymbol;
59+
private SimpleMarkerSymbol greenSymbol;
60+
private Graphic redGraphic;
61+
private Graphic greenGraphic;
62+
private SpatialReference sr = SpatialReferences.getWgs84();
63+
64+
private static final String ELEVATION_IMAGE_SERVICE =
65+
"http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
66+
67+
/**
68+
* Called after FXML loads. Sets up scene and map and configures property bindings.
69+
*/
70+
public void initialize() {
71+
72+
try {
73+
// create a scene and add to view
74+
ArcGISScene scene = new ArcGISScene();
75+
scene.setBasemap(Basemap.createImagery());
76+
sceneView.setArcGISScene(scene);
77+
78+
// adds elevation to surface
79+
Surface surface = new Surface();
80+
surface.getElevationSources().add(new ArcGISTiledElevationSource(ELEVATION_IMAGE_SERVICE));
81+
scene.setBaseSurface(surface);
82+
83+
createGraphics();
84+
85+
// set viewpoint of camera above graphics
86+
Camera camera = new Camera(39, -101, 10000000, 10.0, 0.0, 0.0);
87+
sceneView.setViewpointCamera(camera);
88+
89+
setupAnimation();
90+
91+
// automatically updates distance between graphics to view
92+
distance = new SimpleLongProperty();
93+
txtDistance.textProperty().bind(distance.asString());
94+
// set beginning distance of two graphics
95+
distance.set(Math.round(calculateDirectLinearDistance(redPoint, greenPoint)));
96+
97+
} catch (Exception e) {
98+
// on any error, display the stack trace.
99+
e.printStackTrace();
100+
}
101+
}
102+
103+
/**
104+
* Create red and green triangle graphics and displays them to the view.
105+
*/
106+
private void createGraphics() {
107+
108+
// applies graphics to the view who's altitude is increased by surface's elevation
109+
GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
110+
graphicsOverlay.getSceneProperties().setSurfacePlacement(SurfacePlacement.ABSOLUTE);
111+
sceneView.getGraphicsOverlays().add(graphicsOverlay);
112+
113+
// creating graphics for view
114+
redPoint = new Point(-77.69531409620706, 40.25390707699415, 900, sr);
115+
redSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.TRIANGLE, 0xFFFF0000, 20);
116+
redGraphic = new Graphic(redPoint, redSymbol);
117+
graphicsOverlay.getGraphics().add(redGraphic);
118+
119+
greenPoint = new Point(-120.05859621653715, 38.847657048103514, 1000, sr);
120+
greenSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.TRIANGLE, 0xFF00FF00, 20);
121+
greenSymbol.setAngle(30);
122+
greenGraphic = new Graphic(greenPoint, greenSymbol);
123+
graphicsOverlay.getGraphics().add(greenGraphic);
124+
}
125+
126+
/**
127+
* Sets graphic animation to keep running every 100 milliseconds.
128+
* <p>
129+
* The animation will play once the view is done loading.
130+
*/
131+
private void setupAnimation() {
132+
133+
animation = new Timeline(new KeyFrame(Duration.millis(100), e -> animate()));
134+
animation.setCycleCount(Animation.INDEFINITE);
135+
136+
// listener for the view to stop loading
137+
DrawStatusChangedListener listener = new DrawStatusChangedListener() {
138+
139+
@Override
140+
public void drawStatusChanged(DrawStatusChangedEvent drawStatusChangedEvent) {
141+
if (drawStatusChangedEvent.getDrawStatus() == DrawStatus.COMPLETED) {
142+
// start animation
143+
animation.play();
144+
// stop listening for the view to load
145+
sceneView.removeDrawStatusChangedListener(this);
146+
}
147+
}
148+
};
149+
sceneView.addDrawStatusChangedListener(listener);
150+
}
151+
152+
/**
153+
* Moves graphics along the X axis and calculates distance between them.
154+
*/
155+
private void animate() {
156+
157+
// changes direction of graphics once they reach their boundary
158+
if (redPoint.getX() <= -120) {
159+
xOffset = 0.1;
160+
redSymbol.setAngle(180);
161+
greenSymbol.setAngle(210);
162+
} else if (redPoint.getX() >= -77) {
163+
xOffset = -0.1;
164+
redSymbol.setAngle(0);
165+
greenSymbol.setAngle(30);
166+
}
167+
168+
// update red graphic's position
169+
redPoint = new Point(redPoint.getX() + xOffset, redPoint.getY(), redPoint.getZ(), sr);
170+
redGraphic.setGeometry(redPoint);
171+
172+
//update green graphic's position
173+
greenPoint = new Point(greenPoint.getX() - xOffset, greenPoint.getY(), greenPoint.getZ(), sr);
174+
greenGraphic.setGeometry(greenPoint);
175+
176+
// updates distance between graphics to view
177+
distance.set(Math.round(calculateDirectLinearDistance(redPoint, greenPoint)));
178+
}
179+
180+
/**
181+
* Calculates the distance, in meters, between two Points in 3D space.
182+
*
183+
* @param point1 first point
184+
* @param point2 second point
185+
* @return distance, in meters, between the two points
186+
*/
187+
private double calculateDirectLinearDistance(Point point1, Point point2) {
188+
189+
return convertToCartesianPoint(point1).distance(convertToCartesianPoint(point2));
190+
}
191+
192+
/**
193+
* Converts a Point to the Cartesian coordinate system.
194+
*
195+
* @param Point point to convert
196+
* @return a 3D point in Cartesian coordinates
197+
*/
198+
private Point3D convertToCartesianPoint(Point point) {
199+
200+
double x = convertToRadians(point.getY());
201+
double y = convertToRadians(point.getX());
202+
double z = point.getZ();
203+
204+
// in meters
205+
int earthRadius = 6371000;
206+
double radius = z + earthRadius;
207+
double radCosLat = radius * Math.cos(y);
208+
209+
double p1 = radCosLat * Math.sin(x);
210+
double p2 = radCosLat * Math.cos(x);
211+
double p3 = radius * Math.sin(y);
212+
213+
return new Point3D(p1, p2, p3);
214+
}
215+
216+
/**
217+
* Converts degrees to radians.
218+
*
219+
* @param degree degree to convert
220+
* @return the converted degrees
221+
*/
222+
private double convertToRadians(double degrees) {
223+
224+
return degrees * (Math.PI / 180);
225+
}
226+
227+
/**
228+
* Stops the animation and disposes of application resources.
229+
*/
230+
void terminate() {
231+
232+
if (sceneView != null) {
233+
sceneView.dispose();
234+
}
235+
}
236+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<?import java.lang.*?>
4+
5+
<?import javafx.geometry.Insets?>
6+
<?import javafx.scene.control.*?>
7+
<?import javafx.scene.layout.*?>
8+
<?import javafx.scene.text.Text ?>
9+
10+
<?import com.esri.arcgisruntime.mapping.view.MapView?>
11+
<?import com.esri.arcgisruntime.mapping.view.SceneView?>
12+
13+
<StackPane fx:controller="com.esri.samples.scene.CalculateDistance3DControllerer"
14+
xmlns:fx="http://javafx.com/fxml" stylesheets="/style.css">
15+
<!--SDK SceneView-->
16+
<SceneView fx:id="sceneView"/>
17+
<!--Position Parameters Pane-->
18+
<HBox StackPane.alignment="TOP_CENTER" maxWidth="200" maxHeight="50" spacing="5" styleClass="pane">
19+
<Label text="Distance: " />
20+
<Label fx:id="txtDistance" text="" />
21+
</HBox>
22+
</StackPane>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.pane {
2+
-fx-background-color: rgba(0,0,0, 0.3);
3+
-fx-padding: 15;
4+
}
5+
6+
.label {
7+
-fx-text-fill: white;
8+
-fx-font-weight: bold;
9+
-fx-font-size: 125%;
10+
}

scene/settings.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
rootProject.name = 'scene'
2-
include 'dictionary-renderer-graphics-overlay-3D',
2+
include 'calculate-distance-3D',
3+
'dictionary-renderer-graphics-overlay-3D',
34
'display-scene',
45
'distance-composite-symbol',
56
'elevation-mode',

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ include 'display-information:add-graphics-with-renderer',
3838
'map-view:display-layer-view-state-status',
3939
'map-view:map-rotation',
4040
'na:find-route',
41+
'scene:calculate-distance-3D',
4142
'scene:dictionary-renderer-graphics-overlay-3D',
4243
'scene:display-scene',
4344
'scene:distance-composite-symbol',

0 commit comments

Comments
 (0)