|
5 | 5 |
|
6 | 6 | package com.vesoft.nebula.encoder; |
7 | 7 |
|
| 8 | +import com.vesoft.nebula.Coordinate; |
8 | 9 | import com.vesoft.nebula.Date; |
9 | 10 | import com.vesoft.nebula.DateTime; |
| 11 | +import com.vesoft.nebula.Geography; |
| 12 | +import com.vesoft.nebula.LineString; |
| 13 | +import com.vesoft.nebula.Point; |
| 14 | +import com.vesoft.nebula.Polygon; |
10 | 15 | import com.vesoft.nebula.Time; |
11 | 16 | import com.vesoft.nebula.Value; |
12 | 17 | import com.vesoft.nebula.meta.PropertyType; |
|
15 | 20 | import java.util.ArrayList; |
16 | 21 | import java.util.Collections; |
17 | 22 | import java.util.List; |
| 23 | +import org.apache.commons.codec.binary.Hex; |
| 24 | +import org.locationtech.jts.geom.GeometryFactory; |
| 25 | +import org.locationtech.jts.io.ByteOrderValues; |
| 26 | +import org.locationtech.jts.io.WKBWriter; |
18 | 27 |
|
19 | 28 | public class RowWriterImpl implements RowWriter { |
20 | 29 | private final SchemaProviderImpl schema; |
@@ -509,6 +518,7 @@ public void write(int index, byte[] v) { |
509 | 518 | } |
510 | 519 | int offset = headerLen + numNullBytes + field.offset(); |
511 | 520 | switch (typeEnum) { |
| 521 | + case GEOGRAPHY: |
512 | 522 | case STRING: { |
513 | 523 | strList.add(v); |
514 | 524 | outOfSpaceStr = true; |
@@ -625,6 +635,31 @@ public void write(int index, DateTime v) { |
625 | 635 | isSet.set(index, true); |
626 | 636 | } |
627 | 637 |
|
| 638 | + @Override |
| 639 | + public void write(int index, Geography v) { |
| 640 | + SchemaProvider.Field field = schema.field(index); |
| 641 | + PropertyType typeEnum = PropertyType.findByValue(field.type()); |
| 642 | + if (typeEnum == null) { |
| 643 | + throw new RuntimeException("Incorrect field type " + field.type()); |
| 644 | + } |
| 645 | + if (typeEnum == PropertyType.GEOGRAPHY) { |
| 646 | + if (field.geoShape() != 0 && field.geoShape() != v.getSetField()) { |
| 647 | + throw new RuntimeException("Incorrect geo shape, expect " |
| 648 | + + field.geoShape() + ", got " |
| 649 | + + v.getSetField()); |
| 650 | + } |
| 651 | + } else { |
| 652 | + throw new RuntimeException("Value: " + v + "'s type is unexpected"); |
| 653 | + } |
| 654 | + org.locationtech.jts.geom.Geometry jtsGeom = convertGeographyToJTSGeometry(v); |
| 655 | + byte[] wkb = new org.locationtech.jts.io |
| 656 | + .WKBWriter(2, this.byteOrder == ByteOrder.BIG_ENDIAN |
| 657 | + ? ByteOrderValues.BIG_ENDIAN |
| 658 | + : ByteOrderValues.LITTLE_ENDIAN) |
| 659 | + .write(jtsGeom); |
| 660 | + write(index, wkb); |
| 661 | + } |
| 662 | + |
628 | 663 | @Override |
629 | 664 | public byte[] encodeStr() { |
630 | 665 | return buf.array(); |
@@ -666,6 +701,8 @@ public void setValue(int index, Object value) { |
666 | 701 | write(index, (Date)value); |
667 | 702 | } else if (value instanceof DateTime) { |
668 | 703 | write(index, (DateTime)value); |
| 704 | + } else if (value instanceof Geography) { |
| 705 | + write(index, (Geography)value); |
669 | 706 | } else { |
670 | 707 | throw new RuntimeException("Unsupported value object `" + value.getClass() + "\""); |
671 | 708 | } |
@@ -708,6 +745,9 @@ public void setValue(int index, Value value) { |
708 | 745 | case Value.DTVAL: |
709 | 746 | write(index, value.getDtVal()); |
710 | 747 | break; |
| 748 | + case Value.GGVAL: |
| 749 | + write(index, value.getGgVal()); |
| 750 | + break; |
711 | 751 | default: |
712 | 752 | throw new RuntimeException( |
713 | 753 | "Unknown value: " + value.getFieldValue().getClass() |
@@ -790,6 +830,9 @@ public void checkUnsetFields() { |
790 | 830 | // case Value.DTVAL: |
791 | 831 | // write(i, defVal.getDtVal()); |
792 | 832 | // break; |
| 833 | + // case Value.GGVAL: |
| 834 | + // write(i, defVal.getGgVal()); |
| 835 | + // break; |
793 | 836 | // default: |
794 | 837 | // throw new RuntimeException("Unsupported default value type"); |
795 | 838 | // } |
@@ -821,7 +864,8 @@ public ByteBuffer processOutOfSpace() { |
821 | 864 | if (typeEnum == null) { |
822 | 865 | throw new RuntimeException("Incorrect field type " + field.type()); |
823 | 866 | } |
824 | | - if (typeEnum != PropertyType.STRING) { |
| 867 | + if (typeEnum != PropertyType.STRING |
| 868 | + && typeEnum != PropertyType.GEOGRAPHY) { |
825 | 869 | continue; |
826 | 870 | } |
827 | 871 | int offset = headerLen + numNullBytes + field.offset(); |
@@ -867,4 +911,66 @@ private long getTimestamp() { |
867 | 911 | long nanoTime = System.nanoTime(); |
868 | 912 | return curTime + (nanoTime - nanoTime / 1000000 * 1000000) / 1000; |
869 | 913 | } |
| 914 | + |
| 915 | + public org.locationtech.jts.geom.Geometry |
| 916 | + convertGeographyToJTSGeometry(Geography geog) { |
| 917 | + GeometryFactory geomFactory = new GeometryFactory(); |
| 918 | + switch (geog.getSetField()) { |
| 919 | + case Geography.PTVAL: { |
| 920 | + Point point = geog.getPtVal(); |
| 921 | + Coordinate coord = point.getCoord(); |
| 922 | + return geomFactory.createPoint( |
| 923 | + new org.locationtech.jts.geom.Coordinate(coord.x, coord.y)); |
| 924 | + } |
| 925 | + case Geography.LSVAL: { |
| 926 | + LineString line = geog.getLsVal(); |
| 927 | + List<Coordinate> coordList = line.getCoordList(); |
| 928 | + |
| 929 | + List<org.locationtech.jts.geom.Coordinate> jtsCoordList = |
| 930 | + new ArrayList<>(); |
| 931 | + for (int i = 0; i < coordList.size(); ++i) { |
| 932 | + jtsCoordList.add(new org.locationtech.jts.geom.Coordinate( |
| 933 | + coordList.get(i).x, coordList.get(i).y)); |
| 934 | + } |
| 935 | + org.locationtech.jts.geom.Coordinate[] jtsCoordArray = |
| 936 | + new org.locationtech.jts.geom.Coordinate[jtsCoordList.size()]; |
| 937 | + return geomFactory.createLineString( |
| 938 | + jtsCoordList.toArray(jtsCoordArray)); |
| 939 | + } |
| 940 | + case Geography.PGVAL: { |
| 941 | + Polygon polygon = geog.getPgVal(); |
| 942 | + List<List<Coordinate>> coordListList = polygon.getCoordListList(); |
| 943 | + if (coordListList.isEmpty()) { |
| 944 | + throw new RuntimeException("Polygon must at least contain one loop"); |
| 945 | + } |
| 946 | + |
| 947 | + List<org.locationtech.jts.geom.LinearRing> rings = new ArrayList<>(); |
| 948 | + for (int i = 0; i < coordListList.size(); ++i) { |
| 949 | + List<Coordinate> coordList = coordListList.get(i); |
| 950 | + List<org.locationtech.jts.geom.Coordinate> jtsCoordList = |
| 951 | + new ArrayList<>(); |
| 952 | + for (int j = 0; j < coordList.size(); ++j) { |
| 953 | + jtsCoordList.add(new org.locationtech.jts.geom.Coordinate( |
| 954 | + coordList.get(j).x, coordList.get(j).y)); |
| 955 | + } |
| 956 | + org.locationtech.jts.geom.Coordinate[] jtsCoordArray = |
| 957 | + new org.locationtech.jts.geom.Coordinate[jtsCoordList.size()]; |
| 958 | + rings.add(geomFactory.createLinearRing( |
| 959 | + jtsCoordList.toArray(jtsCoordArray))); |
| 960 | + } |
| 961 | + org.locationtech.jts.geom.LinearRing shell = rings.get(0); |
| 962 | + if (rings.size() == 1) { |
| 963 | + return geomFactory.createPolygon(shell); |
| 964 | + } else { |
| 965 | + rings.remove(0); |
| 966 | + org.locationtech.jts.geom.LinearRing[] holesArrary = |
| 967 | + new org.locationtech.jts.geom.LinearRing[rings.size() - 1]; |
| 968 | + return geomFactory.createPolygon(shell, rings.toArray(holesArrary)); |
| 969 | + } |
| 970 | + } |
| 971 | + default: |
| 972 | + throw new RuntimeException("Unknown geography: " |
| 973 | + + geog.getFieldValue().getClass()); |
| 974 | + } |
| 975 | + } |
870 | 976 | } |
0 commit comments