Skip to content

Commit 31e1555

Browse files
committed
Use implicits rather than wrapper for Layer also
1 parent 3a4e333 commit 31e1555

File tree

4 files changed

+116
-129
lines changed

4 files changed

+116
-129
lines changed

geoscript/src/main/scala/feature/builder/Builder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ package builder {
193193
}
194194
def unapply(feature: Feature): Option[T] = {
195195
val att = feature.getAttribute(name)
196-
if (clazz.isInstance(att))
196+
if (att == null || clazz.isInstance(att))
197197
Some(clazz.cast(att))
198198
else
199199
None
Lines changed: 112 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package org.geoscript.layer
1+
package org.geoscript
22

33
import java.io.File
44

5-
import org.opengis.feature.simple.{ SimpleFeature, SimpleFeatureType }
6-
import org.opengis.feature.`type`.{ AttributeDescriptor, GeometryDescriptor }
5+
// import org.opengis.feature.simple.{ SimpleFeature, SimpleFeatureType }
6+
// import org.opengis.feature.`type`.{ AttributeDescriptor, GeometryDescriptor }
77
import org.{ geotools => gt }
88
import com.vividsolutions.jts.{ geom => jts }
99

@@ -13,142 +13,132 @@ import org.geoscript.geometry._
1313
import org.geoscript.projection._
1414
import org.geoscript.workspace.{Directory,Workspace}
1515

16-
/**
17-
* A Layer represents a geospatial dataset.
18-
*/
19-
trait Layer {
20-
/**
21-
* The name of this data set
22-
*/
23-
val name: String
16+
package object layer {
17+
type Layer = org.geotools.data.FeatureSource[Schema, Feature]
18+
type WritableLayer = org.geotools.data.FeatureStore[Schema, Feature]
2419

2520
/**
26-
* The GeoTools datastore that is wrapped by this Layer.
27-
*/
28-
def store: gt.data.DataStore
29-
30-
/**
31-
* The workspace containing this layer.
21+
* A Layer represents a geospatial dataset.
3222
*/
33-
def workspace: Workspace
23+
implicit class RichLayer(val source: Layer) extends AnyVal {
24+
/**
25+
* The name of this data set
26+
*/
27+
def name: String = schema.name
28+
29+
/**
30+
* The Schema describing this layer's contents.
31+
*/
32+
def schema: Schema = source.getSchema
33+
34+
/**
35+
* Get a feature collection that supports the typical Scala collection
36+
* operations.
37+
*/
38+
def features: FeatureCollection =
39+
source.getFeatures(new gt.data.Query)
40+
41+
/**
42+
* Get a filtered feature collection.
43+
*/
44+
def filter(pred: Filter): FeatureCollection =
45+
source.getFeatures(new gt.data.Query(name, pred))
46+
47+
/**
48+
* Get the number of features currently in the layer.
49+
*/
50+
def count: Int = source.getCount(new gt.data.Query())
51+
52+
/**
53+
* Get the bounding box of this Layer, in the format:
54+
*/
55+
def envelope: Envelope = source.getBounds() // in schema.geometry.projection
56+
}
3457

35-
/**
36-
* Retrieve a GeoTools feature source for this layer.
37-
*/
38-
def source:
39-
org.geotools.data.FeatureSource[
40-
org.opengis.feature.simple.SimpleFeatureType,
41-
org.opengis.feature.simple.SimpleFeature]
42-
= store.getFeatureSource(name)
43-
44-
/**
45-
* The Schema describing this layer's contents.
46-
*/
47-
def schema: Schema = store.getSchema(name)
58+
implicit class RichWritableLayer(val store: WritableLayer) extends AnyVal {
59+
/**
60+
* Add a single Feature to this data set.
61+
*/
62+
def += (f: Feature*) { this ++= f }
63+
64+
private
65+
def dstore = store.getDataStore.asInstanceOf[org.geotools.data.DataStore]
66+
67+
/**
68+
* Add multiple features to this data set. This should be preferred over
69+
* repeated use of += when adding multiple features.
70+
*/
71+
def ++= (features: Traversable[Feature]) {
72+
val tx = new gt.data.DefaultTransaction
73+
val writer = dstore.getFeatureWriterAppend(store.name, tx)
74+
75+
try {
76+
for (f <- features) {
77+
writer.next.attributes = f.attributes
78+
writer.write()
79+
}
80+
tx.commit()
81+
} catch {
82+
case (ex: java.io.IOException) =>
83+
tx.rollback()
84+
throw ex
85+
} finally {
86+
writer.close()
87+
tx.close()
88+
}
89+
}
4890

49-
/**
50-
* Get a feature collection that supports the typical Scala collection
51-
* operations.
52-
*/
53-
def features: FeatureCollection =
54-
source.getFeatures(new gt.data.Query)
55-
56-
/**
57-
* Get a filtered feature collection.
58-
*/
59-
def filter(pred: Filter): FeatureCollection =
60-
source.getFeatures(new gt.data.Query(name, pred))
91+
def -= (feature: Feature*) { this --= feature }
6192

62-
/**
63-
* Get the number of features currently in the layer.
64-
*/
65-
def count: Int = source.getCount(new gt.data.Query())
93+
def --= (features: Traversable[Feature]) {
94+
exclude(Filter.id(
95+
features.filter { null != _ }
96+
.map { f => f.id }
97+
.toSeq
98+
))
99+
}
66100

67-
/**
68-
* Get the bounding box of this Layer, in the format:
69-
*/
70-
def envelope: Envelope = source.getBounds() // in schema.geometry.projection
101+
def exclude(filter: Filter) {
102+
store.removeFeatures(filter)
103+
}
71104

72-
/**
73-
* Add a single Feature to this data set.
74-
*/
75-
def += (f: Feature) { this ++= Seq(f) }
105+
def update(replace: Feature => Unit) {
106+
update(Include)(replace)
107+
}
76108

77-
/**
78-
* Add multiple features to this data set. This should be preferred over
79-
* repeated use of += when adding multiple features.
80-
*/
81-
def ++= (features: Traversable[Feature]) {
82-
val tx = new gt.data.DefaultTransaction
83-
val writer = store.getFeatureWriterAppend(name, tx)
109+
def update(filter: Filter)(replace: Feature => Unit) {
110+
val tx = new gt.data.DefaultTransaction
111+
val writer = filter match {
112+
case Include => dstore.getFeatureWriter(store.name, tx)
113+
case filter => dstore.getFeatureWriter(store.name, filter, tx)
114+
}
84115

85-
try {
86-
for (f <- features) {
87-
writer.next.attributes = f.attributes
116+
while (writer.hasNext) {
117+
val existing = writer.next()
118+
replace(existing)
88119
writer.write()
89120
}
90-
tx.commit()
91-
} catch {
92-
case (ex: java.io.IOException) =>
93-
tx.rollback()
94-
throw ex
95-
} finally {
121+
96122
writer.close()
123+
tx.commit()
97124
tx.close()
98125
}
99126
}
100-
101-
def -= (feature: Feature) { this --= Seq(feature) }
102-
103-
def --= (features: Traversable[Feature]) {
104-
exclude(Filter.or(
105-
features.toSeq filter { null != _ } map { f => Filter.id(Seq(f.id)) }
106-
))
107-
}
108-
109-
def exclude(filter: Filter) {
110-
store.getFeatureSource(name)
111-
.asInstanceOf[gt.data.FeatureStore[SimpleFeatureType, SimpleFeature]]
112-
.removeFeatures(filter)
113-
}
114-
115-
def update(replace: Feature => Unit) {
116-
update(Include)(replace)
117-
}
118-
119-
def update(filter: Filter)(replace: Feature => Unit) {
120-
val tx = new gt.data.DefaultTransaction
121-
val writer = filter match {
122-
case Include => store.getFeatureWriter(name, tx)
123-
case filter => store.getFeatureWriter(name, filter, tx)
124-
}
125-
126-
while (writer.hasNext) {
127-
val existing = writer.next()
128-
replace(existing)
129-
writer.write()
130-
}
131-
132-
writer.close()
133-
tx.commit()
134-
tx.close()
135-
}
136-
137-
override def toString: String =
138-
"<Layer name: %s, count: %d>".format(name, count)
139127
}
140128

141-
/**
142-
* Handy object for loading a Shapefile directly. The Shapefile layer is
143-
* implicitly created in a Directory datastore.
144-
*/
145-
object Shapefile {
146-
private def basename(f: File) = f.getName().replaceFirst("\\.[^.]+$", "")
147-
148-
def apply(path: String): Layer = apply(new File(path))
149-
150-
def apply(file: File): Layer = {
151-
val ws = Directory(file.getParent())
152-
ws.layer(basename(file))
129+
package layer {
130+
/**
131+
* Handy object for loading a Shapefile directly. The Shapefile layer is
132+
* implicitly created in a Directory datastore.
133+
*/
134+
object Shapefile {
135+
private def basename(f: File) = f.getName().replaceFirst("\\.[^.]+$", "")
136+
137+
def apply(path: String): Layer = apply(new File(path))
138+
139+
def apply(file: File): Layer = {
140+
val ws = Directory(file.getParent())
141+
ws.layer(basename(file))
142+
}
153143
}
154144
}

geoscript/src/main/scala/render/Viewport.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package org.geoscript
22

3-
import io._
43

54
import org.{ geotools => gt }
65
import com.vividsolutions.jts.{geom=>jts}
76
import java.awt.{ Graphics2D, Rectangle, RenderingHints }
87
import gt.geometry.jts.ReferencedEnvelope
98
import scala.collection.JavaConverters._
9+
import org.geoscript.io._
1010
import org.geoscript.geometry._
11+
import org.geoscript.layer._
1112

1213
package render {
1314
trait Context[T] {

geoscript/src/main/scala/workspace/Workspace.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ class Workspace(
1212
) {
1313
def count = underlying.getTypeNames.length
1414
def names: Seq[String] = underlying.getTypeNames
15-
def layer(theName: String): Layer = new Layer {
16-
val name = theName
17-
val workspace = Workspace.this
18-
val store = underlying
19-
}
15+
def layer(theName: String): Layer = underlying.getFeatureSource(theName)
2016

2117
def create(name: String, fields: Field*): Layer = create(name, fields)
2218

0 commit comments

Comments
 (0)