Adding serialization, equals and hashCode to GeometryCollectionBuilder

This commit is contained in:
Christoph Büscher 2015-11-23 15:36:42 +01:00
parent 1f5ee642fd
commit 2a810d680d
16 changed files with 203 additions and 10 deletions

View File

@ -108,15 +108,14 @@ public class EnvelopeBuilder extends ShapeBuilder {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(orientation == Orientation.RIGHT); orientation.writeTo(out);
writeCoordinateTo(topLeft, out); writeCoordinateTo(topLeft, out);
writeCoordinateTo(bottomRight, out); writeCoordinateTo(bottomRight, out);
} }
@Override @Override
public EnvelopeBuilder readFrom(StreamInput in) throws IOException { public EnvelopeBuilder readFrom(StreamInput in) throws IOException {
Orientation orientation = in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT; return new EnvelopeBuilder(Orientation.readFrom(in))
return new EnvelopeBuilder(orientation)
.topLeft(readCoordinateFrom(in)) .topLeft(readCoordinateFrom(in))
.bottomRight(readCoordinateFrom(in)); .bottomRight(readCoordinateFrom(in));
} }

View File

@ -20,18 +20,25 @@
package org.elasticsearch.common.geo.builders; package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Shape; import com.spatial4j.core.shape.Shape;
import org.elasticsearch.common.geo.XShapeCollection; import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class GeometryCollectionBuilder extends ShapeBuilder { public class GeometryCollectionBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION; public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
public static final GeometryCollectionBuilder PROTOTYPE = new GeometryCollectionBuilder();
protected final ArrayList<ShapeBuilder> shapes = new ArrayList<>(); protected final ArrayList<ShapeBuilder> shapes = new ArrayList<>();
public GeometryCollectionBuilder() { public GeometryCollectionBuilder() {
@ -103,6 +110,7 @@ public class GeometryCollectionBuilder extends ShapeBuilder {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(FIELD_TYPE, TYPE.shapeName()); builder.field(FIELD_TYPE, TYPE.shapeName());
builder.field(FIELD_ORIENTATION, orientation.name().toLowerCase(Locale.ROOT));
builder.startArray(FIELD_GEOMETRIES); builder.startArray(FIELD_GEOMETRIES);
for (ShapeBuilder shape : shapes) { for (ShapeBuilder shape : shapes) {
shape.toXContent(builder, params); shape.toXContent(builder, params);
@ -132,4 +140,40 @@ public class GeometryCollectionBuilder extends ShapeBuilder {
//note: ShapeCollection is probably faster than a Multi* geom. //note: ShapeCollection is probably faster than a Multi* geom.
} }
@Override
public int hashCode() {
return Objects.hash(orientation, shapes);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
GeometryCollectionBuilder other = (GeometryCollectionBuilder) obj;
return Objects.equals(orientation, other.orientation) && Objects.equals(shapes, other.shapes);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
orientation.writeTo(out);
out.writeVInt(shapes.size());
for (ShapeBuilder shape : shapes) {
out.writeShape(shape);
}
}
@Override
public GeometryCollectionBuilder readFrom(StreamInput in) throws IOException {
GeometryCollectionBuilder geometryCollectionBuilder = new GeometryCollectionBuilder(Orientation.readFrom(in));
int shapes = in.readVInt();
for (int i = 0; i < shapes; i++) {
geometryCollectionBuilder.shape(in.readShape());
}
return geometryCollectionBuilder;
}
} }

View File

@ -123,7 +123,7 @@ public class MultiPolygonBuilder extends ShapeBuilder {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(orientation == Orientation.RIGHT); orientation.writeTo(out);
out.writeVInt(polygons.size()); out.writeVInt(polygons.size());
for (PolygonBuilder polygon : polygons) { for (PolygonBuilder polygon : polygons) {
polygon.writeTo(out); polygon.writeTo(out);
@ -132,8 +132,7 @@ public class MultiPolygonBuilder extends ShapeBuilder {
@Override @Override
public MultiPolygonBuilder readFrom(StreamInput in) throws IOException { public MultiPolygonBuilder readFrom(StreamInput in) throws IOException {
Orientation orientation = in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT; MultiPolygonBuilder polyBuilder = new MultiPolygonBuilder(Orientation.readFrom(in));
MultiPolygonBuilder polyBuilder = new MultiPolygonBuilder(orientation);
int holes = in.readVInt(); int holes = in.readVInt();
for (int i = 0; i < holes; i++) { for (int i = 0; i < holes; i++) {
polyBuilder.polygon(PolygonBuilder.PROTOTYPE.readFrom(in)); polyBuilder.polygon(PolygonBuilder.PROTOTYPE.readFrom(in));

View File

@ -562,7 +562,7 @@ public class PolygonBuilder extends ShapeBuilder {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(orientation == Orientation.RIGHT); orientation.writeTo(out);
shell.writeTo(out); shell.writeTo(out);
out.writeVInt(holes.size()); out.writeVInt(holes.size());
for (LineStringBuilder hole : holes) { for (LineStringBuilder hole : holes) {
@ -572,8 +572,7 @@ public class PolygonBuilder extends ShapeBuilder {
@Override @Override
public PolygonBuilder readFrom(StreamInput in) throws IOException { public PolygonBuilder readFrom(StreamInput in) throws IOException {
Orientation orientation = in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT; PolygonBuilder polyBuilder = new PolygonBuilder(Orientation.readFrom(in));
PolygonBuilder polyBuilder = new PolygonBuilder(orientation);
polyBuilder.shell = LineStringBuilder.PROTOTYPE.readFrom(in); polyBuilder.shell = LineStringBuilder.PROTOTYPE.readFrom(in);
int holes = in.readVInt(); int holes = in.readVInt();
for (int i = 0; i < holes; i++) { for (int i = 0; i < holes; i++) {

View File

@ -408,6 +408,14 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
public static final Orientation COUNTER_CLOCKWISE = Orientation.RIGHT; public static final Orientation COUNTER_CLOCKWISE = Orientation.RIGHT;
public static final Orientation CW = Orientation.LEFT; public static final Orientation CW = Orientation.LEFT;
public static final Orientation CCW = Orientation.RIGHT; public static final Orientation CCW = Orientation.RIGHT;
public void writeTo (StreamOutput out) throws IOException {
out.writeBoolean(this == Orientation.RIGHT);
}
public static Orientation readFrom (StreamInput in) throws IOException {
return in.readBoolean() ? Orientation.RIGHT : Orientation.LEFT;
}
} }
public static final String FIELD_TYPE = "type"; public static final String FIELD_TYPE = "type";

View File

@ -34,6 +34,8 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.text.Text; import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.text.StringAndBytesText;
import org.elasticsearch.common.text.Text; import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
@ -629,6 +631,13 @@ public abstract class StreamInput extends InputStream {
return readNamedWriteable(QueryBuilder.class); return readNamedWriteable(QueryBuilder.class);
} }
/**
* Reads a {@link ShapeBuilder} from the current stream
*/
public ShapeBuilder readShape() throws IOException {
return readNamedWriteable(ShapeBuilder.class);
}
/** /**
* Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream * Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream
*/ */

View File

@ -32,6 +32,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.text.Text; import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
@ -618,6 +619,13 @@ public abstract class StreamOutput extends OutputStream {
writeNamedWriteable(queryBuilder); writeNamedWriteable(queryBuilder);
} }
/**
* Writes a {@link ShapeBuilder} to the current stream
*/
public void writeShape(ShapeBuilder shapeBuilder) throws IOException {
writeNamedWriteable(shapeBuilder);
}
/** /**
* Writes a {@link ScoreFunctionBuilder} to the current stream * Writes a {@link ScoreFunctionBuilder} to the current stream
*/ */

View File

@ -25,7 +25,9 @@ import org.elasticsearch.common.unit.DistanceUnit;
import java.io.IOException; import java.io.IOException;
public class CirlceBuilderTests extends AbstractShapeBuilderTestCase<CircleBuilder> { public class CircleBuilderTests extends AbstractShapeBuilderTestCase<CircleBuilder> {
static CircleBuilderTests PROTOTYPE = new CircleBuilderTests();
@Override @Override
protected CircleBuilder createTestShapeBuilder() { protected CircleBuilder createTestShapeBuilder() {

View File

@ -29,6 +29,8 @@ import java.io.IOException;
public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeBuilder> { public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeBuilder> {
static final EnvelopeBuilderTests PROTOTYPE = new EnvelopeBuilderTests();
@Override @Override
protected EnvelopeBuilder createTestShapeBuilder() { protected EnvelopeBuilder createTestShapeBuilder() {
EnvelopeBuilder envelope = new EnvelopeBuilder(randomFrom(Orientation.values())); EnvelopeBuilder envelope = new EnvelopeBuilder(randomFrom(Orientation.values()));

View File

@ -0,0 +1,111 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.common.geo.builders;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import java.io.IOException;
public class GeometryCollectionBuilderTests extends AbstractShapeBuilderTestCase<GeometryCollectionBuilder> {
@Override
protected GeometryCollectionBuilder createTestShapeBuilder() {
// NORELEASE check of GeometryCollectionBuilder should parse maintain orientation
GeometryCollectionBuilder geometryCollection = new GeometryCollectionBuilder();
int shapes = randomIntBetween(0, 8);
for (int i = 0; i < shapes; i++) {
switch (randomIntBetween(0, 7)) {
case 0:
geometryCollection.shape(PointBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 1:
geometryCollection.shape(CircleBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 2:
geometryCollection.shape(EnvelopeBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 3:
geometryCollection.shape(LineStringBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 4:
geometryCollection.shape(MultiLineStringBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 5:
geometryCollection.shape(MultiPolygonBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 6:
geometryCollection.shape(MultiPointBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
case 7:
geometryCollection.shape(PolygonBuilderTests.PROTOTYPE.createTestShapeBuilder());
break;
}
}
return geometryCollection;
}
@Override
protected GeometryCollectionBuilder mutate(GeometryCollectionBuilder original) throws IOException {
GeometryCollectionBuilder mutation = copyShape(original);
// NORELEASE check of GeometryCollectionBuilder should parse maintain orientation
// if (randomBoolean()) {
// // toggle orientation
// mutation.orientation = (mutation.orientation == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
// } else {
// change one shape
if (mutation.shapes.size() > 0) {
int shapePosition = randomIntBetween(0, mutation.shapes.size() - 1);
ShapeBuilder shapeToChange = mutation.shapes.get(shapePosition);
switch (shapeToChange.type()) {
case POINT:
shapeToChange = PointBuilderTests.PROTOTYPE.mutate((PointBuilder) shapeToChange);
break;
case CIRCLE:
shapeToChange = CircleBuilderTests.PROTOTYPE.mutate((CircleBuilder) shapeToChange);
break;
case ENVELOPE:
shapeToChange = EnvelopeBuilderTests.PROTOTYPE.mutate((EnvelopeBuilder) shapeToChange);
break;
case LINESTRING:
shapeToChange = LineStringBuilderTests.PROTOTYPE.mutate((LineStringBuilder) shapeToChange);
break;
case MULTILINESTRING:
shapeToChange = MultiLineStringBuilderTests.PROTOTYPE.mutate((MultiLineStringBuilder) shapeToChange);
break;
case MULTIPOLYGON:
shapeToChange = MultiPolygonBuilderTests.PROTOTYPE.mutate((MultiPolygonBuilder) shapeToChange);
break;
case MULTIPOINT:
shapeToChange = MultiPointBuilderTests.PROTOTYPE.mutate((MultiPointBuilder) shapeToChange);
break;
case POLYGON:
shapeToChange = PolygonBuilderTests.PROTOTYPE.mutate((PolygonBuilder) shapeToChange);
break;
case GEOMETRYCOLLECTION:
throw new UnsupportedOperationException("GeometryCollection should not be nested inside each other");
}
mutation.shapes.set(shapePosition, shapeToChange);
} else {
mutation.shape(RandomShapeGenerator.createShape(getRandom()));
}
// }
return mutation;
}
}

View File

@ -28,6 +28,8 @@ import java.io.IOException;
public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStringBuilder> { public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStringBuilder> {
static final LineStringBuilderTests PROTOTYPE = new LineStringBuilderTests();
@Override @Override
protected LineStringBuilder createTestShapeBuilder() { protected LineStringBuilder createTestShapeBuilder() {
LineStringBuilder lsb = (LineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.LINESTRING); LineStringBuilder lsb = (LineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.LINESTRING);

View File

@ -28,6 +28,8 @@ import java.io.IOException;
public class MultiLineStringBuilderTests extends AbstractShapeBuilderTestCase<MultiLineStringBuilder> { public class MultiLineStringBuilderTests extends AbstractShapeBuilderTestCase<MultiLineStringBuilder> {
static final MultiLineStringBuilderTests PROTOTYPE = new MultiLineStringBuilderTests();
@Override @Override
protected MultiLineStringBuilder createTestShapeBuilder() { protected MultiLineStringBuilder createTestShapeBuilder() {
return (MultiLineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTILINESTRING); return (MultiLineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTILINESTRING);

View File

@ -28,6 +28,8 @@ import java.io.IOException;
public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPointBuilder> { public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPointBuilder> {
static final MultiPointBuilderTests PROTOTYPE = new MultiPointBuilderTests();
@Override @Override
protected MultiPointBuilder createTestShapeBuilder() { protected MultiPointBuilder createTestShapeBuilder() {
return (MultiPointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTIPOINT); return (MultiPointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTIPOINT);

View File

@ -27,6 +27,8 @@ import java.io.IOException;
public class MultiPolygonBuilderTests extends AbstractShapeBuilderTestCase<MultiPolygonBuilder> { public class MultiPolygonBuilderTests extends AbstractShapeBuilderTestCase<MultiPolygonBuilder> {
static final MultiPolygonBuilderTests PROTOTYPE = new MultiPolygonBuilderTests();
@Override @Override
protected MultiPolygonBuilder createTestShapeBuilder() { protected MultiPolygonBuilder createTestShapeBuilder() {
MultiPolygonBuilder mpb = new MultiPolygonBuilder(randomFrom(Orientation.values())); MultiPolygonBuilder mpb = new MultiPolygonBuilder(randomFrom(Orientation.values()));

View File

@ -26,6 +26,8 @@ import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
public class PointBuilderTests extends AbstractShapeBuilderTestCase<PointBuilder> { public class PointBuilderTests extends AbstractShapeBuilderTestCase<PointBuilder> {
static PointBuilderTests PROTOTYPE = new PointBuilderTests();
@Override @Override
protected PointBuilder createTestShapeBuilder() { protected PointBuilder createTestShapeBuilder() {
return (PointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POINT); return (PointBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POINT);

View File

@ -29,6 +29,8 @@ import java.io.IOException;
public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBuilder> { public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBuilder> {
static final PolygonBuilderTests PROTOTYPE = new PolygonBuilderTests();
@Override @Override
protected PolygonBuilder createTestShapeBuilder() { protected PolygonBuilder createTestShapeBuilder() {
PolygonBuilder pgb = (PolygonBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POLYGON); PolygonBuilder pgb = (PolygonBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.POLYGON);