1
- package org .geoscript . layer
1
+ package org .geoscript
2
2
3
3
import java .io .File
4
4
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 }
7
7
import org .{ geotools => gt }
8
8
import com .vividsolutions .jts .{ geom => jts }
9
9
@@ -13,142 +13,132 @@ import org.geoscript.geometry._
13
13
import org .geoscript .projection ._
14
14
import org .geoscript .workspace .{Directory ,Workspace }
15
15
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 ]
24
19
25
20
/**
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.
32
22
*/
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
+ }
34
57
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
+ }
48
90
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 }
61
92
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
+ }
66
100
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
+ }
71
104
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
+ }
76
108
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
+ }
84
115
85
- try {
86
- for (f <- features) {
87
- writer.next.attributes = f.attributes
116
+ while (writer.hasNext) {
117
+ val existing = writer.next()
118
+ replace(existing)
88
119
writer.write()
89
120
}
90
- tx.commit()
91
- } catch {
92
- case (ex : java.io.IOException ) =>
93
- tx.rollback()
94
- throw ex
95
- } finally {
121
+
96
122
writer.close()
123
+ tx.commit()
97
124
tx.close()
98
125
}
99
126
}
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)
139
127
}
140
128
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
+ }
153
143
}
154
144
}
0 commit comments