package com.revolsys.evelvation.tin.test; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import com.revolsys.awt.WebColors; import com.revolsys.elevation.cloud.las.LasPointCloud; import com.revolsys.elevation.tin.TriangulatedIrregularNetwork; import com.revolsys.elevation.tin.quadedge.QuadEdgeDelaunayTinBuilder; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.Triangle; import com.revolsys.geometry.model.impl.Circle; import com.revolsys.spring.resource.PathResource; public class TriangulationVisualization { private static final int COUNT = Integer.MAX_VALUE; private static boolean showCircumcircle = false; private static boolean writeFile = false; public static void displayTin(final TriangulatedIrregularNetwork tin) { BoundingBox boundingBox = tin.getBoundingBox(); double mapWidth = boundingBox.getWidth() + 4; double mapHeight = boundingBox.getHeight() + 4; if (mapHeight > mapWidth) { boundingBox = boundingBox.expand((mapHeight - mapWidth) / 2, 0); mapWidth = boundingBox.getWidth(); } else if (mapHeight < mapWidth) { boundingBox = boundingBox.expand(0, (mapWidth - mapHeight) / 2); mapHeight = boundingBox.getHeight(); } final AffineTransform transform = new AffineTransform(); final double pixelsPerXUnit = 800 / mapWidth; final double pixelsPerYUnit = -800 / mapHeight; final double originX = boundingBox.getMinX() - 2; final double originY = boundingBox.getMaxY() + 2; transform.concatenate(AffineTransform.getScaleInstance(pixelsPerXUnit, pixelsPerYUnit)); transform.concatenate(AffineTransform.getTranslateInstance(-originX, -originY)); SwingUtilities.invokeLater(() -> { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(850, 850); frame.setVisible(true); frame.setLayout(new BorderLayout()); frame.add(new JPanel() { /** * */ private static final long serialVersionUID = 1L; @Override public void paint(final Graphics graphics) { final Graphics2D g2 = (Graphics2D)graphics; g2.setPaint(WebColors.White); g2.fillRect(0, 0, 800, 800); final AffineTransform oldTransform = g2.getTransform(); g2.transform(transform); synchronized (tin) { g2.setStroke(new BasicStroke((float)(1 / pixelsPerXUnit))); tin.forEachTriangle((triangle) -> { g2.setPaint(WebColors.newAlpha(WebColors.Aqua, 25)); g2.fill(triangle); g2.setColor(WebColors.Black); g2.draw(triangle); }); if (showCircumcircle) { tin.forEachTriangle((triangle) -> { final double x1 = triangle.getX(1); final double x2 = triangle.getY(1); final double[] centre = Triangle.getCircumcentreCoordinates(triangle.getX(0), triangle.getY(0), x1, x2, triangle.getX(2), triangle.getY(2)); final double centreX = centre[0]; final double centreY = centre[1]; final double size = 7; final double half = size / 2; final Ellipse2D.Double shape = new Ellipse2D.Double(centreX - half / pixelsPerXUnit, centreY - half / pixelsPerXUnit, size / pixelsPerXUnit, size / pixelsPerXUnit); g2.setPaint(WebColors.Yellow); g2.fill(shape); g2.setColor(WebColors.Black); g2.draw(shape); }); tin.forEachTriangle((triangle) -> { final double x1 = triangle.getX(1); final double x2 = triangle.getY(1); final double[] centre = Triangle.getCircumcentreCoordinates(triangle.getX(0), triangle.getY(0), x1, x2, triangle.getX(2), triangle.getY(2)); final Circle circle = triangle.getCircumcircle(); final double centreX = centre[0]; final double centreY = centre[1]; final double radius = circle.getRadius(); final Ellipse2D ellipse = new Ellipse2D.Double(centreX - radius, centreY - radius, radius * 2, radius * 2); g2.setColor(WebColors.Red); g2.draw(ellipse); }); } // for (int vertexIndex = 0; vertexIndex < tin.getVertexCount(); vertexIndex++) { // final Point point = tin.getVertex(vertexIndex); // final double x = point.getX(); // final double y = point.getY(); // final double size = 7; // final double half = size / 2; // final Ellipse2D.Double shape = new Ellipse2D.Double(x - half / pixelsPerXUnit, // y - half / pixelsPerXUnit, size / pixelsPerXUnit, size / pixelsPerXUnit); // g2.setPaint(WebColors.Yellow); // g2.fill(shape); // g2.setColor(WebColors.Black); // g2.draw(shape); // } // { // final Point point = pointHolder.getValue(); // if (point != null) { // g2.setPaint(WebColors.Red); // final double x = point.getX(); // final double y = point.getY(); // final double size = 9; // final double half = size / 2; // g2.fill(new Ellipse2D.Double(x - half / pixelsPerXUnit, y - half / pixelsPerXUnit, // size / pixelsPerXUnit, size / pixelsPerXUnit)); // } // } // g2.setTransform(oldTransform); // g2.translate(0, 800); // g2.setPaint(WebColors.Green); // for (int vertexIndex = 0; vertexIndex < tin.getVertexCount(); vertexIndex++) { // final Point point = tin.getVertex(vertexIndex); // final double x = point.getX(); // final double y = point.getY(); // final int screenX = (int)((x + 2) * pixelsPerXUnit); // final int screenY = (int)((y + 2) * pixelsPerYUnit); // g2.drawString(Integer.toString(vertexIndex), screenX + 5, screenY); // } } } }, BorderLayout.CENTER); }); } public static void main(final String[] args) { tinVisual(); } public static void tinVisual() { final GeometryFactory geometryFactory = GeometryFactory.floating(3005, 3); final List<Point> points = new ArrayList<>(); for (int x = 1; x < 10; x++) { for (int y = 1; y < 10; y++) { points.add(geometryFactory.point(x, y, x + y / 10.0)); } } tinVisual(geometryFactory, points); } // // public static void testDem() throws IOException { // final GeometryFactory geometryFactory = GeometryFactory.fixed(3005, 1000.0); // final gbaElevationConfig config = new gbaElevationConfig(); // final Path basePath = config.getBasePath(); // final boolean processAll = false; // final RecordDefinition extentRecordDefinition = new RecordDefinitionBuilder("extents") // // .addField("LETTER_BLOCK", DataTypes.STRING) // // .addField("POLYGON", DataTypes.POLYGON) // // .setGeometryFactory(geometryFactory) // // .getRecordDefinition(); // final Path trim25kDirectory = config.getTrim25mAlbersDirectory(); // RecordWriter writer = null; // if (processAll) { // writer = RecordWriter.newRecordWriter(extentRecordDefinition, // trim25kDirectory.resolve("extents.shp")); // } // try ( // RecordWriter writer2 = writer) { // // Files.walk(trim25kDirectory).forEach((demZipFile) -> { // final String baseName = Paths.getBaseName(demZipFile); // if (processAll || baseName.equals("92i-albers-elevation.asc")) { // try { // final String fileNameExtension = Paths.getFileNameExtension(demZipFile); // if (fileNameExtension.equals("zip")) { // final FileSystem fileSystem = FileSystems.newFileSystem(demZipFile, null); // final String letterBlock = baseName.substring(0, baseName.indexOf('-')); // final Path demFile = fileSystem.getPath(baseName); // // final Map<String, Object> properties = new HashMap<>(); // properties.put(GriddedElevationModel.GEOMETRY_FACTORY, geometryFactory); // properties.put(EsriAsciiGriddedElevation.PROPERTY_READ_DATA, !processAll); // // final GriddedElevationModel sourceModel = GriddedElevationModel // .newGriddedElevationModel(demFile, properties); // final BoundingBox sourceBoundingBox = sourceModel.getBoundingBox(); // if (!processAll) { // for (final RectangularMapTile targetTile : gbaElevationConfig.GRID_25m // .getTiles(sourceBoundingBox)) { // final BoundingBox targetBoundingBox = targetTile.getBoundingBox(); // final boolean contained = sourceBoundingBox.covers(targetBoundingBox); // if (contained) { // System.out.println(targetTile); // } else { // System.err.println(targetTile); // } // final Path targetPath = config.getGriddedElevationModelPath(3005, 25, targetTile, // "asc"); // final GriddedElevationModel targetModel = config.getGriddedElevationModel(3005, // 25, targetTile, "asc"); // final int targetHeight = targetModel.getHeight(); // final int targetWidth = targetModel.getWidth(); // for (int targetJ = 0; targetJ < targetHeight; targetJ++) { // for (int targetI = 0; targetI < targetWidth; targetI++) { // final double x = targetModel.getX(targetI); // final double y = targetModel.getY(targetJ); // final int sourceI = sourceModel.getCellX(x); // final int sourceJ = sourceModel.getCellY(y); // if (!sourceModel.isNull(sourceI, sourceJ)) { // final short elevation = sourceModel.getElevationShort(sourceI, sourceJ); // targetModel.setElevation(targetI, targetJ, elevation); // } // } // } // targetModel.writeGriddedElevationModel(targetPath); // } // } // // if (writer2 != null) { // final Record record = writer2.newRecord(); // record.setValue("LETTER_BLOCK", letterBlock); // final BoundingBox boundingBox = sourceModel.getBoundingBox(); // record.setGeometryValue(boundingBox.toPolygon(1)); // writer2.write(record); // } // } // } catch (final Exception e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // }); // } // } private static void tinVisual(final GeometryFactory geometryFactory, final List<Point> points) { final QuadEdgeDelaunayTinBuilder tinBuilder = new QuadEdgeDelaunayTinBuilder(geometryFactory); tinBuilder.insertVertices(points); final TriangulatedIrregularNetwork tin = tinBuilder.newTriangulatedIrregularNetwork(); displayTin(tin); } public static void tinVisualLas() { final PathResource sourceFile = new PathResource( "/data/dem/elevation/las/bc_093g057c_xl2m_2015_dem_ground.las"); final TriangulatedIrregularNetwork tin; try ( final LasPointCloud pointCloud = new LasPointCloud(sourceFile)) { tin = pointCloud.newTriangulatedIrregularNetwork(); } if (writeFile) { tin.writeTriangulatedIrregularNetwork( new PathResource("/data/elevation/tin/093/g/093g057.tin")); } displayTin(tin); } }