├── .gitignore
├── README.md
├── benchmark
└── src
│ └── main
│ └── scala
│ └── jtscala
│ └── benchmark
│ └── Main.scala
├── core
└── src
│ ├── main
│ └── scala
│ │ └── jtscala
│ │ ├── Factory.scala
│ │ ├── Geometry.scala
│ │ ├── GeometryCollection.scala
│ │ ├── GeometrySet.scala
│ │ ├── Line.scala
│ │ ├── LineSet.scala
│ │ ├── Main.scala
│ │ ├── Point.scala
│ │ ├── PointSet.scala
│ │ ├── Polygon.scala
│ │ ├── PolygonSet.scala
│ │ ├── Results.scala
│ │ └── package.scala
│ └── test
│ └── scala
│ └── jtscala
│ ├── check
│ ├── Generators.scala
│ └── jts
│ │ ├── Generators.scala
│ │ ├── LineStringCheck.scala
│ │ ├── MultiLineStringCheck.scala
│ │ ├── MultiPointCheck.scala
│ │ ├── PointCheck.scala
│ │ └── PolygonCheck.scala
│ └── spec
│ ├── LineSpec.scala
│ ├── PointSpec.scala
│ └── PolygonSpec.scala
├── project
├── Build.scala
└── build.properties
└── sbt
/.gitignore:
--------------------------------------------------------------------------------
1 | project/boot
2 | project/plugins/project
3 | project/plugins/target
4 | project/target
5 | target
6 | .ensime
7 | TAGS
8 | \#*#
9 | *~
10 | .#*
11 | .lib
12 | *.aux.xml
13 |
14 | *.pyc
15 | .project
16 | .classpath
17 | .cache
18 | .settings
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JTScala
2 |
3 | This is a scala wrapper around the [Java Topology Suite](http://www.vividsolutions.com/jts/JTSHome.htm)
4 | that aims to provide an idiomatic scala interface around JTS, as well
5 | as implement a more type-safe way of interacting with JTS.
6 |
--------------------------------------------------------------------------------
/benchmark/src/main/scala/jtscala/benchmark/Main.scala:
--------------------------------------------------------------------------------
1 | package jtscala.benchmark
2 |
3 | import jtscala.check.jts.Generators
4 |
5 | import org.scalacheck.{Prop,Test,Gen,Arbitrary}
6 |
7 | import com.vividsolutions.jts.geom._
8 |
9 | import java.lang.System.currentTimeMillis
10 | import scala.collection.mutable
11 |
12 | object Bench {
13 | def bench[T](times:Int,body: T => Unit, v:T):Long = {
14 | var i = 0
15 | val start = currentTimeMillis()
16 | while(i < times) {
17 | body(v)
18 | i += 1
19 | }
20 | val duration = currentTimeMillis() - start
21 | duration
22 | }
23 |
24 | def bench[T1,T2](times:Int,body: (T1,T2)=> Unit, v1:T1,v2:T2):Long = {
25 | var i = 0
26 | val start = currentTimeMillis()
27 | while(i < times) {
28 | body(v1,v2)
29 | i += 1
30 | }
31 | val duration = currentTimeMillis() - start
32 | duration
33 | }
34 |
35 | def benchmark[T,K](gen:Gen[T])(f:T=>K)(body:T=>Unit): List[(K,Int,Long)] = {
36 | val params = Test.Parameters.default
37 | import params._
38 |
39 | val genPrms = new Gen.Parameters.Default { override val rng = params.rng }
40 |
41 | val iterations = math.ceil(minSuccessfulTests)
42 | val sizeStep = (maxSize-minSize) / iterations
43 |
44 | var n = 0
45 | var skipped = 0
46 |
47 | val results = mutable.ListBuffer[(K,Int,Long)]()
48 | while(n < iterations && skipped < iterations) {
49 | val size = (minSize: Double) + (sizeStep * n)
50 | val propPrms = genPrms.resize(size.round.toInt)
51 | gen(propPrms) match {
52 | case None => skipped += 1
53 | case Some(value) =>
54 | val key = f(value)
55 | for (times <- Seq(1,10,50)) yield {
56 | if(n == 0) // warmup
57 | bench(times,body,value)
58 | else
59 | results += ((key,times,bench(times,body,value)))
60 | }
61 | }
62 | }
63 | results.toList
64 | }
65 |
66 | def benchmark[T1,T2,K](gen1:Gen[T1],gen2:Gen[T2])(f:(T1,T2)=>K)(body:(T1,T2)=>Unit):List[(K,Int,Long)] = {
67 | val params = Test.Parameters.default
68 | import params._
69 |
70 | val genPrms = new Gen.Parameters.Default { override val rng = params.rng }
71 |
72 | val iterations = math.ceil(minSuccessfulTests)
73 | val sizeStep = (maxSize-minSize) / iterations
74 |
75 | var n = 0
76 | var skipped = 0
77 |
78 | val results = mutable.ListBuffer[(K,Int,Long)]()
79 | while(n < iterations && skipped < iterations) {
80 | val size = (minSize: Double) + (sizeStep * n)
81 | val propPrms = genPrms.resize(size.round.toInt)
82 | gen1(propPrms) match {
83 | case None => skipped += 1
84 | case Some(value1) =>
85 | gen2(propPrms) match {
86 | case None => skipped += 1
87 | case Some(value2) =>
88 | val key = f(value1,value2)
89 | for (times <- Seq(1,2)) yield {
90 | if(n == 0) // warmup
91 | bench(times,body,value1,value2)
92 | else
93 | results += ((key,times,bench(times,body,value1,value2)))
94 | }
95 | n += 1
96 | }
97 | }
98 | }
99 | results.toList
100 | }
101 |
102 | def benchmarkArb[T,K](f:T=>K)(body:T=>Unit)(implicit arb:Arbitrary[T]): List[(K,Int,Long)] =
103 | benchmark(arb.arbitrary)(f)(body)
104 |
105 | def benchmarkArb[T1,T2,K](f:(T1,T2)=>K)(body:(T1,T2)=>Unit)(implicit arb1:Arbitrary[T1],arb2:Arbitrary[T2]): List[(K,Int,Long)] =
106 | benchmark(arb1.arbitrary,arb2.arbitrary)(f)(body)
107 | }
108 |
109 | object MultiBenchmark {
110 | import Generators._
111 | import Bench._
112 |
113 | def countMulti(m:MultiLineString):Int = m.getNumGeometries
114 |
115 | def do1() = {
116 | val results =
117 | benchmarkArb((ml:MultiLineString,p:Point) => countMulti(ml))({ (ml: MultiLineString,p:Point) =>
118 | p.intersection(ml)//.intersection(p)
119 | })
120 |
121 | val (times,duration) =
122 | results
123 | .map { case (count,times,duration) => (count*times,duration) }
124 | .reduce { (t1,t2) => (t1._1+t2._1,t1._2+t2._2) }
125 | println(s"Average for line string point intersection: ${times/duration.toDouble}")
126 | }
127 |
128 | def do2() = {
129 | val results =
130 | benchmarkArb((ml:List[LineString],p:Point) => ml.size)({ (ml: List[LineString],p:Point) =>
131 | val v =
132 | ml.map(_.intersection(p)).find(!_.isEmpty) match {
133 | case Some(p) => p
134 | case None => null
135 | }
136 | })
137 |
138 | val (times,duration) =
139 | results
140 | .map { case (count,times,duration) => (count*times,duration) }
141 | .reduce { (t1,t2) => (t1._1+t2._1,t1._2+t2._2) }
142 | println(s"Average for line string Seq point intersection: ${times/duration.toDouble}")
143 | }
144 |
145 | lazy val genListLineString:Gen[List[LineString]] =
146 | Gen.choose(1,20).flatMap(Gen.containerOfN[List,LineString](_,genLineString))
147 | lazy val arbListLineString:Arbitrary[List[LineString]] =
148 | Arbitrary(genListLineString)
149 |
150 | def main(args:Array[String]):Unit = {
151 | do1()
152 | // do2()
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Factory.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.geom
4 |
5 | private[jtscala] object GeomFactory {
6 | val factory = new geom.GeometryFactory()
7 | }
8 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Geometry.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom => jts}
4 |
5 | trait Geometry {
6 | val geom:jts.Geometry
7 |
8 | //def area:Double = geom.getArea
9 | def centroid:Point = Point(geom.getCentroid)
10 | def interiorPoint:Point = Point(geom.getInteriorPoint)
11 |
12 | def coveredBy(other:Geometry) =
13 | geom.coveredBy(other.geom)
14 |
15 | def covers(other:Geometry) =
16 | geom.covers(other.geom)
17 |
18 | def intersects(other:Geometry) =
19 | geom.intersects(other.geom)
20 |
21 | def disjoint(other:Geometry) =
22 | geom.disjoint(other.geom)
23 |
24 | def touches(other:Geometry) =
25 | geom.touches(other.geom)
26 |
27 | def distance(other:Geometry) =
28 | geom.distance(other.geom)
29 |
30 | // Curious to benchmark this against .distance < d,
31 | // JTS implements it as a different op, I'm assuming
32 | // for speed.
33 | def withinDistance(other:Geometry,d:Double) =
34 | geom.isWithinDistance(other.geom,d)
35 |
36 | // TO BE IMPLEMENTED ON A PER TYPE BASIS
37 |
38 | // union ( | )
39 |
40 | // crosses
41 | // difference ( - )
42 | // equal (with tolerance?)
43 | // equalExact (huh?)
44 | // boundary
45 | // vertices
46 | // envelope
47 | // boundingBox
48 | // length
49 | // perimeter
50 |
51 | // isSimple
52 | // isValid ( don't allow invalid? )
53 | // normalize (hmmm)
54 | // overlaps (needs interior to be same dimension as geoms, geom dims ==)
55 | // symDifference
56 |
57 | // within
58 | // something with relate if it's fast (benchmark)
59 |
60 | /**IMPLEMENTED**/
61 | // buffer - None on collections, always a polygon. (wait maybe on Multli's)
62 | // contains - Not on collections (wait maybe on Multli's) - if not, then other Geometry methods don't belong.
63 | // isRectangle (polygon)
64 | // def area:Double = geom.getArea (not for points?)
65 |
66 |
67 | // def boundary = jts.getBoundary
68 | // def boundaryDimension = jts.getBoundaryDimension
69 | // def centriod = jts.getCentroid
70 | // def coordinate:(Double,Double) = jts.getCoordinate
71 | // def coordinates:Seq[(Double,Double)] = jts.getCoordinates
72 | // def dimension = jts.getDimension
73 | }
74 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/GeometryCollection.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 | import GeomFactory._
3 |
4 | import com.vividsolutions.jts.{geom=>jts}
5 | import scala.collection.mutable
6 |
7 | case class GeometryCollection(points:Set[Point],lines:Set[Line],polygons:Set[Polygon],gc:jts.GeometryCollection) {
8 | val geom = factory.createGeometryCollection((points ++ lines ++ polygons).map(_.geom).toArray)
9 | }
10 |
11 | object GeometryCollection {
12 | def apply(points:Set[Point],lines:Set[Line],polygons:Set[Polygon]):GeometryCollection = {
13 | val geom = factory.createGeometryCollection((points ++ lines ++ polygons).map(_.geom).toArray)
14 | GeometryCollection(points,lines,polygons,geom)
15 | }
16 |
17 | implicit def jtsToGeometryCollection(gc:jts.GeometryCollection):GeometryCollection = {
18 | val (points,lines,polygons) = collectGeometries(gc)
19 | GeometryCollection(points,lines,polygons,gc)
20 | }
21 |
22 | @inline final private
23 | def collectGeometries(gc:jts.GeometryCollection):(Set[Point],Set[Line],Set[Polygon]) = {
24 | val points = mutable.Set[Point]()
25 | val lines = mutable.Set[Line]()
26 | val polygons = mutable.Set[Polygon]()
27 |
28 | val len = gc.getNumGeometries
29 | for(i <- 0 until len) {
30 | gc.getGeometryN(i) match {
31 | case p:jts.Point => points += p
32 | case mp:jts.MultiPoint => points ++= mp
33 | case l:jts.LineString => lines += l
34 | case ml:jts.MultiLineString => lines ++= ml
35 | case p:jts.Polygon => polygons += p
36 | case mp:jts.MultiPolygon => polygons ++= mp
37 | case gc:jts.GeometryCollection =>
38 | val (ps,ls,polys) = collectGeometries(gc)
39 | points ++= ps
40 | lines ++= ls
41 | polygons ++= polys
42 | }
43 | }
44 | (points.toSet,lines.toSet,polygons.toSet)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/GeometrySet.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | trait GeometrySet extends Geometry {
7 | def &(p:Point) = intersection(p)
8 | def intersection(p:Point):PointIntersectionResult =
9 | p.intersection(this)
10 |
11 | def &(ps:PointSet) = intersection(ps)
12 | def intersection(ps:PointSet):PointSetIntersectionResult =
13 | geom.intersection(ps.geom)
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Line.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | object Line {
7 | implicit def jtsToLine(geom:jts.LineString):Line = apply(geom)
8 |
9 | def apply(geom:jts.LineString):Line =
10 | Line(geom,geom.getCoordinates.map(c => Point(c.x,c.y)).toList)
11 |
12 | def apply(points:Seq[Point]):Line =
13 | apply(points.toList)
14 | def apply(points:Array[Point]):Line =
15 | apply(points.toList)
16 | def apply(points:List[Point]):Line = {
17 | if(points.length < 2) { sys.error("Invalid line: Requires 2 or more points.") }
18 | Line(factory.createLineString(points.map(_.geom.getCoordinate).toArray),points)
19 | }
20 | }
21 |
22 | case class Line(geom:jts.LineString,points:List[Point]) extends Geometry {
23 | assert(!geom.isEmpty)
24 |
25 | def &(p:Point) = intersection(p)
26 | def intersection(p:Point):PointIntersectionResult = p.intersection(this)
27 |
28 | def &(l:Line) = intersection(l)
29 | def intersection(l:Line):LineLineIntersectionResult =
30 | geom.intersection(l.geom)
31 |
32 | def &(p:Polygon) = intersection(p)
33 | def intersection(p:Polygon):PolygonLineIntersectionResult =
34 | geom.intersection(p.geom)
35 |
36 | def &(ps:PointSet) = intersection(ps)
37 | def intersection(ps:PointSet):PointSetIntersectionResult = ps.intersection(this)
38 |
39 | def &(ls:LineSet) = intersection(ls)
40 | def intersection(ls:LineSet):LineSetIntersectionResult = ls.intersection(this)
41 |
42 | def &(ps:PolygonSet) = intersection(ps)
43 | def intersection(ps:PolygonSet):LineSetIntersectionResult = ps.intersection(this)
44 |
45 | def |(p:Point) = union(p)
46 | def union(p:Point):LinePointUnionResult =
47 | geom.union(p.geom)
48 |
49 | def |(l:Line) = union(l)
50 | def union(l:Line):LineLineUnionResult =
51 | geom.union(l.geom)
52 |
53 | def |(p:Polygon) = union(p)
54 | def union(p:Polygon):PolygonXUnionResult = p.union(this)
55 |
56 | // Not sure what to do about LinearString, if it really
57 | // needs to be around...will make construction of Polys
58 | // tougher maybe.
59 | def isClosed = geom.isClosed
60 |
61 | def crosses(g:Geometry) = geom.crosses(g.geom)
62 |
63 | def contains(p:Point) = geom.contains(p.geom)
64 | def contains(l:Line) = geom.contains(l.geom)
65 | def within(l:Line) = geom.within(l.geom)
66 | def within(p:Polygon) = geom.within(p.geom)
67 |
68 | def difference(g:Geometry):Set[Line] =
69 | geom.difference(g.geom) match {
70 | case ml:jts.MultiLineString =>
71 | ml
72 | case l:jts.LineString =>
73 | Set(Line(l))
74 | case x =>
75 | assert(x.isEmpty)
76 | Set()
77 | }
78 |
79 | def buffer(d:Double):Polygon =
80 | geom.buffer(d).asInstanceOf[Polygon]
81 | }
82 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/LineSet.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | case class LineSet(ls:Set[Line]) extends GeometrySet {
7 | val geom = factory.createMultiLineString(ls.map(_.geom).toArray)
8 |
9 | def &(l:Line) = intersection(l)
10 | def intersection(l:Line):LineSetIntersectionResult =
11 | geom.intersection(l.geom)
12 |
13 | def &(p:Polygon) = intersection(p)
14 | def intersection(p:Polygon):LineSetIntersectionResult =
15 | geom.intersection(p.geom)
16 |
17 | def &(ls:LineSet) = intersection(ls)
18 | def intersection(ls:LineSet):LineSetIntersectionResult =
19 | geom.intersection(ls.geom)
20 |
21 | def &(ps:PolygonSet) = intersection(ps)
22 | def intersection(ps:PolygonSet):LineSetIntersectionResult =
23 | geom.intersection(ps.geom)
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Main.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.geom
4 |
5 | abstract sealed class GeometryType
6 |
7 | object GeometryType {
8 | implicit def jtsToGeometryType(g:geom.Geometry) =
9 | stringToGeometryType(g.getGeometryType)
10 |
11 | implicit def stringToGeometryType(s:String) =
12 | s match {
13 | case "GeometryCollection" => GeometryCollectionType
14 | case "Point" => PointType
15 | case "LineString" => LineStringType
16 | case "LinearRing" => LinearRingType
17 | case "Polygon" => PolygonType
18 | case "MultiPoint" => MultiPointType
19 | case "MultiLineString" => MultiLineStringType
20 | case "MultiPolygon" => MultiPolygonType
21 |
22 | }
23 | }
24 |
25 | case object GeometryCollectionType extends GeometryType
26 | case object PointType extends GeometryType
27 | case object LineStringType extends GeometryType
28 | case object LinearRingType extends GeometryType
29 | case object PolygonType extends GeometryType
30 | case object MultiPointType extends GeometryType
31 | case object MultiLineStringType extends GeometryType
32 | case object MultiPolygonType extends GeometryType
33 |
34 | object Main {
35 | def main(args:Array[String]) = {
36 |
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Point.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | case class Point(geom:jts.Point) extends Geometry {
7 | assert(!geom.isEmpty)
8 | val x = geom.getX
9 | val y = geom.getY
10 |
11 | def &(other:Geometry) = intersection(other)
12 | def intersection(other:Geometry):PointIntersectionResult =
13 | geom.intersection(other.geom)
14 |
15 | def |(p:Point) = union(p)
16 | def union(p:Point):PointPointUnionResult =
17 | geom.union(p.geom)
18 |
19 | def |(l:Line) = union(l)
20 | def union(l:Line):LinePointUnionResult = l.union(this)
21 |
22 | def |(p:Polygon) = union(p)
23 | def union(p:Polygon):PolygonXUnionResult = p.union(this)
24 |
25 | def buffer(d:Double):Polygon =
26 | geom.buffer(d).asInstanceOf[Polygon]
27 |
28 | def within(l:Line) = geom.within(l.geom)
29 | def within(p:Polygon) = geom.within(p.geom)
30 | }
31 |
32 | object Point {
33 | def apply(x:Double,y:Double):Point =
34 | Point(factory.createPoint(new jts.Coordinate(x,y)))
35 |
36 | implicit def jts2Point(geom:jts.Point):Point = apply(geom)
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/PointSet.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | case class PointSet(ps:Set[Point]) extends GeometrySet {
7 | val geom = factory.createMultiPoint(ps.map(_.geom).toArray)
8 |
9 | def &(l:Line) = intersection(l)
10 | def intersection(l:Line):PointSetIntersectionResult =
11 | geom.intersection(l.geom)
12 |
13 | def &(p:Polygon) = intersection(p)
14 | def intersection(p:Polygon):PointSetIntersectionResult =
15 | geom.intersection(p.geom)
16 |
17 | def &(ls:LineSet) = intersection(ls)
18 | def intersection(ls:LineSet):PointSetIntersectionResult = ls.intersection(this)
19 |
20 | def &(ps:PolygonSet) = intersection(ps)
21 | def intersection(ps:PolygonSet):PointSetIntersectionResult = ps.intersection(this)
22 |
23 | def convexHull:Polygon =
24 | geom.convexHull.asInstanceOf[jts.Polygon]
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Polygon.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | object Polygon {
7 | implicit def jtsToPolygon(geom:jts.Polygon):Polygon = Polygon(geom)
8 |
9 | def apply(exterior:Line):Polygon =
10 | apply(exterior,Set())
11 |
12 | def apply(exterior:Line,holes:Set[Line]):Polygon = {
13 | if(!exterior.isClosed) {
14 | sys.error(s"Cannot create a polygon with unclosed exterior: $exterior")
15 | }
16 | if(exterior.points.length < 4) {
17 | sys.error(s"Cannot create a polygon with exterior with less that 4 points: $exterior")
18 | }
19 | val extGeom = factory.createLinearRing(exterior.geom.getCoordinates)
20 | val holeGeoms =
21 | (for(hole <- holes) yield {
22 | if(!hole.isClosed) {
23 | sys.error(s"Cannot create a polygon with an unclosed hole: $hole")
24 | } else {
25 | if(hole.points.length < 4)
26 | sys.error(s"Cannot create a polygon with a hole with less that 4 points: $hole")
27 | else
28 | factory.createLinearRing(hole.geom.getCoordinates)
29 | }
30 | }).toArray
31 | factory.createPolygon(extGeom,holeGeoms)
32 | }
33 | }
34 |
35 | case class Polygon(geom:jts.Polygon) extends Geometry {
36 | assert(!geom.isEmpty)
37 |
38 | lazy val exterior = Line(geom.getExteriorRing)
39 |
40 | def &(p:Point) = intersection(p)
41 | def intersection(p:Point):PointIntersectionResult = p.intersection(this)
42 |
43 | def &(l:Line) = intersection(l)
44 | def intersection(l:Line):PolygonLineIntersectionResult = l.intersection(this)
45 |
46 | def &(p:Polygon) = intersection(p)
47 | def intersection(p:Polygon):PolygonPolygonIntersectionResult =
48 | geom.intersection(p.geom)
49 |
50 | def &(ps:PointSet) = intersection(ps)
51 | def intersection(ps:PointSet):PointSetIntersectionResult = ps.intersection(this)
52 |
53 | def &(ls:LineSet) = intersection(ls)
54 | def intersection(ls:LineSet):LineSetIntersectionResult = ls.intersection(this)
55 |
56 | def &(ps:PolygonSet) = intersection(ps)
57 | def intersection(ps:PolygonSet):PolygonSetIntersectionResult = ps.intersection(this)
58 |
59 | def |(p:Point) = union(p)
60 | def union(p:Point):PolygonXUnionResult =
61 | geom.union(p.geom)
62 |
63 | def |(l:Line) = union(l)
64 | def union(l:Line):PolygonXUnionResult =
65 | geom.union(l.geom)
66 |
67 | def |(p:Polygon) = union(p)
68 | def union(p:Polygon):PolygonPolygonUnionResult =
69 | geom.union(p.geom)
70 |
71 | def buffer(d:Double):Polygon =
72 | geom.buffer(d).asInstanceOf[Polygon]
73 |
74 | def contains(p:Point) = geom.contains(p.geom)
75 | def contains(l:Line) = geom.contains(l.geom)
76 | def contains(p:Polygon) = geom.contains(p.geom)
77 |
78 | def within(p:Polygon) = geom.within(p.geom)
79 |
80 | lazy val isRectangle = geom.isRectangle
81 |
82 | lazy val area = geom.getArea
83 | }
84 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/PolygonSet.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 | import GeomFactory._
5 |
6 | case class PolygonSet(ps:Set[Polygon]) extends GeometrySet {
7 | val geom = factory.createMultiPolygon(ps.map(_.geom).toArray)
8 |
9 | def &(l:Line) = intersection(l)
10 | def intersection(l:Line):LineSetIntersectionResult =
11 | geom.intersection(l.geom)
12 |
13 | def &(p:Polygon) = intersection(p)
14 | def intersection(p:Polygon):PolygonSetIntersectionResult =
15 | geom.intersection(p.geom)
16 |
17 | def &(ls:LineSet):LineSetIntersectionResult = intersection(ls)
18 | def intersection(ls:LineSet):LineSetIntersectionResult = ls.intersection(this)
19 |
20 | def &(ps:PolygonSet) = intersection(ps)
21 | def intersection(ps:PolygonSet):PolygonSetIntersectionResult =
22 | geom.intersection(ps.geom)
23 |
24 | def |(p:Point) = union(p)
25 | def union(p:Point):PolygonSetUnionResult =
26 | geom.union(p.geom)
27 |
28 | def |(l:Line) = union(l)
29 | def union(l:Line):PolygonSetUnionResult =
30 | geom.union(l.geom)
31 |
32 | def |(p:Polygon) = union(p)
33 | def union(p:Polygon):PolygonPolygonUnionResult =
34 | geom.union(p.geom)
35 |
36 | lazy val area:Double = geom.getArea
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/Results.scala:
--------------------------------------------------------------------------------
1 | package jtscala
2 |
3 | import com.vividsolutions.jts.{geom=>jts}
4 |
5 | abstract sealed trait Result
6 | object Result {
7 | implicit def jtsToResult(geom:jts.Geometry):Result =
8 | geom match {
9 | case p:jts.Point => PointResult(p)
10 | case l:jts.LineString => LineResult(l)
11 | case p:jts.Polygon => PolygonResult(p)
12 | case ps:jts.MultiPoint => PointSetResult(ps)
13 | case ps:jts.MultiPolygon => PolygonSetResult(ps)
14 | case ls:jts.MultiLineString => LineSetResult(ls)
15 | case gc:jts.GeometryCollection => GeometryCollectionResult(gc)
16 | case _ => NoResult
17 | }
18 | }
19 |
20 | abstract sealed trait PointIntersectionResult
21 | object PointIntersectionResult {
22 | implicit def jtsToResult(geom:jts.Geometry):PointIntersectionResult =
23 | geom match {
24 | case p:jts.Point => PointResult(p)
25 | case _ => NoResult
26 | }
27 | }
28 |
29 | abstract sealed trait LineLineIntersectionResult
30 | object LineLineIntersectionResult {
31 | implicit def jtsToResult(geom:jts.Geometry):LineLineIntersectionResult =
32 | geom match {
33 | case p:jts.Point => PointResult(p)
34 | case l:jts.LineString => LineResult(l)
35 | case _ => NoResult
36 | }
37 | }
38 |
39 | abstract sealed trait PolygonLineIntersectionResult
40 | object PolygonLineIntersectionResult {
41 | implicit def jtsToResult(geom:jts.Geometry):PolygonLineIntersectionResult =
42 | geom match {
43 | case p:jts.Point => PointResult(p)
44 | case l:jts.LineString => LineResult(l)
45 | case l:jts.MultiLineString => LineSetResult(l)
46 | case _ => NoResult
47 | }
48 | }
49 |
50 | abstract sealed trait PolygonPolygonIntersectionResult
51 | object PolygonPolygonIntersectionResult {
52 | implicit def jtsToResult(geom:jts.Geometry):PolygonPolygonIntersectionResult =
53 | geom match {
54 | case p:jts.Point => PointResult(p)
55 | case l:jts.LineString => LineResult(l)
56 | case p:jts.Polygon => PolygonResult(p)
57 | case ps:jts.MultiPoint => PointSetResult(ps)
58 | case ps:jts.MultiPolygon => PolygonSetResult(ps)
59 | case ls:jts.MultiLineString => LineSetResult(ls)
60 | case gc:jts.GeometryCollection => GeometryCollectionResult(gc)
61 | case _ => NoResult
62 | }
63 | }
64 |
65 | abstract sealed trait PointSetIntersectionResult
66 | object PointSetIntersectionResult {
67 | implicit def jtsToResult(geom:jts.Geometry):PointSetIntersectionResult =
68 | geom match {
69 | case p:jts.Point => if(p.isEmpty) NoResult else PointResult(p)
70 | case mp:jts.MultiPoint => PointSetResult(mp)
71 | case x =>
72 | sys.error(s"Unexpected result for PointSet intersection: ${geom.getGeometryType}")
73 | }
74 | }
75 |
76 | abstract sealed trait LineSetIntersectionResult
77 | object LineSetIntersectionResult {
78 | implicit def jtsToResult(geom:jts.Geometry): LineSetIntersectionResult =
79 | geom match {
80 | case p: jts.Point => PointResult(p)
81 | case l: jts.LineString => if(l.isEmpty) NoResult else LineResult(l)
82 | case mp: jts.MultiPoint => PointSetResult(mp)
83 | case ml: jts.MultiLineString => LineSetResult(ml)
84 | case gc: jts.GeometryCollection => GeometryCollectionResult(gc)
85 | case x =>
86 | sys.error(s"Unexpected result for LineSet intersection: ${geom.getGeometryType}")
87 | }
88 | }
89 |
90 | abstract sealed trait PolygonSetIntersectionResult
91 | object PolygonSetIntersectionResult {
92 | implicit def jtsToResult(geom:jts.Geometry): PolygonSetIntersectionResult =
93 | geom match {
94 | case p: jts.Point => PointResult(p)
95 | case l: jts.LineString => LineResult(l)
96 | case p: jts.Polygon => if(p.isEmpty) NoResult else PolygonResult(p)
97 | case mp: jts.MultiPoint => PointSetResult(mp)
98 | case ml: jts.MultiLineString => LineSetResult(ml)
99 | case mp: jts.MultiPolygon => PolygonSetResult(mp)
100 | case gc: jts.GeometryCollection => GeometryCollectionResult(gc)
101 | case _ =>
102 | sys.error(s"Unexpected result for PolygonSet intersection: ${geom.getGeometryType}")
103 | }
104 | }
105 |
106 | // Union
107 |
108 | abstract sealed trait PointPointUnionResult
109 | object PointPointUnionResult {
110 | implicit def jtsToResult(geom: jts.Geometry): PointPointUnionResult =
111 | geom match {
112 | case l:jts.Point => PointResult(l)
113 | case gc:jts.MultiPoint => PointSetResult(gc)
114 | case _ =>
115 | sys.error(s"Unexpected result for Point Point union: ${geom.getGeometryType}")
116 | }
117 | }
118 |
119 | abstract sealed trait LinePointUnionResult
120 | object LinePointUnionResult {
121 | implicit def jtsToResult(geom: jts.Geometry): LinePointUnionResult =
122 | geom match {
123 | case l:jts.LineString => LineResult(l)
124 | case gc:jts.GeometryCollection => GeometryCollectionResult(gc)
125 | case _ =>
126 | sys.error(s"Unexpected result for Line Point union: ${geom.getGeometryType}")
127 | }
128 | }
129 |
130 | abstract sealed trait LineLineUnionResult
131 | object LineLineUnionResult {
132 | implicit def jtsToResult(geom: jts.Geometry): LineLineUnionResult =
133 | geom match {
134 | case l:jts.LineString => LineResult(l)
135 | case ml:jts.MultiLineString => LineSetResult(ml)
136 | case _ =>
137 | sys.error(s"Unexpected result for Line Line union: ${geom.getGeometryType}")
138 | }
139 | }
140 |
141 | abstract sealed trait PolygonXUnionResult
142 | object PolygonXUnionResult {
143 | implicit def jtsToResult(geom:jts.Geometry): PolygonXUnionResult =
144 | geom match {
145 | case gc:jts.GeometryCollection => GeometryCollectionResult(gc)
146 | case p:jts.Polygon => PolygonResult(Polygon(p))
147 | case _ =>
148 | sys.error(s"Unexpected result for Polygon union: ${geom.getGeometryType}")
149 | }
150 | }
151 |
152 | abstract sealed trait PolygonPolygonUnionResult
153 | object PolygonPolygonUnionResult {
154 | implicit def jtsToResult(geom:jts.Geometry): PolygonPolygonUnionResult =
155 | geom match {
156 | case p:jts.Polygon => PolygonResult(p)
157 | case mp:jts.MultiPolygon => PolygonSetResult(mp)
158 | case _ =>
159 | sys.error(s"Unexpected result for Polygon-Polygon union: ${geom.getGeometryType}")
160 | }
161 | }
162 |
163 | abstract sealed trait PolygonSetUnionResult
164 | object PolygonSetUnionResult {
165 | implicit def jtsToResult(geom:jts.Geometry): PolygonSetUnionResult =
166 | geom match {
167 | case p:jts.Polygon => PolygonResult(p)
168 | case mp:jts.MultiPolygon => PolygonSetResult(mp)
169 | case gc:jts.GeometryCollection => GeometryCollectionResult(gc)
170 | case _ =>
171 | sys.error(s"Unexpected result for Polygon set union: ${geom.getGeometryType}")
172 | }
173 | }
174 |
175 | // Boundary
176 |
177 | abstract sealed trait LineBoundaryResult
178 | object LineBoundaryResult {
179 | implicit def jtsToResult(geom:jts.Geometry): LineBoundaryResult =
180 | geom match {
181 | case p:jts.Point => PointResult(p)
182 | case mp:jts.MultiPoint => PointSetResult(mp)
183 | case _ => NoResult
184 | }
185 | }
186 |
187 | case object NoResult
188 | extends Result
189 | with PointIntersectionResult
190 | with LineLineIntersectionResult
191 | with PolygonLineIntersectionResult
192 | with PolygonPolygonIntersectionResult
193 | with PointSetIntersectionResult
194 | with LineSetIntersectionResult
195 | with PolygonSetIntersectionResult
196 | with LineBoundaryResult
197 |
198 | case class PointResult(p:Point)
199 | extends Result
200 | with PointIntersectionResult
201 | with LineLineIntersectionResult
202 | with PolygonLineIntersectionResult
203 | with PolygonPolygonIntersectionResult
204 | with PointSetIntersectionResult
205 | with LineSetIntersectionResult
206 | with PolygonSetIntersectionResult
207 | with PointPointUnionResult
208 | with LineBoundaryResult
209 |
210 | case class LineResult(l:Line)
211 | extends Result
212 | with LineLineIntersectionResult
213 | with PolygonLineIntersectionResult
214 | with PolygonPolygonIntersectionResult
215 | with LineSetIntersectionResult
216 | with PolygonSetIntersectionResult
217 | with LinePointUnionResult
218 | with LineLineUnionResult
219 |
220 | case class PolygonResult(p:Polygon)
221 | extends Result
222 | with PolygonPolygonIntersectionResult
223 | with PolygonXUnionResult
224 | with PolygonPolygonUnionResult
225 | with PolygonSetIntersectionResult
226 | with PolygonSetUnionResult
227 |
228 | case class PointSetResult(ls:Set[Point])
229 | extends Result
230 | with PolygonPolygonIntersectionResult
231 | with PointSetIntersectionResult
232 | with LineSetIntersectionResult
233 | with PolygonSetIntersectionResult
234 | with PointPointUnionResult
235 | with LineBoundaryResult
236 |
237 | case class LineSetResult(ls:Set[Line])
238 | extends Result
239 | with PolygonLineIntersectionResult
240 | with PolygonPolygonIntersectionResult
241 | with LineSetIntersectionResult
242 | with PolygonSetIntersectionResult
243 | with LineLineUnionResult
244 |
245 | case class PolygonSetResult(ps:Set[Polygon])
246 | extends Result
247 | with PolygonPolygonIntersectionResult
248 | with PolygonPolygonUnionResult
249 | with PolygonSetIntersectionResult
250 | with PolygonSetUnionResult
251 |
252 | case class GeometryCollectionResult(gc:GeometryCollection)
253 | extends Result
254 | with PolygonPolygonIntersectionResult
255 | with LineSetIntersectionResult
256 | with PolygonSetIntersectionResult
257 | with LinePointUnionResult
258 | with PolygonXUnionResult
259 | with PolygonSetUnionResult
260 |
--------------------------------------------------------------------------------
/core/src/main/scala/jtscala/package.scala:
--------------------------------------------------------------------------------
1 | import com.vividsolutions.jts.{geom=>jts}
2 |
3 | import scala.collection.mutable
4 |
5 | package object jtscala {
6 | implicit def tupleToPoint(t:(Double,Double)):Point =
7 | Point(t._1,t._2)
8 |
9 | implicit def coordinateToPoint(c:jts.Coordinate):Point =
10 | Point(c.x,c.y)
11 |
12 | implicit def tupleSetToPointSet(ts:Set[(Double,Double)]):Set[Point] =
13 | ts map(t => Point(t._1,t._2))
14 |
15 | implicit def tupleListToPointList(tl:List[(Double,Double)]):List[Point] =
16 | tl map(t => Point(t._1,t._2))
17 |
18 | // implicit def tupleArrayToPointList(tl:Array[(Double,Double)]):List[Point] =
19 | // tl map(t => Point(t._1,t._2)) toList
20 |
21 | implicit def pointListToCoordinateArray(ps:List[Point]):Array[jts.Coordinate] =
22 | ps map(p => new jts.Coordinate(p.x,p.y)) toArray
23 |
24 | implicit def multiPointToSetPoint(mp:jts.MultiPoint):Set[Point] = {
25 | val len = mp.getNumGeometries
26 | (for(i <- 0 until len) yield {
27 | Point(mp.getGeometryN(i).asInstanceOf[jts.Point])
28 | }).toSet
29 | }
30 |
31 | implicit def multiLineToSetLine(ml:jts.MultiLineString):Set[Line] = {
32 | val len = ml.getNumGeometries
33 | (for(i <- 0 until len) yield {
34 | Line(ml.getGeometryN(i).asInstanceOf[jts.LineString])
35 | }).toSet
36 | }
37 |
38 | implicit def multiPolygonToSetPolygon(mp:jts.MultiPolygon):Set[Polygon] = {
39 | val len = mp.getNumGeometries
40 | (for(i <- 0 until len) yield {
41 | Polygon(mp.getGeometryN(i).asInstanceOf[jts.Polygon])
42 | }).toSet
43 | }
44 |
45 | implicit def geometryCollectionToSetGeometry(gc:jts.GeometryCollection):Set[Geometry] = {
46 | val len = gc.getNumGeometries
47 | (for(i <- 0 until len) yield {
48 | gc.getGeometryN(i) match {
49 | case p:jts.Point => Set[Geometry](Point(p))
50 | case mp:jts.MultiPoint => multiPointToSetPoint(mp)
51 | case l:jts.LineString => Set[Geometry](Line(l))
52 | case ml:jts.MultiLineString => multiLineToSetLine(ml)
53 | case p:jts.Polygon => Set[Geometry](Polygon(p))
54 | case mp:jts.MultiPolygon => multiPolygonToSetPolygon(mp)
55 | case gc:jts.GeometryCollection => geometryCollectionToSetGeometry(gc)
56 | }
57 | }).toSet.flatten
58 | }
59 |
60 | implicit def seqPointToPointSet(ps:Set[Point]):PointSet = PointSet(ps)
61 | implicit def seqLineToLineSet(ps:Set[Line]):LineSet = LineSet(ps)
62 | implicit def seqPolygonToPolygonSet(ps:Set[Polygon]):PolygonSet = PolygonSet(ps)
63 |
64 | implicit def seqGeometryToGeometryCollection(gs:Set[Geometry]):GeometryCollection = {
65 | val points = mutable.Set[Point]()
66 | val lines = mutable.Set[Line]()
67 | val polygons = mutable.Set[Polygon]()
68 | for(g <- gs) {
69 | g match {
70 | case p:Point => points += p
71 | case l:Line => lines += l
72 | case p:Polygon => polygons += p
73 | case _ => sys.error(s"Unknown Geometry type: $g")
74 | }
75 | }
76 | GeometryCollection(points.toSet,lines.toSet,polygons.toSet)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/Generators.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check
2 |
3 | import jtscala._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 | import Gen._
8 | import Arbitrary._
9 |
10 | object Generators {
11 | lazy val genPoint: Gen[Point] =
12 | for {
13 | x <- choose(-99999999999999999999.0,99999999999999999999.0)
14 | y <- choose(-99999999999999999999.0,99999999999999999999.0)
15 | } yield Point(x, y)
16 |
17 | lazy val genLine:Gen[Line] =
18 | for {
19 | size <-Gen.choose(2,40)
20 | points <- Gen.containerOfN[Set,Point](size,genPoint)
21 | } yield Line(points.toList)
22 |
23 | // Doesn't yet deal with interior rings
24 | lazy val genPolygon:Gen[Polygon] =
25 | for {
26 | size <-Gen.choose(6,50)
27 | shareSize <- Gen.choose(3,size)
28 | subSize1 <- Gen.choose(3,size)
29 | subSize2 <- Gen.choose(3,size)
30 | fullSet <- Gen.containerOfN[Set,Point](size,genPoint)
31 | sharedSet <- Gen.pick(shareSize,fullSet).map(_.toSet)
32 | subSet1 <- Gen.pick(subSize1,fullSet).map(_.toSet)
33 | subSet2 <- Gen.pick(subSize2,fullSet).map(_.toSet)
34 | } yield {
35 | val polyOne = (subSet1 ++ sharedSet).convexHull
36 | val polyTwo = (subSet2 ++ sharedSet).convexHull
37 | polyOne | polyTwo match {
38 | case PolygonResult(p) => p
39 | case _ => sys.error("Should have resulted in a polygon.")
40 | }
41 | }
42 |
43 | implicit lazy val arbPoint: Arbitrary[Point] =
44 | Arbitrary(genPoint)
45 |
46 | implicit lazy val arbLine: Arbitrary[Line] =
47 | Arbitrary(genLine)
48 |
49 | implicit lazy val arbPolygon: Arbitrary[Polygon] =
50 | Arbitrary(genPolygon)
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/Generators.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 | import Gen._
8 | import Arbitrary._
9 |
10 | object Generators {
11 | val factory = new GeometryFactory()
12 |
13 | lazy val genCoordinate: Gen[Coordinate] =
14 | for {
15 | x <- choose(-99999999999999999999.0,99999999999999999999.0)
16 | y <- choose(-99999999999999999999.0,99999999999999999999.0)
17 | } yield new Coordinate(x, y)
18 |
19 | lazy val genShortCoordinates: Gen[Coordinate] =
20 | for {
21 | x <- choose(-1.0,1.0)
22 | y <- choose(-1.0,1.0)
23 | } yield new Coordinate(x, y)
24 |
25 | lazy val genPoint:Gen[Point] =
26 | genCoordinate.map(factory.createPoint(_))
27 |
28 | lazy val genMultiPoint:Gen[MultiPoint] =
29 | for {
30 | size <- Gen.choose(1,100)
31 | coords <- Gen.containerOfN[Set,Coordinate](size,genCoordinate)
32 | } yield { factory.createMultiPoint(coords.toArray) }
33 |
34 | lazy val genLongLineString:Gen[LineString] =
35 | for {
36 | size <-Gen.choose(2,40)
37 | s <- Gen.containerOfN[Set,Coordinate](size,genCoordinate)
38 | } yield { factory.createLineString(s.toArray) }
39 |
40 | lazy val genShortLineString:Gen[LineString] =
41 | for {
42 | size <-Gen.choose(2,40)
43 | s <- Gen.containerOfN[Set,Coordinate](size,genCoordinate)
44 | } yield { factory.createLineString(s.toArray) }
45 |
46 | lazy val genLinearRing:Gen[LinearRing] =
47 | genPolygon.map { p =>
48 | factory.createLinearRing(p.getExteriorRing.getCoordinates)//.asInstanceOf[LinearRing]
49 | }
50 |
51 | lazy val genLineString:Gen[LineString] =
52 | Gen.frequency((1,genLongLineString),(1,genShortLineString),(1,genLinearRing))
53 |
54 | lazy val genMultiLineString:Gen[MultiLineString] =
55 | for {
56 | size <- Gen.choose(1,20)
57 | lineStrings <- Gen.containerOfN[Set,LineString](size,genLineString)
58 | } yield { factory.createMultiLineString(lineStrings.toArray) }
59 |
60 | // Doesn't yet deal with interior rings
61 | lazy val genPolygon:Gen[Polygon] =
62 | for {
63 | size <-Gen.choose(6,50)
64 | shareSize <- Gen.choose(3,size)
65 | subSize1 <- Gen.choose(3,size)
66 | subSize2 <- Gen.choose(3,size)
67 | fullSet <- Gen.containerOfN[Set,Coordinate](size,genCoordinate)
68 | sharedSet <- Gen.pick(shareSize,fullSet)
69 | subSet1 <- Gen.pick(subSize1,fullSet)
70 | subSet2 <- Gen.pick(subSize2,fullSet)
71 | } yield {
72 | val polyOne =
73 | factory.createMultiPoint((subSet1 ++ sharedSet).toArray).convexHull.asInstanceOf[Polygon]
74 | val polyTwo =
75 | factory.createMultiPoint((subSet2 ++ sharedSet).toArray).convexHull.asInstanceOf[Polygon]
76 | polyOne.intersection(polyTwo).asInstanceOf[Polygon]
77 | }
78 |
79 | implicit lazy val arbCoordinate: Arbitrary[Coordinate] =
80 | Arbitrary(genCoordinate)
81 |
82 | implicit lazy val arbPoint: Arbitrary[Point] =
83 | Arbitrary(genPoint)
84 |
85 | implicit lazy val arbMultiPoint: Arbitrary[MultiPoint] =
86 | Arbitrary(genMultiPoint)
87 |
88 | implicit lazy val arbLineString: Arbitrary[LineString] =
89 | Arbitrary(genLineString)
90 |
91 | implicit lazy val arbMultiLineString: Arbitrary[MultiLineString] =
92 | Arbitrary(genMultiLineString)
93 |
94 | implicit lazy val arbPolygon: Arbitrary[Polygon] =
95 | Arbitrary(genPolygon)
96 |
97 | // MultiPoint with a set of lines arbitrarily made up of the points
98 | // of the MultiPoint
99 | case class LineInMultiPoint(mp:MultiPoint,ls:LineString)
100 | lazy val genLineInMultiPoint:Gen[LineInMultiPoint] =
101 | for {
102 | size <- Gen.choose(2,100)
103 | lineSize <- Gen.choose(2,size)
104 | coords <- Gen.containerOfN[Set,Coordinate](size,genCoordinate)
105 | lineCoords <- Gen.pick(lineSize,coords)
106 | } yield {
107 | val mp = factory.createMultiPoint(coords.toArray)
108 | val l = factory.createLineString(lineCoords.toArray)
109 | LineInMultiPoint(mp,l)
110 | }
111 |
112 | implicit lazy val arbLineInMultiPoint:Arbitrary[LineInMultiPoint] =
113 | Arbitrary(genLineInMultiPoint)
114 |
115 | case class ClosedLineString(ls:LineString)
116 | lazy val genClosedLineString:Gen[ClosedLineString] =
117 | Gen.frequency((1,genLongLineString),(1,genShortLineString))
118 | .map { l =>
119 | val coords = l.getCoordinates
120 | ClosedLineString(factory.createLineString((coords(coords.length-1) ::coords.toList).toArray))
121 | }
122 |
123 | implicit lazy val arbClosedRing:Arbitrary[ClosedLineString] =
124 | Arbitrary(genClosedLineString)
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/LineStringCheck.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 |
8 | object LineStringCheck extends Properties("Line") {
9 | import Generators._
10 |
11 | // SLOW!
12 | // property("buffer => Polygon") =
13 | // forAll { (l:LineString,d:Double) =>
14 | // l.buffer(d) match {
15 | // case _:Polygon => true
16 | // case x =>
17 | // println(s"FAILED WITH $x")
18 | // false
19 | // }
20 | // }
21 |
22 | property("difference[self]") = forAll { (l:LineString) =>
23 | l.difference(l).isEmpty
24 | }
25 |
26 | property("difference[self] => Empty") =
27 | forAll { (l:LineString) =>
28 | l.difference(l).isEmpty
29 | }
30 |
31 | property("difference[point] => (MultiLineString,LineString)") =
32 | forAll { (l:LineString,p:Point) =>
33 | l.difference(p) match {
34 | case _:MultiLineString => true
35 | case _:LineString => true
36 | case x =>
37 | println(s"FAILED WITH $x")
38 | false
39 | }
40 | }
41 |
42 | property("difference[other line] => (MultiLineString,LineString)") =
43 | forAll { (l:LineString,l2:LineString) =>
44 | l.difference(l2) match {
45 | case _:MultiLineString => true
46 | case _:LineString => true
47 | case x =>
48 | println(s"FAILED WITH $x")
49 | false
50 | }
51 | }
52 |
53 | property("difference[polygon] => (MultiLineString,LineString,Empty)") =
54 | forAll { (l:LineString,p:Polygon) =>
55 | l.difference(p) match {
56 | case _:MultiLineString => true
57 | case _:LineString => true
58 | case x =>
59 | if(x.isEmpty) {
60 | p.contains(l)
61 | } else {
62 | println(s"FAILED WITH $x")
63 | false
64 | }
65 | }
66 | }
67 |
68 | property("intersection[point] => Point") =
69 | forAll { (l:LineString,p:Point) =>
70 | l.intersection(p) match {
71 | case _:Point => true
72 | case x =>
73 | if(x.isEmpty) {
74 | l.disjoint(p)
75 | } else {
76 | println(s"FAILED WITH $x")
77 | false
78 | }
79 | }
80 | }
81 |
82 | property("intersection[line] => (Point,LineString)") =
83 | forAll { (l:LineString,p:Point) =>
84 | l.intersection(p) match {
85 | case _:Point => true
86 | case _:LineString => true
87 | case x =>
88 | if(x.isEmpty) {
89 | l.disjoint(p)
90 | } else {
91 | println(s"FAILED WITH $x")
92 | false
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/MultiLineStringCheck.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 | import Arbitrary._
8 |
9 | import java.lang.System.currentTimeMillis
10 | import scala.collection.mutable
11 |
12 | object MultiLineStringCheck extends Properties("MultiLineString") {
13 | import Generators._
14 |
15 | // property("buffer => EMPTY") =
16 | // forAll { (mp: MultiLineString) =>
17 | // mp.buffer(1.0).isEmpty
18 | // }
19 |
20 | property("intersection[point] => (Point)") =
21 | forAll { (ml: MultiLineString,p:Point) =>
22 | ml.intersection(p) match {
23 | case _:Point => true
24 | case x =>
25 | println(s"FAILED WITH $x")
26 | false
27 | }
28 | }
29 |
30 | property("intersection[line] => (Point,LineString,MultiLineString,GeometryCollection)") =
31 | forAll { (ml: MultiLineString,l: LineString) =>
32 | ml.intersection(l) match {
33 | case p: Point => !p.isEmpty
34 | case l: LineString => if(l.isEmpty) !ml.intersects(l) else true
35 | case mp: MultiPoint => !mp.isEmpty
36 | case ml: MultiLineString => !ml.isEmpty
37 | case x =>
38 | println(s"FAILED WITH $x")
39 | false
40 | }
41 | }
42 |
43 | // property("intersection[lineOfPoints] => (MultiLineString)") = forAll { (limp: LineInMultiLineString) =>
44 | // val LineInMultiLineString(mp,l) = limp
45 | // mp.intersection(l) match {
46 | // case _:MultiLineString => true
47 | // case x =>
48 | // println(s"FAILED WITH $x")
49 | // false
50 | // }
51 | // }
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/MultiPointCheck.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 | import Arbitrary._
8 |
9 | object MultiPointCheck extends Properties("MultiPoint") {
10 | import Generators._
11 |
12 | property("buffer => EMPTY") =
13 | forAll { (mp: MultiPoint) =>
14 | mp.buffer(1.0).isEmpty
15 | }
16 |
17 | property("intersection[line] => (Point,MultiPoint)") =
18 | forAll { (mp: MultiPoint,l:LineString) =>
19 | mp.intersection(l) match {
20 | case _:Point => true
21 | case _:MultiPoint => true
22 | case x =>
23 | println(s"FAILED WITH $x")
24 | false
25 | }
26 | }
27 |
28 | property("intersection[lineOfPoints] => (MultiPoint)") = forAll { (limp: LineInMultiPoint) =>
29 | val LineInMultiPoint(mp,l) = limp
30 | mp.intersection(l) match {
31 | case _:MultiPoint => true
32 | case x =>
33 | println(s"FAILED WITH $x")
34 | false
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/PointCheck.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 |
8 | object PointCheck extends Properties("Point") {
9 | import Generators._
10 |
11 | property("getEnvelope") = forAll { (p: Point) =>
12 | p.getEnvelope match {
13 | case x:Point => true
14 | case _ => false
15 | }
16 | }
17 |
18 | property("within[itself]") = forAll { (p: Point) =>
19 | p.within(p)
20 | }
21 |
22 | property("contains[itself]") = forAll { (p: Point) =>
23 | p.contains(p)
24 | }
25 |
26 | property("buffer") = forAll { (p: Point, d: Double) =>
27 | p.buffer(d) match {
28 | case x:Polygon => true
29 | case _ => false
30 | }
31 | }
32 |
33 | property("convexHull") = forAll { (p: Point) =>
34 | p.convexHull match {
35 | case x:Point => true
36 | case _ => false
37 | }
38 | }
39 |
40 | property("covers[itself]") = forAll { (p: Point) =>
41 | p.covers(p)
42 | }
43 |
44 | property("covers[others]") = forAll { (p1: Point,p2: Point) =>
45 | !p1.covers(p2) || (p1 == p2)
46 | }
47 |
48 | property("getInteriorPoint") = forAll { (p:Point) =>
49 | p.getInteriorPoint == p
50 | }
51 |
52 | property("getDimension") = forAll { (p:Point) =>
53 | p.getDimension == 0
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/check/jts/PolygonCheck.scala:
--------------------------------------------------------------------------------
1 | package jtscala.check.jts
2 |
3 | import com.vividsolutions.jts.geom._
4 |
5 | import org.scalacheck._
6 | import Prop._
7 |
8 | object PolygonCheck extends Properties("Polygon") {
9 | import Generators._
10 |
11 | property("union[polygon] => (Polygon,Multipolygon)") = forAll { (p1:Polygon,p2:Polygon) =>
12 | p1.union(p2) match {
13 | case _:MultiPolygon => true
14 | case _:Polygon => true
15 | case x =>
16 | println(s"FAILED WITH $x")
17 | false
18 | }
19 | }
20 |
21 | property("union[line] => (Polygon,GeometryCollection)") = forAll { (p:Polygon,l:LineString) =>
22 | p.union(l) match {
23 | case _:GeometryCollection => true
24 | case _:Polygon => true
25 | case x =>
26 | println(s"FAILED WITH $x")
27 | false
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/spec/LineSpec.scala:
--------------------------------------------------------------------------------
1 | package jtscala.spec
2 |
3 | import jtscala._
4 |
5 | import com.vividsolutions.jts.{geom=>jts}
6 |
7 | import org.scalatest.FunSpec
8 | import org.scalatest.matchers._
9 |
10 | class LineSpec extends FunSpec with ShouldMatchers {
11 | describe("Line") {
12 | it("should be a closed Line if constructed with l(0) == l(-1)") {
13 | val l = Line(List[(Double,Double)]((0,0),(1,0),(1,1),(0,1),(0,0)))
14 | l.isClosed should be (true)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/spec/PointSpec.scala:
--------------------------------------------------------------------------------
1 | package jtscala.spec
2 |
3 | import jtscala._
4 |
5 | import org.scalatest.FunSpec
6 | import org.scalatest.matchers._
7 |
8 | class PointSpec extends FunSpec with ShouldMatchers {
9 | describe("Point") {
10 | it("should return true for comparing points with equal x and y") {
11 | val x = 123.321
12 | val y = -0.4343434
13 | Point(x,y) should be (Point(x,y))
14 | }
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/core/src/test/scala/jtscala/spec/PolygonSpec.scala:
--------------------------------------------------------------------------------
1 | package jtscala.spec
2 |
3 | import jtscala._
4 |
5 | import com.vividsolutions.jts.{geom=>jts}
6 |
7 | import org.scalatest.FunSpec
8 | import org.scalatest.matchers._
9 |
10 | class PolygonSpec extends FunSpec with ShouldMatchers {
11 | describe("Polygon") {
12 | it("should be a closed Polygon if constructed with l(0) == l(-1)") {
13 | val p = Polygon(Line(List[(Double,Double)]((0,0),(1,0),(1,1),(0,1),(0,0))))
14 | p.exterior.isClosed should be (true)
15 | }
16 |
17 | it("should throw if attempt to construct with unclosed line") {
18 | intercept[Exception] {
19 | val p = Polygon(Line(List[(Double,Double)]((0,0),(1,0),(1,1),(0,1))))
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/project/Build.scala:
--------------------------------------------------------------------------------
1 | import sbt._
2 | import sbt.Keys._
3 |
4 | object JTScalaBuild extends Build {
5 |
6 | // Default settings
7 | override lazy val settings = super.settings ++
8 | Seq(
9 | version := "0.1.0-SNAPSHOT",
10 | scalaVersion := "2.10.3",
11 | organization := "com.azavea.geotrellis",
12 |
13 | // disable annoying warnings about 2.10.x
14 | conflictWarning in ThisBuild := ConflictWarning.disable,
15 | scalacOptions ++=
16 | Seq("-deprecation",
17 | "-unchecked",
18 | "-Yclosure-elim",
19 | "-Yinline-warnings",
20 | "-optimize",
21 | "-language:implicitConversions",
22 | "-language:postfixOps",
23 | "-language:existentials",
24 | "-feature"),
25 |
26 | publishMavenStyle := true,
27 |
28 | publishTo <<= version { (v: String) =>
29 | val nexus = "https://oss.sonatype.org/"
30 | if (v.trim.endsWith("SNAPSHOT"))
31 | Some("snapshots" at nexus + "content/repositories/snapshots")
32 | else
33 | Some("releases" at nexus + "service/local/staging/deploy/maven2")
34 | },
35 |
36 | publishArtifact in Test := false,
37 |
38 | pomIncludeRepository := { _ => false },
39 | licenses := Seq("Apache 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.html")),
40 | homepage := Some(url("http://geotrellis.github.io/")),
41 |
42 | pomExtra := (
43 |
44 |
45 | git@github.com:geotrellis/geotrellis.git
46 | scm:git:git@github.com:geotrellis/geotrellis.git
47 |
48 |
49 |
50 | lossyrob
51 | Rob Emanuele
52 | http://github.com/lossyrob/
53 |
54 |
55 | )
56 | )
57 |
58 | // Project: jtscala
59 |
60 | lazy val jtscala =
61 | Project("jtscala", file("core"))
62 | .settings(jtscalaSettings:_*)
63 |
64 | lazy val jtscalaSettings =
65 | Seq(
66 | name := "jtscala",
67 | libraryDependencies ++= Seq(
68 | "org.scalatest" % "scalatest_2.10" % "2.0.M5b" % "test",
69 | "org.scalacheck" %% "scalacheck" % "1.11.1" % "test",
70 | "com.vividsolutions" % "jts" % "1.13"
71 | )
72 | )
73 |
74 | // Project: benchmark
75 |
76 | lazy val jtscala_benchmark =
77 | Project("benchmark", file("benchmark"))
78 | .settings(jtscalaBenchmarkSettings:_*)
79 | .dependsOn(jtscala % "compile->test")
80 |
81 | lazy val jtscalaBenchmarkSettings =
82 | Seq(
83 | name := "jtscala-benchmark",
84 | libraryDependencies ++= Seq(
85 | "org.scalatest" % "scalatest_2.10" % "2.0.M5b" % "test",
86 | "org.scalacheck" %% "scalacheck" % "1.11.1" % "test",
87 | "com.vividsolutions" % "jts" % "1.13"
88 | )
89 | )
90 | }
91 |
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=0.12.0
--------------------------------------------------------------------------------
/sbt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # A more capable sbt runner, coincidentally also called sbt.
4 | # Author: Paul Phillips
5 |
6 | # todo - make this dynamic
7 | declare -r sbt_release_version=0.13.0
8 |
9 | declare sbt_jar sbt_dir sbt_create sbt_launch_dir
10 | declare scala_version java_home sbt_explicit_version
11 | declare verbose debug quiet noshare batch trace_level log_level
12 | declare sbt_saved_stty
13 |
14 | echoerr () { [[ -z $quiet ]] && echo "$@" >&2; }
15 | vlog () { [[ -n "$verbose$debug" ]] && echoerr "$@"; }
16 | dlog () { [[ -n $debug ]] && echoerr "$@"; }
17 |
18 | # we'd like these set before we get around to properly processing arguments
19 | for arg in "$@"; do
20 | case $arg in
21 | -q|-quiet) quiet=true ;;
22 | -d|-debug) debug=true ;;
23 | -v|-verbose) verbose=true ;;
24 | *) ;;
25 | esac
26 | done
27 |
28 | build_props_sbt () {
29 | if [[ -r project/build.properties ]]; then
30 | versionLine=$(grep ^sbt.version project/build.properties | tr -d ' \r')
31 | versionString=${versionLine##sbt.version=}
32 | echo "$versionString"
33 | fi
34 | }
35 |
36 | update_build_props_sbt () {
37 | local ver="$1"
38 | local old=$(build_props_sbt)
39 |
40 | if [[ $ver == $old ]]; then
41 | return
42 | elif [[ -r project/build.properties ]]; then
43 | perl -pi -e "s/^sbt\.version[ ]*=.*\$/sbt.version=${ver}/" project/build.properties
44 | grep -q '^sbt.version[ ]*=' project/build.properties || printf "\nsbt.version=${ver}\n" >> project/build.properties
45 |
46 | echoerr !!!
47 | echoerr !!! Updated file project/build.properties setting sbt.version to: $ver
48 | echoerr !!! Previous value was: $old
49 | echoerr !!!
50 | fi
51 | }
52 |
53 | sbt_version () {
54 | if [[ -n $sbt_explicit_version ]]; then
55 | echo $sbt_explicit_version
56 | else
57 | local v=$(build_props_sbt)
58 | if [[ -n $v ]]; then
59 | echo $v
60 | else
61 | echo $sbt_release_version
62 | fi
63 | fi
64 | }
65 |
66 | # restore stty settings (echo in particular)
67 | onSbtRunnerExit() {
68 | [[ -n $sbt_saved_stty ]] || return
69 | dlog ""
70 | dlog "restoring stty: $sbt_saved_stty"
71 | stty $sbt_saved_stty
72 | unset sbt_saved_stty
73 | }
74 |
75 | # save stty and trap exit, to ensure echo is reenabled if we are interrupted.
76 | trap onSbtRunnerExit EXIT
77 | sbt_saved_stty=$(stty -g 2>/dev/null)
78 | dlog "Saved stty: $sbt_saved_stty"
79 |
80 | # this seems to cover the bases on OSX, and someone will
81 | # have to tell me about the others.
82 | get_script_path () {
83 | local path="$1"
84 | [[ -L "$path" ]] || { echo "$path" ; return; }
85 |
86 | local target=$(readlink "$path")
87 | if [[ "${target:0:1}" == "/" ]]; then
88 | echo "$target"
89 | else
90 | echo "$(dirname $path)/$target"
91 | fi
92 | }
93 |
94 | die() {
95 | echo "Aborting: $@"
96 | exit 1
97 | }
98 |
99 | make_url () {
100 | version="$1"
101 |
102 | echo "$sbt_launch_repo/org.scala-sbt/sbt-launch/$version/sbt-launch.jar"
103 | }
104 |
105 | readarr () {
106 | while read ; do
107 | eval "$1+=(\"$REPLY\")"
108 | done
109 | }
110 |
111 | init_default_option_file () {
112 | local overriding_var=${!1}
113 | local default_file=$2
114 | if [[ ! -r "$default_file" && $overriding_var =~ ^@(.*)$ ]]; then
115 | local envvar_file=${BASH_REMATCH[1]}
116 | if [[ -r $envvar_file ]]; then
117 | default_file=$envvar_file
118 | fi
119 | fi
120 | echo $default_file
121 | }
122 |
123 | declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
124 | declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation"
125 | declare -r default_jvm_opts="-Dfile.encoding=UTF8 -XX:MaxPermSize=384m -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
126 | declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
127 | declare -r latest_28="2.8.2"
128 | declare -r latest_29="2.9.3"
129 | declare -r latest_210="2.10.3"
130 | declare -r latest_211="2.11.0-M5"
131 |
132 | declare -r script_path=$(get_script_path "$BASH_SOURCE")
133 | declare -r script_dir="$(dirname $script_path)"
134 | declare -r script_name="$(basename $script_path)"
135 |
136 | # some non-read-onlies set with defaults
137 | declare java_cmd=java
138 | declare sbt_opts_file=$(init_default_option_file SBT_OPTS .sbtopts)
139 | declare jvm_opts_file=$(init_default_option_file JVM_OPTS .jvmopts)
140 | declare sbt_launch_repo="http://typesafe.artifactoryonline.com/typesafe/ivy-releases"
141 |
142 | # pull -J and -D options to give to java.
143 | declare -a residual_args
144 | declare -a java_args
145 | declare -a scalac_args
146 | declare -a sbt_commands
147 |
148 | # args to jvm/sbt via files or environment variables
149 | declare -a extra_jvm_opts extra_sbt_opts
150 |
151 | # if set, use JAVA_HOME over java found in path
152 | [[ -e "$JAVA_HOME/bin/java" ]] && java_cmd="$JAVA_HOME/bin/java"
153 |
154 | # directory to store sbt launchers
155 | declare sbt_launch_dir="$HOME/.sbt/launchers"
156 | [[ -d "$sbt_launch_dir" ]] || mkdir -p "$sbt_launch_dir"
157 | [[ -w "$sbt_launch_dir" ]] || sbt_launch_dir="$(mktemp -d -t sbt_extras_launchers)"
158 |
159 | build_props_scala () {
160 | if [[ -r project/build.properties ]]; then
161 | versionLine=$(grep ^build.scala.versions project/build.properties)
162 | versionString=${versionLine##build.scala.versions=}
163 | echo ${versionString%% .*}
164 | fi
165 | }
166 |
167 | execRunner () {
168 | # print the arguments one to a line, quoting any containing spaces
169 | [[ $verbose || $debug ]] && echo "# Executing command line:" && {
170 | for arg; do
171 | if [[ -n "$arg" ]]; then
172 | if printf "%s\n" "$arg" | grep -q ' '; then
173 | printf "\"%s\"\n" "$arg"
174 | else
175 | printf "%s\n" "$arg"
176 | fi
177 | fi
178 | done
179 | echo ""
180 | }
181 |
182 | if [[ -n $batch ]]; then
183 | exec /dev/null; then
212 | curl --fail --silent "$url" --output "$jar"
213 | elif which wget >/dev/null; then
214 | wget --quiet -O "$jar" "$url"
215 | fi
216 | } && [[ -r "$jar" ]]
217 | }
218 |
219 | acquire_sbt_jar () {
220 | for_sbt_version="$(sbt_version)"
221 | sbt_url="$(jar_url $for_sbt_version)"
222 | sbt_jar="$(jar_file $for_sbt_version)"
223 |
224 | [[ -r "$sbt_jar" ]] || download_url "$sbt_url" "$sbt_jar"
225 | }
226 |
227 | usage () {
228 | cat < display stack traces with a max of frames (default: -1, traces suppressed)
236 | -no-colors disable ANSI color codes
237 | -sbt-create start sbt even if current directory contains no sbt project
238 | -sbt-dir path to global settings/plugins directory (default: ~/.sbt/)
239 | -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+)
240 | -ivy path to local Ivy repository (default: ~/.ivy2)
241 | -no-share use all local caches; no sharing
242 | -offline put sbt in offline mode
243 | -jvm-debug Turn on JVM debugging, open at the given port.
244 | -batch Disable interactive mode
245 | -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted
246 |
247 | # sbt version (default: from project/build.properties if present, else latest release)
248 | !!! The only way to accomplish this pre-0.12.0 if there is a build.properties file which
249 | !!! contains an sbt.version property is to update the file on disk. That's what this does.
250 | -sbt-version use the specified version of sbt (default: $sbt_release_version)
251 | -sbt-jar use the specified jar as the sbt launcher
252 | -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir)
253 | -sbt-launch-repo repo url for downloading sbt launcher jar (default: $sbt_launch_repo)
254 |
255 | # scala version (default: as chosen by sbt)
256 | -28 use $latest_28
257 | -29 use $latest_29
258 | -210 use $latest_210
259 | -211 use $latest_211
260 | -scala-home use the scala build at the specified directory
261 | -scala-version use the specified version of scala
262 | -binary-version use the specified scala version when searching for dependencies
263 |
264 | # java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
265 | -java-home alternate JAVA_HOME
266 |
267 | # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution
268 | # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found
269 | $default_jvm_opts
270 | JVM_OPTS environment variable holding either the jvm args directly, or
271 | the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts')
272 | Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument.
273 | -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present)
274 | -Dkey=val pass -Dkey=val directly to the jvm
275 | -J-X pass option -X directly to the jvm (-J is stripped)
276 |
277 | # passing options to sbt, OR to this runner
278 | SBT_OPTS environment variable holding either the sbt args directly, or
279 | the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts')
280 | Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument.
281 | -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present)
282 | -S-X add -X to sbt's scalacOptions (-S is stripped)
283 | EOM
284 | }
285 |
286 | addJava () {
287 | dlog "[addJava] arg = '$1'"
288 | java_args=( "${java_args[@]}" "$1" )
289 | }
290 | addSbt () {
291 | dlog "[addSbt] arg = '$1'"
292 | sbt_commands=( "${sbt_commands[@]}" "$1" )
293 | }
294 | addScalac () {
295 | dlog "[addScalac] arg = '$1'"
296 | scalac_args=( "${scalac_args[@]}" "$1" )
297 | }
298 | addResidual () {
299 | dlog "[residual] arg = '$1'"
300 | residual_args=( "${residual_args[@]}" "$1" )
301 | }
302 | addResolver () {
303 | addSbt "set resolvers += $1"
304 | }
305 | addDebugger () {
306 | addJava "-Xdebug"
307 | addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"
308 | }
309 | setScalaVersion () {
310 | [[ "$1" == *-SNAPSHOT ]] && addResolver 'Resolver.sonatypeRepo("snapshots")'
311 | addSbt "++ $1"
312 | }
313 |
314 | process_args ()
315 | {
316 | require_arg () {
317 | local type="$1"
318 | local opt="$2"
319 | local arg="$3"
320 |
321 | if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
322 | die "$opt requires <$type> argument"
323 | fi
324 | }
325 | while [[ $# -gt 0 ]]; do
326 | case "$1" in
327 | -h|-help) usage; exit 1 ;;
328 | -v|-verbose) verbose=true && log_level=Info && shift ;;
329 | -d|-debug) debug=true && log_level=Debug && shift ;;
330 | -q|-quiet) quiet=true && log_level=Error && shift ;;
331 |
332 | -trace) require_arg integer "$1" "$2" && trace_level=$2 && shift 2 ;;
333 | -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;;
334 | -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;;
335 | -no-share) noshare=true && shift ;;
336 | -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;;
337 | -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;;
338 | -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;;
339 | -offline) addSbt "set offline := true" && shift ;;
340 | -jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;;
341 | -batch) batch=true && shift ;;
342 | -prompt) require_arg "expr" "$1" "$2" && addSbt "set shellPrompt in ThisBuild := (s => { val e = Project.extract(s) ; $2 })" && shift 2 ;;
343 |
344 | -sbt-create) sbt_create=true && shift ;;
345 | -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;;
346 | -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;;
347 | -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;;
348 | -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;;
349 | -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;;
350 | -binary-version) require_arg version "$1" "$2" && addSbt "set scalaBinaryVersion in ThisBuild := \"$2\"" && shift 2 ;;
351 | -scala-home) require_arg path "$1" "$2" && addSbt "set every scalaHome := Some(file(\"$2\"))" && shift 2 ;;
352 | -java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;;
353 | -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;;
354 | -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;;
355 |
356 | -D*) addJava "$1" && shift ;;
357 | -J*) addJava "${1:2}" && shift ;;
358 | -S*) addScalac "${1:2}" && shift ;;
359 | -28) setScalaVersion $latest_28 && shift ;;
360 | -29) setScalaVersion $latest_29 && shift ;;
361 | -210) setScalaVersion $latest_210 && shift ;;
362 | -211) setScalaVersion $latest_211 && shift ;;
363 |
364 | *) addResidual "$1" && shift ;;
365 | esac
366 | done
367 | }
368 |
369 | # process the direct command line arguments
370 | process_args "$@"
371 |
372 | # skip #-styled comments
373 | readConfigFile() {
374 | while read line; do echo ${line/\#*/} | grep -vE '^\s*$'; done < $1
375 | }
376 |
377 | # if there are file/environment sbt_opts, process again so we
378 | # can supply args to this runner
379 | if [[ -r "$sbt_opts_file" ]]; then
380 | vlog "Using sbt options defined in file $sbt_opts_file"
381 | readarr extra_sbt_opts < <(readConfigFile "$sbt_opts_file")
382 | elif [[ -n "$SBT_OPTS" && !($SBT_OPTS =~ ^@.*) ]]; then
383 | vlog "Using sbt options defined in variable \$SBT_OPTS"
384 | extra_sbt_opts=( $SBT_OPTS )
385 | else
386 | vlog "No extra sbt options have been defined"
387 | fi
388 |
389 | [[ -n $extra_sbt_opts ]] && process_args "${extra_sbt_opts[@]}"
390 |
391 | # reset "$@" to the residual args
392 | set -- "${residual_args[@]}"
393 | argumentCount=$#
394 |
395 | # only exists in 0.12+
396 | setTraceLevel() {
397 | case $(sbt_version) in
398 | 0.{7,10,11}.*) echoerr "Cannot set trace level in sbt version $(sbt_version)" ;;
399 | *) addSbt "set every traceLevel := $trace_level" ;;
400 | esac
401 | }
402 |
403 | # set scalacOptions if we were given any -S opts
404 | [[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[@]}\""
405 |
406 | # Update build.properties on disk to set explicit version - sbt gives us no choice
407 | [[ -n "$sbt_explicit_version" ]] && update_build_props_sbt "$sbt_explicit_version"
408 | vlog "Detected sbt version $(sbt_version)"
409 |
410 | [[ -n "$scala_version" ]] && echoerr "Overriding scala version to $scala_version"
411 |
412 | # no args - alert them there's stuff in here
413 | (( $argumentCount > 0 )) || {
414 | vlog "Starting $script_name: invoke with -help for other options"
415 | residual_args=( shell )
416 | }
417 |
418 | # verify this is an sbt dir or -create was given
419 | [[ -r ./build.sbt || -d ./project || -n "$sbt_create" ]] || {
420 | cat <