private void writeArrayHeaderTo( byte[] bytes ) { bytes[0] = (byte) PropertyType.GEOMETRY.intValue(); bytes[1] = (byte) geometryType; bytes[2] = (byte) dimension; bytes[3] = (byte) crs.getTable().getTableId(); bytes[4] = (byte) (crs.getCode() >> 8 & 0xFFL); bytes[5] = (byte) (crs.getCode() & 0xFFL); }
SpatialFile( CoordinateReferenceSystem crs, ConfiguredSpaceFillingCurveSettingsCache configuredSettings, File indexDirectory ) { this.crs = crs; this.configuredSettings = configuredSettings; String s = crs.getTable().getTableId() + "-" + Integer.toString( crs.getCode() ); this.indexFile = new File( indexDirectory, s ); }
@Override public long updateHash( HashFunction hashFunction, long hash ) { hash = hashFunction.update( hash, crs.getCode() ); for ( double v : coordinate ) { hash = hashFunction.update( hash, Double.doubleToLongBits( v ) ); } return hash; }
@Override public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) throws RuntimeException { builder.append( crs.getTable().getTableId() ); builder.append( ':' ); builder.append( crs.getCode() ); builder.append( ':' ); int index = 0; for ( double c : coordinate ) { if ( index > 0 ) { builder.append( ';' ); } builder.append( c ); index++; } builder.append( '|' ); }
/** * The string representation of this object when indexed in string-only indexes, like lucene, for equality search only. This should normally only * happen when points are part of composite indexes, because otherwise they are indexed in the spatial index. */ public String toIndexableString() { CoordinateReferenceSystem crs = getCoordinateReferenceSystem(); return format( "P:%d-%d%s", crs.getTable().getTableId(), crs.getCode(), Arrays.toString( coordinate ) ); }
@Override Value get( PointValue value ) { return Values.intValue( value.getCoordinateReferenceSystem().getCode() ); } };
@Override public int computeHash() { int result = 1; result = 31 * result + NumberValues.hash( crs.getCode() ); result = 31 * result + NumberValues.hash( coordinate ); return result; }
@Override public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) { checkArgument( coordinate.length == crs.getDimension(), "Dimension for %s is %d, got %d", crs.getName(), crs.getDimension(), coordinate.length ); buf.putInt( crs.getCode() ); for ( int i = 0; i < crs.getDimension(); i++ ) { buf.putDouble( coordinate[i] ); } }
void writePointDerived( CoordinateReferenceSystem crs, long derivedValue, NativeIndexKey.Inclusion inclusion ) { if ( isArray ) { throw new IllegalStateException( "This method is intended to be called when querying, where one or more sub-ranges are derived " + "from a queried range and each sub-range written to separate keys. " + "As such it's unexpected that this key state thinks that it's holds state for an array" ); } updateCurve( crs.getTable().getTableId(), crs.getCode() ); setType( Types.GEOMETRY ).write( this, derivedValue, NO_COORDINATES ); this.inclusion = inclusion; }
public static long[] encodePoint( int keyId, CoordinateReferenceSystem crs, double[] coordinate ) { if ( coordinate.length > GeometryType.getMaxSupportedDimensions() ) { // One property block can only contains at most 4x8 byte parts, one for header and 3 for coordinates throw new UnsupportedOperationException( "Points with more than " + GeometryType.getMaxSupportedDimensions() + " dimensions are not supported" ); } int idBits = StandardFormatSettings.PROPERTY_TOKEN_MAXIMUM_ID_BITS; long keyAndType = keyId | (((long) (PropertyType.GEOMETRY.intValue()) << idBits)); long gtypeBits = GeometryType.GEOMETRY_POINT.gtype << (idBits + 4); long dimensionBits = ((long) coordinate.length) << (idBits + 8); long crsTableIdBits = ((long) crs.getTable().getTableId()) << (idBits + 12); long crsCodeBits = ((long) crs.getCode()) << (idBits + 16); long[] data = new long[1 + coordinate.length]; data[0] = keyAndType | gtypeBits | dimensionBits | crsTableIdBits | crsCodeBits; for ( int i = 0; i < coordinate.length; i++ ) { data[1 + i] = Double.doubleToLongBits( coordinate[i] ); } return data; }
@Override public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) throws RuntimeException { append( "{geometry: {type: \"Point\", coordinates: " ); append( Arrays.toString(coordinate) ); append( ", crs: {type: link, properties: {href: \"" ); append( crs.getHref() ); append( "\", code: " ); append( Integer.toString( crs.getCode() ) ); append( "}}}}" ); }
@Override public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) throws IOException { if ( coordinate.length == 2 ) { packStructHeader( POINT_2D_SIZE, POINT_2D ); pack( crs.getCode() ); pack( coordinate[0] ); pack( coordinate[1] ); } else if ( coordinate.length == 3 ) { packStructHeader( POINT_3D_SIZE, POINT_3D ); pack( crs.getCode() ); pack( coordinate[0] ); pack( coordinate[1] ); pack( coordinate[2] ); } else { throw new IllegalArgumentException( "Point with 2D or 3D coordinate expected, " + "got crs=" + crs + ", coordinate=" + Arrays.toString( coordinate ) ); } }
@Override public void write( Object value, FlushableChannel into ) throws IOException { PointValue pointValue = (PointValue) value; // using code is not a future-proof solution like the one we have in the PropertyStore. // But then again, this is not used from procution code. into.putInt( pointValue.getCoordinateReferenceSystem().getCode() ); double[] coordinate = pointValue.coordinate(); into.putInt( coordinate.length ); for ( double c : coordinate ) { into.putDouble( c ); } } } );
@Override public void visit( CoordinateReferenceSystem crs, SpaceFillingCurveSettings settings ) { // For tableId+code the native layout is even stricter here, but it'd add unnecessary complexity to shave off a couple of more bits cursor.putByte( (byte) assertInt( "table id", crs.getTable().getTableId(), 0xFF ) ); cursor.putInt( crs.getCode() ); cursor.putShort( (short) assertInt( "max levels", settings.maxLevels, 0xFFFF ) ); cursor.putShort( (short) assertInt( "dimensions", settings.dimensions, 0xFFFF ) ); double[] min = settings.extents.getMin(); double[] max = settings.extents.getMax(); for ( int i = 0; i < settings.dimensions; i++ ) { cursor.putLong( Double.doubleToLongBits( min[i] ) ); cursor.putLong( Double.doubleToLongBits( max[i] ) ); } }
private void assertPointArrayHasCorrectFormat( PointValue[] array, int numberOfBitsUsedForDoubles ) { Collection<DynamicRecord> records = new ArrayList<>(); arrayStore.allocateRecords( records, array ); Pair<byte[],byte[]> loaded = loadArray( records ); assertGeometryHeader( loaded.first(), GeometryType.GEOMETRY_POINT.getGtype(), 2, array[0].getCoordinateReferenceSystem().getTable().getTableId(), array[0].getCoordinateReferenceSystem().getCode() ); final int dimension = array[0].coordinate().length; double[] pointDoubles = new double[array.length * dimension]; for ( int i = 0; i < pointDoubles.length; i++ ) { pointDoubles[i] = array[i / dimension].coordinate()[i % dimension]; } byte[] doubleHeader = Arrays.copyOf( loaded.other(), DynamicArrayStore.NUMBER_HEADER_SIZE ); byte[] doubleBody = Arrays.copyOfRange( loaded.other(), DynamicArrayStore.NUMBER_HEADER_SIZE, loaded.other().length ); assertNumericArrayHeaderAndContent( pointDoubles, PropertyType.DOUBLE, numberOfBitsUsedForDoubles, Pair.of( doubleHeader, doubleBody ) ); }
@Test public void shouldFailWhenPoint2DDimensionsDoNotMatch() throws Exception { testDisconnectWithUnpackableValue( packer -> { packer.packStructHeader( 3, StructType.POINT_3D.signature() ); packer.pack( Values.of( CoordinateReferenceSystem.Cartesian_3D.getCode() ) ); packer.pack( Values.of( 3.15 ) ); packer.pack( Values.of( 4.012 ) ); }, "Unable to construct Point value: `Cannot create point, CRS cartesian-3d expects 3 dimensions, but got coordinates [3.15, 4.012]`" ); }
@Test public void shouldFailWhenPoint3DDimensionsDoNotMatch() throws Exception { testFailureWithUnpackableValue( packer -> { packer.packStructHeader( 4, StructType.POINT_3D.signature() ); packer.pack( Values.of( CoordinateReferenceSystem.Cartesian.getCode() ) ); packer.pack( Values.of( 3.15 ) ); packer.pack( Values.of( 4.012 ) ); packer.pack( Values.of( 5.905 ) ); }, "Unable to construct Point value: `Cannot create point, CRS cartesian expects 2 dimensions, but got coordinates [3.15, 4.012, 5.905]`" ); }
@Test public void shouldFailToUnpack2DPointWithIncorrectCoordinate() throws IOException { Neo4jPackV2 neo4jPack = new Neo4jPackV2(); PackedOutputArray output = new PackedOutputArray(); Neo4jPack.Packer packer = neo4jPack.newPacker( output ); packer.packStructHeader( 3, Neo4jPackV2.POINT_2D ); packer.pack( intValue( WGS84.getCode() ) ); packer.pack( doubleValue( 42.42 ) ); try { unpack( output ); fail( "Exception expected" ); } catch ( UncheckedIOException ignore ) { } }
@Test public void shouldFailToUnpack3DPointWithIncorrectCoordinate() throws IOException { Neo4jPackV2 neo4jPack = new Neo4jPackV2(); PackedOutputArray output = new PackedOutputArray(); Neo4jPack.Packer packer = neo4jPack.newPacker( output ); packer.packStructHeader( 4, Neo4jPackV2.POINT_3D ); packer.pack( intValue( Cartesian.getCode() ) ); packer.pack( doubleValue( 1.0 ) ); packer.pack( doubleValue( 100.1 ) ); try { unpack( output ); fail( "Exception expected" ); } catch ( UncheckedIOException ignore ) { } }