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
Pointand a newGraphicand add it to the overlay with e.g.graphicsOverlay.getGraphics().add(graphic). - To update the graphic’s rotation, update the
HEADINGorPITCHproperty 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 2022 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. */
module com.esri.samples.scene_properties_expressions { // require ArcGIS Maps SDK for Java module requires com.esri.arcgisruntime;
// handle SLF4J http://www.slf4j.org/codes.html#StaticLoggerBinder requires org.slf4j.nop;
// require JavaFX modules that the application uses requires javafx.graphics; requires javafx.controls; requires javafx.fxml;
// make all @FXML annotated objects reflectively accessible to the javafx.fxml module opens com.esri.samples.scene_properties_expressions to javafx.fxml;
exports com.esri.samples.scene_properties_expressions;}/* * 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(); }}/* * 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 java.io.IOException;
import javafx.application.Application;import javafx.fxml.FXMLLoader;import javafx.scene.Parent;import javafx.scene.Scene;import javafx.stage.Stage;
public class ScenePropertiesExpressionsSample extends Application {
private static ScenePropertiesExpressionsController controller;
@Override public void start(Stage stage) throws IOException { // set up the scene FXMLLoader loader = new FXMLLoader(getClass().getResource("/scene_properties_expressions/main.fxml")); Parent root = loader.load(); controller = loader.getController(); Scene scene = new Scene(root);
// set up the stage stage.setTitle("Scene Properties Expressions Sample"); stage.setWidth(800); stage.setHeight(700); stage.setScene(scene); stage.show(); }
/** * Stops and releases all resources used in application. */ @Override public void stop() { controller.terminate(); }
/** * Opens and runs application. * * @param args arguments passed to this application */ public static void main(String[] args) {
Application.launch(args); }}