I need to create a GeoJSON stream, which contains data about roads. The roads are like polygons, except they are open (the start and end points are different).
I tried to use the following code to achieve that goal:
protected void addPolyLine(final double[] coords,
final GeometryBuilder builder,
final SimpleFeatureBuilder fbuilder,
final List<SimpleFeature> features,
final String id) {
final double[] modcoords = new double[coords.length+2];
for (int i=0; i < coords.length; i++) {
modcoords[i] = coords[i];
}
modcoords[modcoords.length-2] = coords[0];
modcoords[modcoords.length-1] = coords[1];
final double[] holeStart = new double[] {coords[0], coords[1],
coords[coords.length-2], coords[coords.length - 1]};
final LinearRing shell = builder.linearRing(modcoords);
final LinearRing hole = builder.linearRing(holeStart);
final Polygon polygon = builder.polygon(shell, hole);
fbuilder.add(polygon);
final SimpleFeature feature = fbuilder.buildFeature(id);
features.add(feature);
}
It doesn't work - I get the error
java.lang.IllegalArgumentException: Invalid number of points in LinearRing (found 3 - must be 0 or >= 4)
at com.vividsolutions.jts.geom.LinearRing.validateConstruction(LinearRing.java:114)
at com.vividsolutions.jts.geom.LinearRing.<init>(LinearRing.java:106)
at com.vividsolutions.jts.geom.GeometryFactory.createLinearRing(GeometryFactory.java:341)
at org.geotools.geometry.jts.GeometryBuilder.linearRing(GeometryBuilder.java:199)
When I use builder.lineString(coords), the resulting GeoJSON contains no coordinates as it should.
How can I create a polyline (a line, which connects several point and is not closed) using GeoTools 12-RC1?
Update 1 (05.07.2015 21:22 MSK): This is how I define feature types for points, polygons and lines. Points and polygons work fine, lines don't.
private final static SimpleFeatureType POINT =
createType("Test", "Location:Point");
private final static SimpleFeatureType POLYGON =
createType("Test2", "Location:Polygon");
private final BuildingsReader buildingsReader =
new DefaultBuildingsReader();
private final static SimpleFeatureType LINE =
createType("Test3", "Line");
private static SimpleFeatureType createType(final String x1, final String x2) {
try
{
return DataUtilities.createType(x1, x2);
}
catch (final SchemaException exception) {
exception.printStackTrace();
}
return null;
}
You need to do something with createLineString like:
line=builder.createLineString(Arrays.asList(coords));
fbuilder.add(line);
final SimpleFeature feature = fbuilder.buildFeature(id);
features.add(feature);
You will need to modify your feature type to expect a line instead of a polygon.
Related
There was such a problem: working with some * .tiff, when trying to get DataRaster [] using the readDataRaster () method in the NASA WorldWind library class GeotiffReader, an exception is thrown:
ERROR j.l.Throwable - java.io.IOException: TIFF file is missing a
required tagStripOffsets
Below is the code that works with * .tiff.
Code:
private GeotiffReader reader;
private ByteBufferRaster raster;
...
reader = new GeotiffReader(file);
listDataRaster.add(reader.readDataRaster());
...
DataRaster[] dataRaster = listDataRaster.get(iter);
raster = (ByteBufferRaster)dataRaster[0];
...
raster.setDoubleAtPosition(y, x, value);
The error occurs in the line:
listDataRaster.add(reader.readDataRaster());
The method tries to return a DataRaster[] and gives the above error.
My task is to take the * .tiff ByteBufferRaster and then use setDoubleAtPosition to make changes to the grid after some calculations and rewrite * .tiff. How do I fix this error? And if not, are there other ways to accomplish my task?
Thank you all, we demand to solve this way via ExtendedGDALDataRaster
DataRasterReaderFactory readerFactory = (DataRasterReaderFactory) WorldWind
.createConfigurationComponent(AVKey.DATA_RASTER_READER_FACTORY_CLASS_NAME);
DataRasterReader dataRasterReader;
DataRaster[] dataRasters = null;
...
dataRasterReader = readerFactory.findReaderFor(file, null);
dataRasters = dataRasterReader.read(file, null);
...
rasterGdal = (ExtendedGDALDataRaster) dataRasters[0];
ElevationModel elevationModelFromGlobe = GLOBE.getElevationModel();
Sector boundingSector = rasterGdal.getSector();
int[] heightAndWidth = new int[2];
// Method for creating an empty sector by analogy with the current one
recalculationHeightAndWidth (boundingSector, elevationModelFromGlobe, heightAndWidth);
// Method to create default parameters for the sector
AVList params = getParams(boundingSector, heightAndWidth[1], heightAndWidth[0]);
raster = (ByteBufferRaster) ByteBufferRaster.createGeoreferencedRaster(params);
Dataset dataset = rasterGdal.getBestSuitedDataset(heightAndWidth[1], heightAndWidth[0], rasterGdal.getSector());
band = dataset.GetRasterBand(1);
And then for you can get the value of the height of any point from * .tiff and change it to your discretion (it will be in data)
float[] data = new float[1];
band.ReadRaster(x, y, 1, 1, band.getDataType(), data);
From a set of coordinates that define a route, I want to draw a Geometry that mimicks a theoretical highway of that track, given an arbitrary number of meters wide (e.g. 20)
I don't know if GeoTools provides tools for constructing a Geometry with such inputs, so my initial idea is to split the track coordinates (several thousands) in pairs (coord0, coord1), (coord1, coord2), ...., (coordN, coordN-1) and, with each pair, build a rectangle assuming that the two points are the midpoints of a 20m wide segment (as in Knowing two points of a rectangle, how can I figure out the other two?), and joining all the resulting geometries.
Maybe it's overkill but I haven't found a cheaper way to do this
Any ideas would be greatly appreciated!
The easy way to do this is to use a 20m buffer around a line created from your points. So some code like this to create a line from the points (:
String[] wkt = {
"Point (-0.13666168754467312 50.81919869153657743)",
"Point (-0.13622277073931291 50.82205165077141373)",
"Point (-0.13545466632993253 50.82512406840893959)",
"Point (-0.13457683271921211 50.82687973563037787)",
"Point (-0.13413791591385191 50.82907431965718104)",
"Point (-0.13951464677951447 50.8294035072611976)",
"Point (-0.14346489802775639 50.83082998687861931)",
"Point (-0.14697623247063807 50.83072025767727808)",
"Point (-0.15004865010815954 50.83390240451614517)",
"Point (-0.15740050659794308 50.8349996965295432)",
"Point (-0.16486209228906662 50.83741373895902171)",
"Point (-0.17276259478555042 50.83894994777778464)",
"Point (-0.18549118214099652 50.8387304893751022)"
};
//build line
WKTReader2 reader = new WKTReader2();
GeometryFactory gf = new GeometryFactory();
Coordinate[] points = new Coordinate[wkt.length];
int i=0;
for(String w:wkt) {
Point p;
try {
p = (Point) reader.read(w);
points[i++]=p.getCoordinate();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
LineString line = gf.createLineString(points);
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
builder.set("locations", line);
SimpleFeature feature = builder.buildFeature("1");
And then a BufferLine method like:
public SimpleFeature bufferFeature(SimpleFeature feature, Measure<Double, Length> distance) {
// extract the geometry
GeometryAttribute gProp = feature.getDefaultGeometryProperty();
CoordinateReferenceSystem origCRS = gProp.getDescriptor().getCoordinateReferenceSystem();
Geometry geom = (Geometry) feature.getDefaultGeometry();
Geometry pGeom = geom;
MathTransform toTransform, fromTransform = null;
// reproject the geometry to a local projection
if (!(origCRS instanceof ProjectedCRS)) {
Point c = geom.getCentroid();
double x = c.getCoordinate().x;
double y = c.getCoordinate().y;
String code = "AUTO:42001," + x + "," + y;
// System.out.println(code);
CoordinateReferenceSystem auto;
try {
auto = CRS.decode(code);
toTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
fromTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
pGeom = JTS.transform(geom, toTransform);
} catch (MismatchedDimensionException | TransformException | FactoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// buffer
Geometry out = buffer(pGeom, distance.doubleValue(SI.METER));
Geometry retGeom = out;
// reproject the geometry to the original projection
if (!(origCRS instanceof ProjectedCRS)) {
try {
retGeom = JTS.transform(out, fromTransform);
} catch (MismatchedDimensionException | TransformException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// return a new feature containing the geom
SimpleFeatureType schema = feature.getFeatureType();
SimpleFeatureTypeBuilder ftBuilder = new SimpleFeatureTypeBuilder();
ftBuilder.setCRS(origCRS);
// ftBuilder.setDefaultGeometry("buffer");
ftBuilder.addAll(schema.getAttributeDescriptors());
ftBuilder.setName(schema.getName());
SimpleFeatureType nSchema = ftBuilder.buildFeatureType();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(nSchema);
List<Object> atts = feature.getAttributes();
for (int i = 0; i < atts.size(); i++) {
if (atts.get(i) instanceof Geometry) {
atts.set(i, retGeom);
}
}
SimpleFeature nFeature = builder.buildFeature(null, atts.toArray());
return nFeature;
}
/**
* create a buffer around the geometry, assumes the geometry is in the same
* units as the distance variable.
*
* #param geom
* a projected geometry.
* #param dist
* a distance for the buffer in the same units as the projection.
* #return
*/
private Geometry buffer(Geometry geom, double dist) {
Geometry buffer = geom.buffer(dist);
return buffer;
}
The tricky part is reprojecting into a locally flat CRS so that you can use metres for the buffer size. If you know of a locally good projection you could just use that (in this case we could have used OSGB (EPSG:27700) for better results).
This gives the following map:
I have a project where I want to load in a given shapefile, and pick out polygons above a certain size before writing the results to a new shapefile. Maybe not the most efficient, but I've got code that successfully does all of that, right up to the point where it is supposed to write the shapefile. I get no errors, but the resulting shapefile has no usable data in it. I've followed as many tutorials as possible, but still I'm coming up blank.
The first bit of code is where I read in a shapefile, pickout the polygons I want, and put then into a feature collection. This part seems to work fine as far as I can tell.
public class ShapefileTest {
public static void main(String[] args) throws MalformedURLException, IOException, FactoryException, MismatchedDimensionException, TransformException, SchemaException {
File oldShp = new File("Old.shp");
File newShp = new File("New.shp");
//Get data from the original ShapeFile
Map<String, Object> map = new HashMap<String, Object>();
map.put("url", oldShp.toURI().toURL());
//Connect to the dataStore
DataStore dataStore = DataStoreFinder.getDataStore(map);
//Get the typeName from the dataStore
String typeName = dataStore.getTypeNames()[0];
//Get the FeatureSource from the dataStore
FeatureSource<SimpleFeatureType, SimpleFeature> source = dataStore.getFeatureSource(typeName);
SimpleFeatureCollection collection = (SimpleFeatureCollection) source.getFeatures(); //Get all of the features - no filter
//Start creating the new Shapefile
final SimpleFeatureType TYPE = createFeatureType(); //Calls a method that builds the feature type - tested and works.
DefaultFeatureCollection newCollection = new DefaultFeatureCollection(); //To hold my new collection
try (FeatureIterator<SimpleFeature> features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next(); //Get next feature
SimpleFeatureBuilder fb = new SimpleFeatureBuilder(TYPE); //Create a new SimpleFeature based on the original
Integer level = (Integer) feature.getAttribute(1); //Get the level for this feature
MultiPolygon multiPoly = (MultiPolygon) feature.getDefaultGeometry(); //Get the geometry collection
//First count how many new polygons we will have
int numNewPoly = 0;
for (int i = 0; i < multiPoly.getNumGeometries(); i++) {
double area = getArea(multiPoly.getGeometryN(i));
if (area > 20200) {
numNewPoly++;
}
}
//Now build an array of the larger polygons
Polygon[] polys = new Polygon[numNewPoly]; //Array of new geometies
int iPoly = 0;
for (int i = 0; i < multiPoly.getNumGeometries(); i++) {
double area = getArea(multiPoly.getGeometryN(i));
if (area > 20200) { //Write the new data
polys[iPoly] = (Polygon) multiPoly.getGeometryN(i);
iPoly++;
}
}
GeometryFactory gf = new GeometryFactory(); //Create a geometry factory
MultiPolygon mp = new MultiPolygon(polys, gf); //Create the MultiPolygonyy
fb.add(mp); //Add the geometry collection to the feature builder
fb.add(level);
fb.add("dBA");
SimpleFeature newFeature = SimpleFeatureBuilder.build( TYPE, new Object[]{mp, level,"dBA"}, null );
newCollection.add(newFeature); //Add it to the collection
}
At this point I have a collection that looks right - it has the correct bounds and everything. The next bit if code is where I put it into a new Shapefile.
//Time to put together the new Shapefile
Map<String, Serializable> newMap = new HashMap<String, Serializable>();
newMap.put("url", newShp.toURI().toURL());
newMap.put("create spatial index", Boolean.TRUE);
DataStore newDataStore = DataStoreFinder.getDataStore(newMap);
newDataStore.createSchema(TYPE);
String newTypeName = newDataStore.getTypeNames()[0];
SimpleFeatureStore fs = (SimpleFeatureStore) newDataStore.getFeatureSource(newTypeName);
Transaction t = new DefaultTransaction("add");
fs.setTransaction(t);
fs.addFeatures(newCollection);
t.commit();
ReferencedEnvelope env = fs.getBounds();
}
}
I put in the very last code to check the bounds of the FeatureStore fs, and it comes back null. Obviously, loading the newly created shapefile (which DOES get created and is ab out the right size), nothing shows up.
The solution actually had nothing to do with the code I posted - it had everything to do with my FeatureType definition. I did not include the "the_geom" to my polygon feature type, so nothing was getting written to the file.
I believe you are missing the step to finalize/close the file. Try adding this after the the t.commit line.
fs.close();
As an expedient alternative, you might try out the Shapefile dumper utility mentioned in the Shapefile DataStores docs. Using that may simplify your second code block into two or three lines.
I am very new to GeoTools. I would like to create a hex grid and save it to a SHP file. But something goes wrong along the way (the saved SHP file is empty). In the debug mode I found that the gird is correctly created and contains a bunch of polygons that make sense. Writing those to a shape file proves to be difficult. I followed the tutorial on GeoTools' website, but that does not quite do it yet. I suspect TYPE to be incorrectly defined, but could not find out how to define it correctly.
Any help of how to store the grid into a SHP file is highly appreciated.
ReferencedEnvelope gridBounds = new ReferencedEnvelope(xMin, xMax, yMin, yMax, DefaultGeographicCRS.WGS84);
// length of each hexagon edge
double sideLen = 0.5;
// max distance between vertices
double vertexSpacing = sideLen / 20;
SimpleFeatureSource grid = Grids.createHexagonalGrid(gridBounds, sideLen, vertexSpacing);
/*
* We use the DataUtilities class to create a FeatureType that will describe the data in our
* shapefile.
*
* See also the createFeatureType method below for another, more flexible approach.
*/
final SimpleFeatureType TYPE = createFeatureType();
/*
* Get an output file name and create the new shapefile
*/
File newFile = new File("D:/test/shape.shp");
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
Map<String, Serializable> params = new HashMap<String, Serializable>();
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
newDataStore.createSchema(TYPE);
/*
* You can comment out this line if you are using the createFeatureType method (at end of
* class file) rather than DataUtilities.createType
*/
newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84);
/*
* Write the features to the shapefile
*/
Transaction transaction = new DefaultTransaction("create");
String typeName = newDataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
if (featureSource instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(grid.getFeatures());
transaction.commit();
} catch (Exception problem) {
problem.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
}
} else {
System.out.println(typeName + " does not support read/write access");
}
private static SimpleFeatureType createFeatureType() {
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Location");
builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference system
// add attributes in order
builder.add("Polygon", Polygon.class);
builder.length(15).add("Name", String.class); // <- 15 chars width for name field
// build the type
final SimpleFeatureType LOCATION = builder.buildFeatureType();
return LOCATION;
}
I was practicing on some face recognition and detection codes using Java on JavaCv on Eclpise Juno. The Thing is i was trying to run the sample code below but i cant get the expected result or output. The sample code is as follows
import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.*;
import com.googlecode.javacv.cpp.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_calib3d.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
public class Demo {
public static void main(String[] args) throws Exception {
String classifierName = null;
if (args.length > 0) {
classifierName = args[0];
} else {
System.err.println("C://opencv/data/haarcascades\"haarcascade_frontalface_alt.xml\".");
System.exit(1);
}
// Preload the opencv_objdetect module to work around a known bug.
Loader.load(opencv_objdetect.class);
// We can "cast" Pointer objects by instantiating a new object of the desired class.
CvHaarClassifierCascade classifier = new CvHaarClassifierCascade(cvLoad(classifierName));
if (classifier.isNull()) {
System.err.println("Error loading classifier file \"" + classifierName + "\".");
System.exit(1);
}
// CanvasFrame is a JFrame containing a Canvas component, which is hardware accelerated.
// It can also switch into full-screen mode when called with a screenNumber.
CanvasFrame frame = new CanvasFrame("Some Title");
// OpenCVFrameGrabber uses opencv_highgui, but other more versatile FrameGrabbers
// include DC1394FrameGrabber, FlyCaptureFrameGrabber, OpenKinectFrameGrabber,
// PS3EyeFrameGrabber, VideoInputFrameGrabber, and FFmpegFrameGrabber.
FrameGrabber grabber = new OpenCVFrameGrabber(0);
grabber.start();
// FAQ about IplImage:
// - For custom raw processing of data, getByteBuffer() returns an NIO direct
// buffer wrapped around the memory pointed by imageData.
// - To get a BufferedImage from an IplImage, you may call getBufferedImage().
// - The createFrom() factory method can construct an IplImage from a BufferedImage.
// - There are also a few copy*() methods for BufferedImage<->IplImage data transfers.
IplImage grabbedImage = grabber.grab();
int width = grabbedImage.width();
int height = grabbedImage.height();
IplImage grayImage = IplImage.create(width, height, IPL_DEPTH_8U, 1);
IplImage rotatedImage = grabbedImage.clone();
// Let's create some random 3D rotation...
CvMat randomR = CvMat.create(3, 3), randomAxis = CvMat.create(3, 1);
// We can easily and efficiently access the elements of CvMat objects
// with the set of get() and put() methods.
randomAxis.put((Math.random()-0.5)/4, (Math.random()-0.5)/4, (Math.random()-0.5)/4);
cvRodrigues2(randomAxis, randomR, null);
double f = (width + height)/2.0; randomR.put(0, 2, randomR.get(0, 2)*f);
randomR.put(1, 2, randomR.get(1, 2)*f);
randomR.put(2, 0, randomR.get(2, 0)/f); randomR.put(2, 1, randomR.get(2, 1)/f);
System.out.println(randomR);
// Objects allocated with a create*() or clone() factory method are automatically released
// by the garbage collector, but may still be explicitly released by calling release().
// You shall NOT call cvReleaseImage(), cvReleaseMemStorage(), etc.
//on objects allocated this way.
CvMemStorage storage = CvMemStorage.create();
// We can allocate native arrays using constructors taking an integer as argument.
CvPoint hatPoints = new CvPoint(3);
// Again, FFmpegFrameRecorder also exists as a more versatile alternative.
FrameRecorder recorder = new OpenCVFrameRecorder("output.avi", width, height);
recorder.start();
while (frame.isVisible() && (grabbedImage = grabber.grab()) != null) {
cvClearMemStorage(storage);
// Let's try to detect some faces! but we need a grayscale image...
cvCvtColor(grabbedImage, grayImage, CV_BGR2GRAY);
CvSeq faces = cvHaarDetectObjects(grayImage, classifier, storage,
1.1, 3, CV_HAAR_DO_CANNY_PRUNING);
int total = faces.total();
for (int i = 0; i < total; i++) {
CvRect r = new CvRect(cvGetSeqElem(faces, i));
int x = r.x(), y = r.y(), w = r.width(), h = r.height();
cvRectangle(grabbedImage, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0);
// To access the elements of a native array, use the position() method.
hatPoints.position(0).x(x-w/10) .y(y-h/10);
hatPoints.position(1).x(x+w*11/10).y(y-h/10);
hatPoints.position(2).x(x+w/2) .y(y-h/2);
cvFillConvexPoly(grabbedImage, hatPoints.position(0), 3, CvScalar.GREEN, CV_AA, 0);
}
// Let's find some contours! but first some thresholding...
cvThreshold(grayImage, grayImage, 64, 255, CV_THRESH_BINARY);
// To check if an output argument is null we may call either isNull() or equals(null).
CvSeq contour = new CvSeq(null);
cvFindContours(grayImage, storage, contour, Loader.sizeof(CvContour.class),
CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
while (contour != null && !contour.isNull()) {
if (contour.elem_size() > 0) {
CvSeq points = cvApproxPoly(contour, Loader.sizeof(CvContour.class),
storage, CV_POLY_APPROX_DP, cvContourPerimeter(contour)*0.02, 0);
cvDrawContours(grabbedImage, points, CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);
}
contour = contour.h_next();
}
cvWarpPerspective(grabbedImage, rotatedImage, randomR);
frame.showImage(rotatedImage);
recorder.record(rotatedImage);
}
recorder.stop();
grabber.stop();
frame.dispose();
}
}
The Output i am getting is a line printed in red and its like.
C://opencv/data/haarcascades"haarcascade_frontalface_alt.xml".
Can anybody show what i missed?
I am new to image processing and so please can anyone indicate me where i could get good tutorials and sample source codes that could teach me how to master all the in-built functions in JavaCv and their functionalities? I was working on my final year project and really need your hand on this one.
With lots of respect
Sisay
haarcascade_frontalface_alt.xml is trained classifier for detecting frontal face. It is usually present in opencv_installation_folder/opencv/data/haarcascade folder. you can give the direct path of your classifier instead of taking it from command line as
classifierName = opencv_installation_folder/opencv/data/harcascade/haarcascade_frontalface_alt.xml
that demo expects you to give it the cascade-file as an argument. it just stops, if it does not get one.
maybe you want to change the beginning like this:
public class Demo {
public static void main(String[] args) throws Exception {
String classifierName = "C:/opencv/data/haarcascades/haarcascade_frontalface_alt.xml";
if (args.length > 0) {
classifierName = args[0];
}
like that, it takes an arg from cmdline if present, else it takes the default-value