To visualize polygons and polylines with rounded corners, you can use the classes TLcdRoundedPolygon
and TLcdRoundedPolyline
.
You may be using other shapes in your model though, such as ILcdPolyline
and ILcdPolygon
. This article shows you how to round the corners of those shapes when you visualize them in a Lightspeed view.
How to do it?
Create a custom ALspStyleTargetProvider
that provides rounded shapes as the visualization targets and the original shapes as the edit targets.
With that, you can edit the original shapes as control points of the rounded shapes: you can move individual control points,
move the whole set of control points, and insert or remove control points.
You can easily convert the original shapes to rounded shapes using the rounding methods in TLcdShapeUtil
.
public static class RoundedLineStyleTargetProvider extends ALspStyleTargetProvider {
@Override
public void getStyleTargetsSFCT(Object aObject, TLspContext aContext, List<Object> aResultSFCT) {
if (aObject instanceof ILcdPolygon) {
aResultSFCT.add(TLcdShapeUtil.round(aContext.getModelReference(), (ILcdPolygon) aObject, 0.5));
} else if (aObject instanceof ILcdPolyline) {
aResultSFCT.add(TLcdShapeUtil.round(aContext.getModelReference(), (ILcdPolyline) aObject, 0.5));
} else {
aResultSFCT.add(aObject);
}
}
@Override
public void getEditTargetsSFCT(Object aObject, TLspContext aContext, List<Object> aResultSFCT) {
// We return the original shapes as edit targets. We use the original shape for editing
// to ensure we can edit our rounded shapes by moving the control points that are used
// to define the rounded shapes.
aResultSFCT.add(aObject);
}
}
To apply the custom ALspStyleTargetProvider
, create an ALspStyler
that configures your ALspStyleTargetProvider
as the geometry of the objects when it submits styles for them.
public static class LineStyler extends ALspStyler {
private final boolean fSelected;
public LineStyler(boolean aSelected) {
fSelected = aSelected;
}
@Override
public void style(Collection<?> aObjects, ALspStyleCollector aStyleCollector, TLspContext aContext) {
TLspLineStyle.Builder<?> styleBuilder = TLspLineStyle.newBuilder()
.width(5);
if (fSelected) {
styleBuilder.color(Color.MAGENTA);
} else {
styleBuilder.color(Color.CYAN);
}
aStyleCollector.objects(aObjects)
// Set the style target provider
.geometry(new RoundedLineStyleTargetProvider())
.style(styleBuilder.build())
.submit();
}
}
For more information about using a style target provider, see Deriving geometry from objects with a style target provider. |
Full code
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.util.Collection;
import java.util.List;
import javax.swing.JFrame;
import com.luciad.model.ILcdModel;
import com.luciad.model.TLcdVectorModel;
import com.luciad.reference.TLcdGeodeticReference;
import com.luciad.shape.ILcdPolygon;
import com.luciad.shape.ILcdPolyline;
import com.luciad.shape.TLcdShapeUtil;
import com.luciad.shape.shape2D.TLcd2DEditablePointList;
import com.luciad.shape.shape2D.TLcdLonLatPolygon;
import com.luciad.shape.shape2D.TLcdLonLatPolyline;
import com.luciad.shape.shape2D.TLcdRoundedPolygon;
import com.luciad.shape.shape2D.TLcdRoundedPolyline;
import com.luciad.view.lightspeed.ILspAWTView;
import com.luciad.view.lightspeed.TLspContext;
import com.luciad.view.lightspeed.TLspViewBuilder;
import com.luciad.view.lightspeed.layer.ILspLayer;
import com.luciad.view.lightspeed.layer.TLspPaintState;
import com.luciad.view.lightspeed.layer.shape.TLspShapeLayerBuilder;
import com.luciad.view.lightspeed.style.TLspLineStyle;
import com.luciad.view.lightspeed.style.styler.ALspStyleCollector;
import com.luciad.view.lightspeed.style.styler.ALspStyleTargetProvider;
import com.luciad.view.lightspeed.style.styler.ALspStyler;
import samples.lightspeed.common.FitUtil;
public class RoundedLinesTutorial {
public static class RoundedLineStyleTargetProvider extends ALspStyleTargetProvider {
@Override
public void getStyleTargetsSFCT(Object aObject, TLspContext aContext, List<Object> aResultSFCT) {
if (aObject instanceof ILcdPolygon) {
aResultSFCT.add(TLcdShapeUtil.round(aContext.getModelReference(), (ILcdPolygon) aObject, 0.5));
} else if (aObject instanceof ILcdPolyline) {
aResultSFCT.add(TLcdShapeUtil.round(aContext.getModelReference(), (ILcdPolyline) aObject, 0.5));
} else {
aResultSFCT.add(aObject);
}
}
@Override
public void getEditTargetsSFCT(Object aObject, TLspContext aContext, List<Object> aResultSFCT) {
// We return the original shapes as edit targets. We use the original shape for editing
// to ensure we can edit our rounded shapes by moving the control points that are used
// to define the rounded shapes.
aResultSFCT.add(aObject);
}
}
public static class LineStyler extends ALspStyler {
private final boolean fSelected;
public LineStyler(boolean aSelected) {
fSelected = aSelected;
}
@Override
public void style(Collection<?> aObjects, ALspStyleCollector aStyleCollector, TLspContext aContext) {
TLspLineStyle.Builder<?> styleBuilder = TLspLineStyle.newBuilder()
.width(5);
if (fSelected) {
styleBuilder.color(Color.MAGENTA);
} else {
styleBuilder.color(Color.CYAN);
}
aStyleCollector.objects(aObjects)
// Set the style target provider
.geometry(new RoundedLineStyleTargetProvider())
.style(styleBuilder.build())
.submit();
}
}
private static ILcdModel createModel() {
TLcdVectorModel model = new TLcdVectorModel(new TLcdGeodeticReference());
//
// Hereunder is an example of how to create a TLcdRoundedPolyline and TLcdRoundedPolygon
// These shapes will not be transformed by our RoundedLineStyleTargetProvider
// Note that TLcdRoundedPolyline and TLcdRoundedPolygon do not implement ILcdPolyline or ILcdPolygon
//
TLcd2DEditablePointList roundedLineControlPoints = new TLcd2DEditablePointList();
roundedLineControlPoints.append2DPoint(0, 0);
roundedLineControlPoints.append2DPoint(0, 1);
roundedLineControlPoints.append2DPoint(1, 1);
roundedLineControlPoints.append2DPoint(1, 2);
roundedLineControlPoints.append2DPoint(2, 2);
TLcdRoundedPolyline roundedLine = new TLcdRoundedPolyline(model.getModelReference(), roundedLineControlPoints, 0.5);
model.addElement(roundedLine, ILcdModel.NO_EVENT);
TLcd2DEditablePointList roundedPolygonControlPoints = new TLcd2DEditablePointList();
roundedPolygonControlPoints.append2DPoint(-1, -1);
roundedPolygonControlPoints.append2DPoint(-2, -1);
roundedPolygonControlPoints.append2DPoint(-2, -2);
roundedPolygonControlPoints.append2DPoint(-3, -2);
roundedPolygonControlPoints.append2DPoint(-3, -3);
TLcdRoundedPolygon roundedPolygon = new TLcdRoundedPolygon(model.getModelReference(), roundedPolygonControlPoints, 0.5);
model.addElement(roundedPolygon, ILcdModel.NO_EVENT);
//
// Hereunder we add a 'regular' ILcdPolyline and ILcdPolygon to our model.
// These shapes will be transformed into rounded shapes by our RoundedLineStyleTargetProvider
//
TLcd2DEditablePointList polyLineControlPoints = new TLcd2DEditablePointList();
polyLineControlPoints.append2DPoint(-1, 0);
polyLineControlPoints.append2DPoint(-1, 1);
polyLineControlPoints.append2DPoint(-2, 1);
polyLineControlPoints.append2DPoint(-2, 2);
polyLineControlPoints.append2DPoint(-3, 2);
ILcdPolyline polyLine = new TLcdLonLatPolyline(polyLineControlPoints);
model.addElement(polyLine, ILcdModel.NO_EVENT);
TLcd2DEditablePointList polygonControlPoints = new TLcd2DEditablePointList();
polygonControlPoints.append2DPoint(0, -1);
polygonControlPoints.append2DPoint(1, -1);
polygonControlPoints.append2DPoint(1, -2);
polygonControlPoints.append2DPoint(2, -2);
polygonControlPoints.append2DPoint(2, -3);
ILcdPolygon polygon = new TLcdLonLatPolygon(polygonControlPoints);
model.addElement(polygon, ILcdModel.NO_EVENT);
return model;
}
private static ILspLayer createLayer(ILcdModel aModel) {
return TLspShapeLayerBuilder.newBuilder()
.model(aModel)
.bodyEditable(true)
.bodyStyler(TLspPaintState.REGULAR, new LineStyler(false))
.bodyStyler(TLspPaintState.SELECTED, new LineStyler(true))
.bodyStyler(TLspPaintState.EDITED, new LineStyler(true))
.build();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
// create the view
ILspAWTView view = TLspViewBuilder.newBuilder()
.buildAWTView();
// create the custom decoration layer and add it to the view
ILcdModel model = createModel();
ILspLayer lineLayer = createLayer(model);
view.addLayer(lineLayer);
// display the view in a frame
JFrame frame = new JFrame("Rounded Lines");
frame.add(view.getHostComponent(), BorderLayout.CENTER);
frame.setSize(350, 350);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// fit on the layer
FitUtil.fitOnLayers(frame, view, false, lineLayer);
});
}
}