This tutorial series show you how to build your first LuciadLightspeed application that loads data and allows you to navigate on a 2D/3D map:
Starting point
We take the code written in the Navigate the map article as our starting point, and expand from there.
Adding a UI widget with available layers
To keep the user of our application informed about the layers that are available on the view,
we add a widget showing the available layers: a TLcdLayerTree
.
The widget also includes check boxes to toggle the visibility of the individual layers.
Program: Creating the
TLcdLayerTree
widget
private JComponent createLayerControl(ILspView aView) {
return new TLcdLayerTree(aView);
}
Once the widget is created, we can add it to our JFrame
:
Program: Creating the
TLcdLayerTree
widget
JComponent layerControl = createLayerControl(view);
frame.add(layerControl, BorderLayout.EAST);
![lls basic app layer control](images/lls_basic_app_layer_control.png)
Figure 1. Adding the layer control
The full code
Program: The full Swing code
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JToolBar;
import com.luciad.geodesy.TLcdGeodeticDatum;
import com.luciad.model.ILcdModel;
import com.luciad.model.ILcdModelDecoder;
import com.luciad.model.TLcdCompositeModelDecoder;
import com.luciad.projection.TLcdEquidistantCylindrical;
import com.luciad.reference.TLcdGridReference;
import com.luciad.util.service.TLcdServiceLoader;
import com.luciad.view.lightspeed.ILspAWTView;
import com.luciad.view.lightspeed.ILspView;
import com.luciad.view.lightspeed.TLspViewBuilder;
import com.luciad.view.lightspeed.layer.ILspLayer;
import com.luciad.view.lightspeed.layer.ILspLayerFactory;
import com.luciad.view.lightspeed.layer.TLspCompositeLayerFactory;
import com.luciad.view.lightspeed.painter.grid.TLspLonLatGridLayerBuilder;
import com.luciad.view.lightspeed.util.TLspViewTransformationUtil;
import com.luciad.view.swing.TLcdLayerTree;
public class FirstApplicationTutorial {
public JFrame createUI() {
JFrame frame = new JFrame("First Lightspeed application");
ILspAWTView view = createView();
frame.add(view.getHostComponent(), BorderLayout.CENTER);
addData(view);
JComponent layerControl = createLayerControl(view);
frame.add(layerControl, BorderLayout.EAST);
view.addLayer(createGridLayer());
JToolBar toolBar = new JToolBar();
JRadioButton b2d = new JRadioButton(createSwitchTo2DAction(view));
b2d.setSelected(true);//start with a 2D view
JRadioButton b3d = new JRadioButton(createSwitchTo3DAction(view));
//Place the buttons in a ButtonGroup.
//This ensures that only one of them can be selected at the same time
ButtonGroup group = new ButtonGroup();
group.add(b2d);
group.add(b3d);
toolBar.add(b2d);
toolBar.add(b3d);
frame.add(toolBar, BorderLayout.NORTH);
frame.setSize(2000, 1500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return frame;
}
ILspAWTView createView() {
return TLspViewBuilder.newBuilder().buildAWTView();
}
static void addData(ILspView view) {
try {
ILcdModel shpModel = createSHPModel();
view.addLayer(createLayer(shpModel));
ILcdModel rasterModel = createRasterModel();
view.addLayer(createLayer(rasterModel));
} catch (IOException e) {
throw new RuntimeException("Problem during data decoding", e);
}
}
private static ILcdModel createSHPModel() throws IOException {
// This composite decoder can decode all supported formats
ILcdModelDecoder decoder =
new TLcdCompositeModelDecoder(TLcdServiceLoader.getInstance(ILcdModelDecoder.class));
// Decode city_125.shp to create an ILcdModel
ILcdModel shpModel = decoder.decode("Data/Shp/Usa/city_125.shp");
return shpModel;
}
private static ILcdModel createRasterModel() throws IOException {
// This composite decoder can decode all supported formats
ILcdModelDecoder decoder =
new TLcdCompositeModelDecoder(TLcdServiceLoader.getInstance(ILcdModelDecoder.class));
// Decode a sample data set (imagery data)
ILcdModel geopackageModel = decoder.decode("Data/GeoPackage/bluemarble.gpkg");
return geopackageModel;
}
private static ILspLayer createLayer(ILcdModel aModel) {
TLspCompositeLayerFactory layerFactory =
new TLspCompositeLayerFactory(TLcdServiceLoader.getInstance(ILspLayerFactory.class));
if (layerFactory.canCreateLayers(aModel)) {
Collection<ILspLayer> layers = layerFactory.createLayers(aModel);
//We only expect a single layer for our data
return layers.iterator().next();
}
throw new RuntimeException("Could not create a layer for " + aModel.getModelDescriptor().getDisplayName());
}
static ILspLayer createGridLayer() {
return TLspLonLatGridLayerBuilder.newBuilder().build();
}
private JComponent createLayerControl(ILspView aView) {
return new TLcdLayerTree(aView);
}
static Action createSwitchTo2DAction(ILspView aView) {
AbstractAction action = new AbstractAction("2D") {
@Override
public void actionPerformed(ActionEvent e) {
TLspViewTransformationUtil.setup2DView(
aView,
new TLcdGridReference(new TLcdGeodeticDatum(),
new TLcdEquidistantCylindrical()),
true
);
}
};
action.putValue(Action.SHORT_DESCRIPTION, "Switch the view to 2D");
return action;
}
private Action createSwitchTo3DAction(ILspView aView) {
AbstractAction action = new AbstractAction("3D") {
@Override
public void actionPerformed(ActionEvent e) {
TLspViewTransformationUtil.setup3DView(aView, true);
}
};
action.putValue(Action.SHORT_DESCRIPTION, "Switch the view to 3D");
return action;
}
public static void main(String[] args) {
//Swing components must be created on the Event Dispatch Thread
EventQueue.invokeLater(() -> {
JFrame frame = new FirstApplicationTutorial().createUI();
frame.setVisible(true);
});
}
}
Program: The JavaFX code
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import com.luciad.geodesy.TLcdGeodeticDatum;
import com.luciad.projection.TLcdEquidistantCylindrical;
import com.luciad.reference.TLcdGridReference;
import com.luciad.view.lightspeed.ILspView;
import com.luciad.view.lightspeed.TLspFXView;
import com.luciad.view.lightspeed.TLspViewBuilder;
import com.luciad.view.lightspeed.util.TLspViewTransformationUtil;
import samples.lightspeed.javafx.common.layercontrols.FXLayerControl;
public class FirstApplicationFXTutorial extends Application {
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("First Lightspeed application");
BorderPane borderPane = new BorderPane();
TLspFXView view = createView();
borderPane.setCenter(view.getHostNode());
FirstApplicationTutorial.addData(view);
Node layerControl = createLayerControl(view);
borderPane.setRight(layerControl);
view.addLayer(FirstApplicationTutorial.createGridLayer());
ToolBar toolBar = new ToolBar();
borderPane.setTop(toolBar);
RadioButton b2d = new RadioButton("2D");
RadioButton b3d = new RadioButton("3D");
toolBar.getItems().add(b2d);
toolBar.getItems().add(b3d);
//Place the buttons in a group.
//This ensures that only one of them can be selected at the same time
ToggleGroup group = new ToggleGroup();
b2d.setToggleGroup(group);
b3d.setToggleGroup(group);
group.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == b2d) {
TLspViewTransformationUtil.setup2DView(
view,
new TLcdGridReference(new TLcdGeodeticDatum(), new TLcdEquidistantCylindrical()), true);
} else {
TLspViewTransformationUtil.setup3DView(view, true);
}
});
b2d.setSelected(true);//start with a 2D view
Scene scene = new Scene(borderPane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private TLspFXView createView() {
return TLspViewBuilder.newBuilder().buildFXView();
}
private Node createLayerControl(ILspView aView) {
return new FXLayerControl(aView);
}
}