Feature layer extrusion

View on GitHub
Sample viewer app

Extrude features based on their attributes.

Image of feature layer extrusion

Use case

Extrusion is the process of stretching a flat, 2D shape vertically to create a 3D object in a scene. For example, you can extrude building polygons by a height value to create three-dimensional building shapes.

How to use the sample

Press the button to switch between using population density and total population for extrusion. Higher extrusion directly corresponds to higher attribute values.

How it works

  1. Create a ServiceFeatureTable from a URL.
  2. Create a feature layer from the service feature table.

    • Make sure to set the rendering mode to dynamic using statesFeatureLayer.setRenderingMode(FeatureLayer.RenderingMode.DYNAMIC).
  3. Apply a SimpleRenderer to the feature layer.
  4. Set the extrusion mode of the render using renderer.getSceneProperties().setExtrusionMode(SceneProperties.ExtrusionMode.ABSOLUTE_HEIGHT).
  5. Set the extrusion expression of the renderer using renderer.getSceneProperties().setExtrusionExpression(expression).

Relevant API

  • ExtrusionExpression
  • ExtrusionMode
  • FeatureLayer
  • FeatureLayer
  • SceneProperties
  • ServiceFeatureTable
  • SimpleRenderer

Tags

3D, extrude, extrusion, extrusion expression, height, renderer, scene

Sample Code

FeatureLayerExtrusionSample.java
                                                                                                                                                                              
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * 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.feature_layer_extrusion;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.SpatialReferences;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.mapping.ArcGISScene;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.view.Camera;
import com.esri.arcgisruntime.mapping.view.SceneView;
import com.esri.arcgisruntime.symbology.Renderer;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;

public class FeatureLayerExtrusionSample extends Application {

  private SceneView sceneView;

  @Override
  public void start(Stage stage) {

    StackPane stackPane = new StackPane();
    Scene fxScene = new Scene(stackPane);
    // for adding styling to any controls that are added
    fxScene.getStylesheets().add(getClass().getResource("/feature_layer_extrusion/style.css").toExternalForm());

    // set title, size, and add scene to stage
    stage.setTitle("Feature Layer Extrusion Sample");
    stage.setWidth(800);
    stage.setHeight(700);
    stage.setScene(fxScene);
    stage.show();

    // so scene can be visible within application
    ArcGISScene scene = new ArcGISScene(Basemap.createTopographic());
    sceneView = new SceneView();
    sceneView.setArcGISScene(scene);
    stackPane.getChildren().add(sceneView);

    // get us census data as a service feature table
    ServiceFeatureTable statesServiceFeatureTable = new ServiceFeatureTable("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3");

    // creates feature layer from table and add to scene
    final FeatureLayer statesFeatureLayer = new FeatureLayer(statesServiceFeatureTable);
    // feature layer must be rendered dynamically for extrusion to work
    statesFeatureLayer.setRenderingMode(FeatureLayer.RenderingMode.DYNAMIC);
    scene.getOperationalLayers().add(statesFeatureLayer);

    // symbols are used to display features (US states) from table
    SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xFF000000, 1.0f);
    SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, 0xFF0000FF, lineSymbol);
    final SimpleRenderer renderer = new SimpleRenderer(fillSymbol);
    // set the extrusion mode to absolute height
    renderer.getSceneProperties().setExtrusionMode(Renderer.SceneProperties.ExtrusionMode.ABSOLUTE_HEIGHT);
    statesFeatureLayer.setRenderer(renderer);

    // set camera to focus on state features
    Point lookAtPoint = new Point(-10974490, 4814376, 0, SpatialReferences.getWebMercator());
    sceneView.setViewpointCamera(new Camera(lookAtPoint, 10000000, 0, 20, 0));

    // create a combo box to choose between different expressions/attributes to extrude by
    ComboBox<ExtrusionAttribute> attributeComboBox = new ComboBox<>();
    attributeComboBox.setCellFactory(list -> new ListCell<ExtrusionAttribute> (){
      @Override
      protected void updateItem(ExtrusionAttribute attribute, boolean bln) {

        super.updateItem(attribute, bln);
        if (attribute != null) {
          setText(attribute.getName());
        }
      }
    });
    attributeComboBox.setConverter(new StringConverter<ExtrusionAttribute>() {

      @Override
      public String toString(ExtrusionAttribute travelMode) {
        return travelMode != null ? travelMode.getName() : "";
      }

      @Override
      public ExtrusionAttribute fromString(String fileName) {
        return null;
      }
    });
    // scale down outlier populations
    ExtrusionAttribute populationDensity = new ExtrusionAttribute("Population Density","[POP07_SQMI] * 5000 + 100000");
    // scale up density
    ExtrusionAttribute totalPopulation = new ExtrusionAttribute("Total Population", "[POP2007]/ 10");
    attributeComboBox.setItems(FXCollections.observableArrayList(populationDensity, totalPopulation));
    stackPane.getChildren().add(attributeComboBox);
    StackPane.setAlignment(attributeComboBox, Pos.TOP_LEFT);
    StackPane.setMargin(attributeComboBox, new Insets(10, 0, 0, 10));

    // set the extrusion expression on the renderer when one is chosen in the combo box
    attributeComboBox.getSelectionModel().selectedItemProperty().addListener(e -> {
      ExtrusionAttribute selectedAttribute = attributeComboBox.getSelectionModel().getSelectedItem();
      renderer.getSceneProperties().setExtrusionExpression(selectedAttribute.getExpression());
    });

    // start with total population selected
    attributeComboBox.getSelectionModel().select(totalPopulation);
  }

  /**
   * Create a helper class for showing the extrusion attribute name in a ComboBox.
   */
  private class ExtrusionAttribute {

    private String name;
    private String expression;

    public ExtrusionAttribute(String name, String expression) {
      this.name = name;
      this.expression = expression;
    }

    public String getName() {
      return name;
    }

    public String getExpression() {
      return expression;
    }
  }

  /**
   * Stops and releases all resources used in application.
   */
  @Override
  public void stop() {

    if (sceneView != null) {
      sceneView.dispose();
    }
  }

  /**
   * Opens and runs application.
   *
   * @param args arguments passed to this application
   */
  public static void main(String[] args) {

    Application.launch(args);
  }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.