/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2014-2016, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.renderer.windbarbs; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Path2D; import javax.swing.JFrame; import javax.swing.JPanel; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.GeoTools; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.FilterFactory; import org.opengis.filter.expression.Expression; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.io.WKTWriter; /** * Unit tests for WindBarbs factory * * @author Daniele Romagnoli, GeoSolutions SAS * */ public class WindBarbsFactoryTest extends Assert { /** WKT_WRITER */ private static final WKTWriter WKT_WRITER = new WKTWriter(2); class ShapePanel extends JPanel { private Shape shp; public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.black); g2d.setTransform(AffineTransform.getTranslateInstance(-shp.getBounds().getMinX(), -shp .getBounds().getMinY())); g2d.draw(shp); g2d.dispose(); } } private WindBarbsFactory wbf = new WindBarbsFactory(); private SimpleFeature feature; private Expression exp; private FilterFactory ff; { try { ff = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints()); SimpleFeatureTypeBuilder featureTypeBuilder = new SimpleFeatureTypeBuilder(); featureTypeBuilder.setName("TestType"); featureTypeBuilder.add("geom", LineString.class, DefaultGeographicCRS.WGS84); SimpleFeatureType featureType = featureTypeBuilder.buildFeatureType(); SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType); this.feature = featureBuilder.buildFeature(null); } catch (Exception e) { throw new RuntimeException(e); } } @Test public void testInvalidAndRare() { // INF and -INF are rejected this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(Infinity)[kts]"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(-Infinity)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // NaN is x----- this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(NaN)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (5 45, -5 35), (-5 45, 5 35))"); // missing ? before KVP this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(110)[kts]emisphere=N"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // wrong separator before KVP this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(110)[kts]&emisphere=N"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); } @Test public void otherInvalidTests() { // wrong name this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "dummy(110)[kts]"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // wrong name this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "(110)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // wrong qualifier this.exp = ff.literal("wrong://" + "default(110)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // missing UoM this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(110)"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // wrong syntax for speed this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default110[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNull(shp); // null symbol shp = (Shape) wbf.getShape(null, null, this.feature); assertNull(shp); // null feature shp = (Shape) wbf.getShape(null, this.exp, null); assertNull(shp); } @Test public void testCustomBarbs() { // no module --> x-------- this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(NaN)[kts]?vectorLength=50"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); String wkt = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(wkt, "MULTILINESTRING ((0 -0, 0 50), (5 55, -5 45), (-5 55, 5 45))"); // 2.99999999 KNOTS --> calm this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(2.999999999999)[kts]?zeroWindRadius=15"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Ellipse2D); assertEquals(((Ellipse2D) shp).getHeight(), ((Ellipse2D) shp).getWidth(), 1E-6); // circle assertEquals(((Ellipse2D) shp).getHeight(), 15, 1E-6); // 15 assertEquals(((Ellipse2D) shp).getWidth(), 15, 1E-6); // 15 // 3 KNOTS --> short barb // NORTH this.exp = ff .literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(3)[kts]?vectorLength=50"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); wkt = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(wkt, "MULTILINESTRING ((0 -0, 0 50), (0 45, 10 46.25))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(3)[kts]?emisphere=S&vectorLength=50"); Shape shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), wkt); // 5 KNOTS --> short barb this.exp = ff .literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(5)[kts]?vectorLength=50"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); wkt = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(wkt, "MULTILINESTRING ((0 -0, 0 50), (0 45, 10 46.25))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(5)[kts]?hemisphere=S&vectorLength=50"); shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), wkt); // 15 KNOTS --> square this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(15)[kts]?vectorLength=30"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)), "MULTILINESTRING ((0 -0, 0 30), (0 30, 20 32.5), (0 25, 10 26.25))"); // 20 KNOTS --> 2 long feathers this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(20)[kts]?longBarbLength=50"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)), "MULTILINESTRING ((0 -0, 0 40), (0 40, 50 42.5), (0 35, 50 37.5))"); // 25 KNOTS --> complex this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(25)[kts]?longBarbLength=50"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)), "MULTILINESTRING ((0 -0, 0 40), (0 40, 50 42.5), (0 35, 50 37.5), (0 30, 25 31.25))"); // 50 KNOTS --> pennant this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(50)[kts]?basePennantLength=10"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)), "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 35, 0 30, 0 40))"); // 100 KNOTS --> 2 pennants this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(100)[kts]?vectorLength=30"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); wkt = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(wkt, "MULTILINESTRING ((0 -0, 0 30), (0 30, 20 27, 0 24, 0 30), (0 24, 20 21, 0 18, 0 24))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(100)[kts]?hemisphere=s&vectorLength=30"); shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), wkt); } @Test public void testDefaultValid() { // no module --> x-------- this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(NaN)[kts]"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (5 45, -5 35), (-5 45, 5 35))"); // 1 KNOTS --> calm this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(1)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Ellipse2D); assertEquals(((Ellipse2D) shp).getHeight(), ((Ellipse2D) shp).getWidth(), 1E-6); // circle // 2.99999999 KNOTS --> calm this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(2.999999999999)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Ellipse2D); assertEquals(((Ellipse2D) shp).getHeight(), ((Ellipse2D) shp).getWidth(), 1E-6); // circle // 3 KNOTS --> short barb // NORTH this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(3)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); String shpString = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (0 35, 10 36.25))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(3)[kts]?emisphere=S"); Shape shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), shpString); // 5 KNOTS --> short barb this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(5)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); shpString = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(shpString, "MULTILINESTRING ((0 -0, 0 40), (0 35, 10 36.25))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(5)[kts]?hemisphere=S"); shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), shpString); // 15 KNOTS --> 1 short barb + 1 long barb this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(15)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 42.5), (0 35, 10 36.25))"); // 20 KNOTS --> 2 long barbs this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(20)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 42.5), (0 35, 20 37.5))"); // 25 KNOTS --> 1 short barb + 2 long barbs this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(25)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 42.5), (0 35, 20 37.5), (0 30, 10 31.25))"); // 50 KNOTS --> pennant this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(50)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(), "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 37, 0 34, 0 40))"); // 100 KNOTS --> 2 pennants this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(100)[kts]?vectorLength=30"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); shpString = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(shpString, "MULTILINESTRING ((0 -0, 0 30), (0 30, 20 27, 0 24, 0 30), (0 24, 20 21, 0 18, 0 24))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(100)[kts]?vectorLength=30&hemisphere=s"); shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), shpString); // 175 KNOTS --> 1 short barb + 2 long barbs + 3 pennants this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(175)[kts]"); shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); shpString = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(shpString, "MULTILINESTRING ((0 -0, 0 40), (0 40, 20 37, 0 34, 0 40), (0 34, 20 31, 0 28, 0 34), (0 28, 20 25, 0 22, 0 28), (0 17, 20 19.5), (0 12, 20 14.5), (0 7, 10 8.25))"); // SOUTH make sure the same shp is flipped on y axis this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(175)[kts]?hemisphere=s"); shpS = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shpS); assertTrue(shpS instanceof Path2D); shpS = WindBarbsFactory.SOUTHERN_EMISPHERE_FLIP.createTransformedShape(shpS); // flip and check assertEquals(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shpS)).toString(), shpString); } @Test public void testUncachedBarb() { // 500 KNOTS --> Not in cache being greater than max speed. Make sure I'm getting that anyway this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(500)[kts]?vectorLength=80"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); assertNotNull(shp); assertTrue(shp instanceof Path2D); String shpString = WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)).toString(); assertEquals(shpString, "MULTILINESTRING ((0 -0, 0 80), (0 80, 20 77, 0 74, 0 80), " + "(0 74, 20 71, 0 68, 0 74), (0 68, 20 65, 0 62, 0 68), (0 62, 20 59, 0 56, 0 62), " + "(0 56, 20 53, 0 50, 0 56), (0 50, 20 47, 0 44, 0 50), (0 44, 20 41, 0 38, 0 44), " + "(0 38, 20 35, 0 32, 0 38), (0 32, 20 29, 0 26, 0 32), (0 26, 20 23, 0 20, 0 26))"); } @Ignore @Test public void testWellKnownTextLineString() { WindBarbsFactory wbf = new WindBarbsFactory(); try { this.exp = ff.literal(WindBarbsFactory.WINDBARBS_PREFIX + "default(100)[kts]?vectorLength=30"); Shape shp = (Shape) wbf.getShape(null, this.exp, this.feature); System.out.println(WindBarbsFactoryTest.WKT_WRITER.write(JTS.toGeometry(shp)) .toString()); ShapePanel p = new ShapePanel(); p.shp = shp; JFrame frame = new JFrame("Draw Shapes"); frame.getContentPane().add(p); frame.setSize(100, 100); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); System.in.read(); } catch (Exception e) { e.printStackTrace(); assertTrue(false); return; } assertTrue(true); } }