package com.github.davidmoten.rtree.fbs; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.github.davidmoten.guavamini.Preconditions; import com.github.davidmoten.rtree.Entries; import com.github.davidmoten.rtree.Entry; import com.github.davidmoten.rtree.fbs.generated.Box_; import com.github.davidmoten.rtree.fbs.generated.Circle_; import com.github.davidmoten.rtree.fbs.generated.Entry_; import com.github.davidmoten.rtree.fbs.generated.GeometryType_; import com.github.davidmoten.rtree.fbs.generated.Geometry_; import com.github.davidmoten.rtree.fbs.generated.Line_; import com.github.davidmoten.rtree.fbs.generated.Node_; import com.github.davidmoten.rtree.fbs.generated.Point_; import com.github.davidmoten.rtree.geometry.Circle; import com.github.davidmoten.rtree.geometry.Geometries; import com.github.davidmoten.rtree.geometry.Geometry; import com.github.davidmoten.rtree.geometry.Line; import com.github.davidmoten.rtree.geometry.Point; import com.github.davidmoten.rtree.geometry.Rectangle; import com.github.davidmoten.rtree.internal.Util; import com.google.flatbuffers.FlatBufferBuilder; import rx.functions.Func1; final class FlatBuffersHelper { private FlatBuffersHelper() { // prevent instantiation } static <T, S extends Geometry> int addEntries(List<Entry<T, S>> entries, FlatBufferBuilder builder, Func1<? super T, byte[]> serializer) { int[] entries2 = new int[entries.size()]; for (int i = 0; i < entries.size(); i++) { Geometry g = entries.get(i).geometry(); final int geom; final byte geomType; // Must check Point before Rectangle because Point is instance of // Rectangle if (g instanceof Point) { Point p = (Point) g; geom = Point_.createPoint_(builder, p.x(), p.y()); geomType = GeometryType_.Point; } else if (g instanceof Rectangle) { Rectangle b = (Rectangle) g; geom = Box_.createBox_(builder, b.x1(), b.y1(), b.x2(), b.y2()); geomType = GeometryType_.Box; } else if (g instanceof Circle) { Circle c = (Circle) g; geom = Circle_.createCircle_(builder, c.x(), c.y(), c.radius()); geomType = GeometryType_.Circle; } else if (g instanceof Line) { Line c = (Line) g; geom = Line_.createLine_(builder, c.x1(), c.y1(), c.x2(), c.y2()); geomType = GeometryType_.Line; } else throw new RuntimeException("unexpected"); Geometry_.startGeometry_(builder); if (geomType == GeometryType_.Box) { Geometry_.addBox(builder, geom); } else if (geomType == GeometryType_.Point) { Geometry_.addPoint(builder, geom); } else if (geomType == GeometryType_.Circle) { Geometry_.addCircle(builder, geom); } else if (geomType == GeometryType_.Line) { Geometry_.addLine(builder, geom); } else throw new RuntimeException("unexpected"); Geometry_.addType(builder, geomType); int geo = Geometry_.endGeometry_(builder); int obj = Entry_.createObjectVector(builder, serializer.call(entries.get(i).value())); entries2[i] = Entry_.createEntry_(builder, geo, obj); } int ents = Node_.createEntriesVector(builder, entries2); Rectangle mbb = Util.mbr(entries); int b = Box_.createBox_(builder, mbb.x1(), mbb.y1(), mbb.x2(), mbb.y2()); Node_.startNode_(builder); Node_.addMbb(builder, b); Node_.addEntries(builder, ents); return Node_.endNode_(builder); } static <T, S extends Geometry> List<Entry<T, S>> createEntries(Node_ node, Func1<byte[], ? extends T> deserializer) { int numEntries = node.entriesLength(); List<Entry<T, S>> entries = new ArrayList<Entry<T, S>>(numEntries); Preconditions.checkArgument(numEntries > 0); Entry_ entry = new Entry_(); Geometry_ geom = new Geometry_(); for (int i = 0; i < numEntries; i++) { Entry<T, S> ent = createEntry(node, deserializer, entry, geom, i); entries.add(ent); } return entries; } @SuppressWarnings("unchecked") private static <T, S extends Geometry> Entry<T, S> createEntry(Node_ node, Func1<byte[], ? extends T> deserializer, Entry_ entry, Geometry_ geom, int i) { node.entries(entry, i); entry.geometry(geom); final Geometry g = toGeometry(geom); return Entries.entry(parseObject(deserializer, entry), (S) g); } static <T, S extends Geometry> Entry<T, S> createEntry(Node_ node, Func1<byte[], ? extends T> deserializer, int i) { return createEntry(node, deserializer, new Entry_(), new Geometry_(), i); } static <T> T parseObject(Func1<byte[], ? extends T> deserializer, Entry_ entry) { ByteBuffer bb = entry.objectAsByteBuffer(); if (bb == null) { return null; } else { byte[] bytes = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit()); T t = deserializer.call(bytes); return t; } } @SuppressWarnings("unchecked") static <S extends Geometry> S toGeometry(Geometry_ g) { final Geometry result; byte type = g.type(); if (type == GeometryType_.Box) { result = createBox(g.box()); } else if (type == GeometryType_.Point) { Point_ p = g.point(); result = Geometries.point(p.x(), p.y()); } else if (type == GeometryType_.Circle) { Circle_ c = g.circle(); result = Geometries.circle(c.x(), c.y(), c.radius()); } else if (type == GeometryType_.Line) { result = createLine(g.line()); } else throw new RuntimeException("unexpected"); return (S) result; } static Rectangle createBox(Box_ b) { return Geometries.rectangle(b.minX(), b.minY(), b.maxX(), b.maxY()); } static Line createLine(Box_ b) { return Geometries.line(b.minX(), b.minY(), b.maxX(), b.maxY()); } }