Skip to content

Commit 6f36a43

Browse files
authored
Merge pull request #187 from Esri/stolstov/serialize_quadtree
Add serialization for QuadTree and related classes
2 parents c74e7a8 + e7fb7ca commit 6f36a43

File tree

5 files changed

+232
-16
lines changed

5 files changed

+232
-16
lines changed

src/main/java/com/esri/core/geometry/AttributeStreamOfInt32.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 1995-2017 Esri
2+
Copyright 1995-2018 Esri
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -27,14 +27,20 @@
2727

2828
import com.esri.core.geometry.VertexDescription.Persistence;
2929

30+
import java.io.IOException;
31+
import java.io.ObjectStreamException;
32+
import java.io.Serializable;
3033
import java.nio.ByteBuffer;
34+
import java.nio.IntBuffer;
3135
import java.util.Arrays;
3236

3337
import static com.esri.core.geometry.SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT32;
3438
import static com.esri.core.geometry.SizeOf.sizeOfIntArray;
3539

36-
final class AttributeStreamOfInt32 extends AttributeStreamBase {
37-
private int[] m_buffer = null;
40+
final class AttributeStreamOfInt32 extends AttributeStreamBase implements Serializable {
41+
private static final long serialVersionUID = 1L;
42+
43+
transient private int[] m_buffer = null;
3844
private int m_size;
3945

4046
public void reserve(int reserve)
@@ -594,7 +600,6 @@ private void _selfWriteRangeImpl(int toElement, int count, int fromElement,
594600
// reverse what we written
595601
int j = toElement;
596602
int offset = toElement + count - stride;
597-
int dj = stride;
598603
for (int i = 0, n = count / 2; i < n; i++) {
599604
for (int k = 0; k < stride; k++) {
600605
int v = m_buffer[j + k];
@@ -728,4 +733,49 @@ void quicksort(int leftIn, int rightIn, IntComparator compare,
728733
public void sort(int start, int end) {
729734
Arrays.sort(m_buffer, start, end);
730735
}
736+
737+
private void writeObject(java.io.ObjectOutputStream stream)
738+
throws IOException {
739+
stream.defaultWriteObject();
740+
IntBuffer intBuf = null;
741+
byte[] bytes = null;
742+
for (int i = 0; i < m_size;) {
743+
int n = Math.min(32, m_size - i);
744+
if (bytes == null) {
745+
bytes = new byte[n * 4]; //32 elements at a time
746+
ByteBuffer buf = ByteBuffer.wrap(bytes);
747+
intBuf = buf.asIntBuffer();
748+
}
749+
intBuf.rewind();
750+
intBuf.put(m_buffer, i, n);
751+
stream.write(bytes, 0, n * 4);
752+
i += n;
753+
}
754+
}
755+
756+
private void readObject(java.io.ObjectInputStream stream)
757+
throws IOException, ClassNotFoundException {
758+
stream.defaultReadObject();
759+
m_buffer = new int[m_size];
760+
IntBuffer intBuf = null;
761+
byte[] bytes = null;
762+
for (int i = 0; i < m_size;) {
763+
int n = Math.min(32, m_size - i);
764+
if (bytes == null) {
765+
bytes = new byte[n * 4]; //32 elements at a time
766+
ByteBuffer buf = ByteBuffer.wrap(bytes);
767+
intBuf = buf.asIntBuffer();
768+
}
769+
stream.read(bytes, 0, n * 4);
770+
intBuf.rewind();
771+
intBuf.get(m_buffer, i, n);
772+
i += n;
773+
}
774+
}
775+
776+
@SuppressWarnings("unused")
777+
private void readObjectNoData() throws ObjectStreamException {
778+
m_buffer = new int[2];
779+
m_size = 0;
780+
}
731781
}

src/main/java/com/esri/core/geometry/QuadTree.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 1995-2015 Esri
2+
Copyright 1995-2018 Esri
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -25,7 +25,11 @@
2525

2626
package com.esri.core.geometry;
2727

28-
public class QuadTree {
28+
import java.io.Serializable;
29+
30+
public class QuadTree implements Serializable {
31+
private static final long serialVersionUID = 1L;
32+
2933
public static final class QuadTreeIterator {
3034
/**
3135
* Resets the iterator to an starting state on the QuadTree. If the

src/main/java/com/esri/core/geometry/QuadTreeImpl.java

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 1995-2015 Esri
2+
Copyright 1995-2018 Esri
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -23,9 +23,15 @@
2323
*/
2424
package com.esri.core.geometry;
2525

26+
import java.io.IOException;
27+
import java.io.InvalidObjectException;
28+
import java.io.ObjectStreamException;
29+
import java.io.Serializable;
2630
import java.util.ArrayList;
2731

28-
class QuadTreeImpl {
32+
class QuadTreeImpl implements Serializable {
33+
private static final long serialVersionUID = 1L;
34+
2935
static final class QuadTreeIteratorImpl {
3036
/**
3137
* Resets the iterator to an starting state on the Quad_tree_impl. If
@@ -1248,19 +1254,28 @@ private void set_data_values_(int data_handle, int element, Envelope2D bounding_
12481254
private Envelope2D m_data_extent;
12491255
private StridedIndexTypeCollection m_quad_tree_nodes;
12501256
private StridedIndexTypeCollection m_element_nodes;
1251-
private ArrayList<Data> m_data;
1257+
transient private ArrayList<Data> m_data;
12521258
private AttributeStreamOfInt32 m_free_data;
12531259
private int m_root;
12541260
private int m_height;
12551261
private boolean m_b_store_duplicates;
12561262

1257-
private int m_quadrant_mask = 3;
1258-
private int m_height_bit_shift = 2;
1259-
private int m_flushing_count = 5;
1263+
final static private int m_quadrant_mask = 3;
1264+
final static private int m_height_bit_shift = 2;
1265+
final static private int m_flushing_count = 5;
12601266

12611267
static final class Data {
12621268
int element;
12631269
Envelope2D box;
1270+
1271+
Data() {
1272+
}
1273+
1274+
Data(int element_, double x1, double y1, double x2, double y2) {
1275+
element = element_;
1276+
box = new Envelope2D();
1277+
box.setCoords(x1, y1, x2, y2);
1278+
}
12641279

12651280
Data(int element_, Envelope2D box_) {
12661281
element = element_;
@@ -1269,6 +1284,57 @@ static final class Data {
12691284
}
12701285
}
12711286

1287+
private void writeObject(java.io.ObjectOutputStream stream)
1288+
throws IOException {
1289+
stream.defaultWriteObject();
1290+
stream.writeInt(m_data.size());
1291+
for (int i = 0, n = m_data.size(); i < n; ++i) {
1292+
Data d = m_data.get(i);
1293+
if (d != null) {
1294+
stream.writeByte(1);
1295+
stream.writeInt(d.element);
1296+
stream.writeDouble(d.box.xmin);
1297+
stream.writeDouble(d.box.ymin);
1298+
stream.writeDouble(d.box.xmax);
1299+
stream.writeDouble(d.box.ymax);
1300+
}
1301+
else {
1302+
stream.writeByte(0);
1303+
}
1304+
1305+
}
1306+
}
1307+
1308+
private void readObject(java.io.ObjectInputStream stream)
1309+
throws IOException, ClassNotFoundException {
1310+
stream.defaultReadObject();
1311+
int dataSize = stream.readInt();
1312+
m_data = new ArrayList<Data>(dataSize);
1313+
for (int i = 0, n = dataSize; i < n; ++i) {
1314+
int b = stream.readByte();
1315+
if (b == 1) {
1316+
int elm = stream.readInt();
1317+
double x1 = stream.readDouble();
1318+
double y1 = stream.readDouble();
1319+
double x2 = stream.readDouble();
1320+
double y2 = stream.readDouble();
1321+
Data d = new Data(elm, x1, y1, x2, y2);
1322+
m_data.add(d);
1323+
}
1324+
else if (b == 0) {
1325+
m_data.add(null);
1326+
}
1327+
else {
1328+
throw new IOException();
1329+
}
1330+
}
1331+
}
1332+
1333+
@SuppressWarnings("unused")
1334+
private void readObjectNoData() throws ObjectStreamException {
1335+
throw new InvalidObjectException("Stream data required");
1336+
}
1337+
12721338
/* m_quad_tree_nodes
12731339
* 0: m_north_east_child
12741340
* 1: m_north_west_child

src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 1995-2015 Esri
2+
Copyright 1995-2018 Esri
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -23,13 +23,17 @@
2323
*/
2424
package com.esri.core.geometry;
2525

26+
import java.io.Serializable;
27+
2628
/**
2729
* A collection of strides of Index_type elements. To be used when one needs a
2830
* collection of homogeneous elements that contain only integer fields (i.e.
2931
* structs with Index_type members) Recycles the strides. Allows for constant
3032
* time creation and deletion of an element.
3133
*/
32-
final class StridedIndexTypeCollection {
34+
final class StridedIndexTypeCollection implements Serializable {
35+
private static final long serialVersionUID = 1L;
36+
3337
private int[][] m_buffer = null;
3438
private int m_firstFree = -1;
3539
private int m_last = 0;

src/test/java/com/esri/core/geometry/TestSerialization.java

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 1995-2017 Esri
2+
Copyright 1995-2018 Esri
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
2626

2727
import java.io.ByteArrayInputStream;
2828
import java.io.ByteArrayOutputStream;
29-
import java.io.FileOutputStream;
3029
import java.io.InputStream;
3130
import java.io.ObjectInputStream;
3231
import java.io.ObjectOutputStream;
@@ -401,4 +400,97 @@ public void testSerializeEnvelope2D() {
401400
}
402401
}
403402

403+
public void testAttributeStreamOfInt32() {
404+
AttributeStreamOfInt32 a = new AttributeStreamOfInt32(0);
405+
for (int i = 0; i < 100; i++)
406+
a.add(i);
407+
408+
try {
409+
// serialize
410+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
411+
ObjectOutputStream os = new ObjectOutputStream(baos);
412+
os.writeObject(a);
413+
os.close();
414+
baos.close();
415+
416+
// deserialize
417+
ByteArrayInputStream bais = new ByteArrayInputStream(
418+
baos.toByteArray());
419+
ObjectInputStream in = new ObjectInputStream(bais);
420+
AttributeStreamOfInt32 aOut = (AttributeStreamOfInt32) in.readObject();
421+
in.close();
422+
bais.close();
423+
424+
assertTrue(aOut.size() == a.size());
425+
for (int i = 0; i < 100; i++)
426+
assertTrue(aOut.get(i) == a.get(i));
427+
428+
} catch (Exception e) {
429+
fail("AttributeStreamOfInt32 serialization failure");
430+
}
431+
432+
}
433+
434+
@Test
435+
public void testQuadTree() {
436+
MultiPoint mp = new MultiPoint();
437+
int r = 124124;
438+
for (int i = 0; i < 100; ++i) {
439+
r = NumberUtils.nextRand(r);
440+
int x = r;
441+
r = NumberUtils.nextRand(r);
442+
int y = r;
443+
mp.add(x, y);
444+
}
445+
446+
Envelope2D extent = new Envelope2D();
447+
mp.queryEnvelope2D(extent);
448+
QuadTree quadTree = new QuadTree(extent, 8);
449+
Envelope2D boundingbox = new Envelope2D();
450+
Point2D pt;
451+
452+
for (int i = 0; i < mp.getPointCount(); i++) {
453+
pt = mp.getXY(i);
454+
boundingbox.setCoords(pt.x, pt.y, pt.x, pt.y);
455+
quadTree.insert(i, boundingbox, -1);
456+
}
457+
458+
try {
459+
// serialize
460+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
461+
ObjectOutputStream os = new ObjectOutputStream(baos);
462+
os.writeObject(quadTree);
463+
os.close();
464+
baos.close();
465+
466+
// deserialize
467+
ByteArrayInputStream bais = new ByteArrayInputStream(
468+
baos.toByteArray());
469+
ObjectInputStream in = new ObjectInputStream(bais);
470+
QuadTree qOut = (QuadTree) in.readObject();
471+
in.close();
472+
bais.close();
473+
474+
assertTrue(quadTree.getElementCount() == qOut.getElementCount());
475+
QuadTree.QuadTreeIterator iter1 = quadTree.getIterator();
476+
QuadTree.QuadTreeIterator iter2 = qOut.getIterator();
477+
int h1 = iter1.next();
478+
int h2 = iter2.next();
479+
for (; h1 != -1 && h2 != -1; h1 = iter1.next(), h2 = iter2.next()) {
480+
assertTrue(quadTree.getElement(h1) == qOut.getElement(h2));
481+
assertTrue(quadTree.getElementExtent(h1).equals(qOut.getElementExtent(h2)));
482+
assertTrue(quadTree.getExtent(quadTree.getQuad(h1)).equals(qOut.getExtent(qOut.getQuad(h2))));
483+
int c1 = quadTree.getSubTreeElementCount(quadTree.getQuad(h1));
484+
int c2 = qOut.getSubTreeElementCount(qOut.getQuad(h2));
485+
assertTrue(c1 == c2);
486+
}
487+
488+
assertTrue(h1 == -1 && h2 == -1);
489+
490+
assertTrue(quadTree.getDataExtent().equals(qOut.getDataExtent()));
491+
} catch (Exception e) {
492+
fail("QuadTree serialization failure");
493+
}
494+
495+
}
404496
}

0 commit comments

Comments
 (0)