/* Copyright 2013 The jeo project. All rights reserved. * * Licensed 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 io.jeo.data.mem; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.vividsolutions.jts.geom.Envelope; import io.jeo.geom.Bounds; import io.jeo.vector.DiffFeature; import io.jeo.vector.FeatureAppendCursor; import io.jeo.vector.FeatureCursor; import io.jeo.vector.FeatureWriteCursor; import io.jeo.vector.Field; import io.jeo.vector.VectorQueryPlan; import io.jeo.vector.VectorQuery; import io.jeo.vector.VectorDataset; import io.jeo.vector.Feature; import io.jeo.vector.Schema; import io.jeo.util.Key; import org.osgeo.proj4j.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.index.SpatialIndex; import com.vividsolutions.jts.index.quadtree.Quadtree; public class MemVectorDataset implements VectorDataset { Schema schema; Map<String,Feature> features = new LinkedHashMap<>(); SpatialIndex index; public MemVectorDataset() { this(Schema.build("feature").schema()); } public MemVectorDataset(Schema schema) { this.schema = schema; index = new Quadtree(); } public Memory driver() { return new Memory(); } public Map<Key<?>,Object> driverOptions() { return Collections.emptyMap(); } Iterable<Feature> features() { return features.values(); } @Override public String name() { return schema.name(); } @Override public CoordinateReferenceSystem crs() { return schema.crs(); } @Override public Bounds bounds() throws IOException { if (schema.geometry() == null) { return null; } Bounds e = new Bounds(); e.setToNull(); if (features.isEmpty()) { return e; } for (Feature f : features()) { Geometry g = f.geometry(); if (g != null) { e.expandToInclude(g.getEnvelopeInternal()); } } return e; } @Override public Schema schema() { return schema; } @Override public long count(VectorQuery q) throws IOException { return read(q).count(); } @Override public FeatureCursor read(VectorQuery q) throws IOException { VectorQueryPlan qp = new VectorQueryPlan(q); Iterable<Feature> features = features(); if (!Bounds.isNull(q.bounds())) { features = query(q.bounds()); qp.bounded(); } return qp.apply(new MemFeatureCursor(features)); } @Override public FeatureWriteCursor update(VectorQuery q) throws IOException { return new MemFeatureWriteCursor(read(q).iterator(), this); } @Override public FeatureAppendCursor append(VectorQuery q) throws IOException { return new MemFeatureAppendCursor(this); } List<Feature> query(Envelope bounds) { List<Feature> features = index.query(bounds); for (Iterator<Feature> it = features.iterator(); it.hasNext(); ) { Feature f = it.next(); if (!bounds.intersects(f.geometry().getEnvelopeInternal())) { it.remove(); } } return features; } public void add(Feature f) { features.put(f.id(), f); Geometry g = f.geometry(); if (g != null) { index.insert(g.getEnvelopeInternal(), f); } } public void remove(Feature f) { features.remove(f.id()); Geometry g = f.geometry(); if (g != null) { index.remove(g.getEnvelopeInternal(), f); } } void modify(DiffFeature f) { Feature pre = f.getDelegate(); Field geo = schema.geometry(); if (geo != null && f.changed().containsKey(geo.name())) { Geometry g1 = pre.geometry(); Geometry g2 = f.geometry(); if (g1 != null) { index.remove(g1.getEnvelopeInternal(), pre); } if (g2 != null) { index.insert(g2.getEnvelopeInternal(), pre); } } f.apply(); add(f.getDelegate()); } @Override public void close() { } }