Update the orientation of a graphic using expressions based on its attributes.
Use case
Instead of reading the attribute and changing the rotation on the symbol for a single graphic (a manual CPU operation), you can bind the rotation to an expression that applies to the whole overlay (an automatic GPU operation). This usually results in a noticeable performance boost (smooth rotations).
How to use the sample
Adjust the heading and pitch sliders to rotate the cone.
How it works
- Create a new
GraphicsOverlay
. - Create a new
SimpleRenderer
. - Set the heading expression to
[HEADING]
and the pitch expression to[PITCH]
withsimpleRenderer.getSceneProperties().setHeadingExpression(...)
. - Apply the renderer to the graphics overlay with
graphicsOverlay.setRenderer(simpleRenderer)
. - Create a new
Point
and a newGraphic
and add it to the overlay with e.g.graphicsOverlay.getGraphics().add(graphic)
. - To update the graphic's rotation, update the
HEADING
orPITCH
property in the graphic's attributes withgraphic.getAttributes().put(key, value)
.
Relevant API
- Graphic
- GraphicsOverlay
- SceneProperties
- SceneProperties.setHeadingExpression
- SceneProperties.setPitchExpression
- SimpleRenderer
Tags
3D, expression, graphics, heading, pitch, rotation, scene, symbology
Sample Code
/* * Copyright 2017 Esri. * * 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. */ package com.esri.samples.scene_properties_expressions; import javafx.fxml.FXML; import javafx.scene.control.Slider; import javafx.scene.paint.Color; import com.esri.arcgisruntime.ArcGISRuntimeEnvironment; import com.esri.arcgisruntime.geometry.Point; import com.esri.arcgisruntime.geometry.SpatialReferences; import com.esri.arcgisruntime.mapping.ArcGISScene; import com.esri.arcgisruntime.mapping.BasemapStyle; import com.esri.arcgisruntime.mapping.view.Camera; import com.esri.arcgisruntime.mapping.view.Graphic; import com.esri.arcgisruntime.mapping.view.GraphicsOverlay; import com.esri.arcgisruntime.mapping.view.LayerSceneProperties; import com.esri.arcgisruntime.mapping.view.SceneView; import com.esri.arcgisruntime.symbology.SimpleMarkerSceneSymbol; import com.esri.arcgisruntime.symbology.SimpleRenderer; public class ScenePropertiesExpressionsController { @FXML private SceneView sceneView; @FXML private Slider headingSlider; @FXML private Slider pitchSlider; public void initialize() { // authentication with an API key or named user is required to access basemaps and other location services String yourAPIKey = System.getProperty("apiKey"); ArcGISRuntimeEnvironment.setApiKey(yourAPIKey); // create a scene and add a basemap to it ArcGISScene scene = new ArcGISScene(BasemapStyle.ARCGIS_IMAGERY); // add the SceneView to the stack pane sceneView.setArcGISScene(scene); // add a camera and initial camera position Point point = new Point(83.9, 28.4, 1000, SpatialReferences.getWgs84()); Camera camera = new Camera(point, 1000, 0, 50, 0); sceneView.setViewpointCamera(camera); // create a graphics overlay GraphicsOverlay graphicsOverlay = new GraphicsOverlay(); graphicsOverlay.getSceneProperties().setSurfacePlacement(LayerSceneProperties.SurfacePlacement.RELATIVE); sceneView.getGraphicsOverlays().add(graphicsOverlay); // add renderer using rotation expressions SimpleRenderer renderer = new SimpleRenderer(); renderer.getSceneProperties().setHeadingExpression("[HEADING]"); renderer.getSceneProperties().setPitchExpression("[PITCH]"); graphicsOverlay.setRenderer(renderer); // create a red cone graphic SimpleMarkerSceneSymbol coneSymbol = SimpleMarkerSceneSymbol.createCone(Color.RED, 100, 100); coneSymbol.setPitch(-90); // correct symbol's default pitch Graphic cone = new Graphic(new Point(83.9, 28.41, 200, SpatialReferences.getWgs84()), coneSymbol); graphicsOverlay.getGraphics().add(cone); // bind attribute values to sliders headingSlider.valueProperty().addListener(o -> cone.getAttributes().put("HEADING", headingSlider.getValue())); pitchSlider.valueProperty().addListener(o -> cone.getAttributes().put("PITCH", pitchSlider.getValue())); } /** * Disposes application resources. */ void terminate() { if (sceneView != null) sceneView.dispose(); } }