Skip to content
This repository
Browse code

first working version

  • Loading branch information...
commit 05e55f08f387ef10616e1e4011a25c34dcc3ada5 1 parent 46b0f4c
Stanisław Wasiutyński authored
24 src/Circle.scala
... ... @@ -0,0 +1,24 @@
  1 +import com.seisw.util.geom.PolySimple
  2 +
  3 +class Circle(x1: Double, y1: Double, z1: Int, r1: Double) {
  4 +
  5 + val z = if(z1 < 1) 1 else if(z1 > 100) 100 else z1
  6 + val x = x1
  7 + val y = y1
  8 + val r = r1
  9 +
  10 + // Converts circle to a polygon
  11 + def toPoly: PolySimple = {
  12 +
  13 + val count = 50
  14 + val result = new PolySimple
  15 + val step = 2 * Math.Pi / count
  16 +
  17 + for(i <- 1 to count){
  18 + val y1 = y + r * Math.cos(step*i)
  19 + val x1 = x + r * Math.sin(step*i)
  20 + result.add(x1, y1)
  21 + }
  22 + result
  23 + }
  24 +}
55 src/Geo.scala
... ... @@ -0,0 +1,55 @@
  1 +class Geo(n:Double, e:Double, s:Double, w:Double, points: List[Point]) {
  2 +
  3 + // Avg. speed in km/h
  4 + val speed: Int = 4
  5 + // Time limit in hours
  6 + val limit: Float = 0.25f
  7 + // Distance in kilometers
  8 + val dist: Float = speed * limit
  9 +
  10 + // Sector width in km
  11 + val width: Double = length((n+s)/2, w, (n+s)/2, e) + 2*dist
  12 + // Sector height in km
  13 + val height: Double = length(n, w, s, w) + 2*dist
  14 +
  15 + // Image width in pixels
  16 + val image_width: Int = 1000
  17 + // Image height in pixels
  18 + val image_height: Int = (width / height * image_width).toInt
  19 +
  20 + val w_factor = (e - w) / width
  21 + val h_factor = (n - s) / height
  22 + println((e + w_factor*dist/2) +","+ (n ) +"), new GLatLng("+ (w + w_factor*dist/2) +","+ (s))
  23 + // pixels in km
  24 + val factor: Double = image_width / width
  25 +
  26 + var circles: List[Circle] = points.map{ pkt =>
  27 + new Circle( distance_to(pkt.lng, e) + dist, distance_to(s, pkt.lat) + dist, pkt.mag, dist)
  28 + }
  29 +
  30 + // Distance to given point in km
  31 + def distance_to(lng:Double, lat:Double): Double = {
  32 + length(s, e, lng, lat)
  33 + }
  34 +
  35 + // Returns: "x, y, width, height"
  36 + def viewbox: String = {
  37 + 0 + ", " + 0 + ", " + height + ", " + width
  38 + }
  39 +
  40 + // Returns length in kilometers from and to given points
  41 + // Takes two points
  42 + private def length(p1_lng: Double, p1_lat: Double, p2_lng: Double, p2_lat: Double): Double = {
  43 + val r = 6371
  44 + val to_rad = 3.142 / 180
  45 +
  46 + val d_lat = (p2_lat - p1_lat) * to_rad
  47 + val d_lng = (p2_lng - p1_lng) * to_rad
  48 +
  49 + val a = Math.sin(d_lat / 2) * Math.sin(d_lat / 2) +
  50 + Math.cos(p1_lat * to_rad) * Math.cos(p2_lat * to_rad) *
  51 + Math.sin(d_lng / 2) * Math.sin(d_lng / 2)
  52 + val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  53 + r * c
  54 + }
  55 +}
183 src/HeatMap.scala
... ... @@ -1,126 +1,103 @@
1   -import java.awt.Color
2 1 import scala.io.Source
3   -import scala.xml.XML._
4 2 import scala.xml.NodeBuffer
5   -import scala.xml.dtd.{DocType, PublicID}
  3 +import com.seisw.util.geom.{Poly, PolyDefault}
6 4
7   -object HeatMap {
  5 +class HeatMap(source: Source) {
8 6
9   - // Image width in pixels
10   - val width: Int = 1000
11   - // Avg. speed
12   - val speed: Int = 5
13   - // Time limit in hours
14   - val limit: Float = 0.25f
15   - // Distance in kilometers
16   - val dist: Float = speed * limit
  7 + // Convert numbers from source to List (of List of 3 params: x, y, z)
  8 + val data: List[Point] = List.fromString(source.mkString, '\n').map{line =>
  9 + val args:List[Float] = List.fromString(line, ' ').map(_.toFloat)
  10 + new Point(args(0), args(1), args(2).toInt)
  11 + }
17 12
18   - // Zamienia liczbę z przedziału 0-100 na odpowiadający mu kolor w zefiniowanym gardiencie
19   - def color(percent: Int): Color = {
  13 + // Find min and max value of latitude and longitude
  14 + val lats: List[Float] = data.map( row => row.lat)
  15 + val w: Float = lats.reduceLeft(Math.min(_,_))
  16 + val e: Float = lats.reduceLeft(Math.max(_,_))
  17 +
  18 + val lngs: List[Float] = data.map( row => row.lng)
  19 + val s: Float = lngs.reduceLeft(Math.min(_,_))
  20 + val n: Float = lngs.reduceLeft(Math.max(_,_))
  21 +
  22 + // Object which represents given Earth sector as rectangle
  23 + val geo = new Geo(n, e, s, w, data)
  24 +
  25 + // Zamienia liczbę z przedziału 0-100 na odpowiadający mu kolor w zefiniowanym gradiencie
  26 + def color(percent: Int): String = {
20 27
  28 + val str = "%02X%02X%02X"
21 29 val decr: Double = if(percent % 33 == 0) 1 else percent % 33 / 33.0
22 30 val incr: Double = 1 - decr
23 31
24 32 percent match {
25   - case x if 0 to 33 contains x =>
26   - new Color(0, (255*decr).toInt, (255).toInt)
  33 + case 0 =>
  34 + str.format(255, 0, 0)
  35 + case x if 1 to 33 contains x =>
  36 + str.format(255, (255*decr).toInt, 0)
27 37 case x if 34 to 66 contains x =>
28   - new Color((255*decr).toInt, (255).toInt, (255*incr).toInt)
  38 + str.format((255*incr).toInt, (255).toInt, (255*decr).toInt)
29 39 case x if 67 to 99 contains x =>
30   - new Color(255, (255*incr).toInt, 0)
31   - case 100 =>
32   - new Color(255, 0, 0)
  40 + str.format(0, (255*incr).toInt, (255).toInt)
33 41 case _ =>
34   - new Color(0, 0, 255)
  42 + str.format(0, 0, 255)
35 43 }
36 44 }
37   -
38   - def main(args: Array[String]) {
39   -
40   - // Read file with initial data
41   - val source = Source.fromFile("../data/AWF.input")
42   -
43   - // Convert numbers from file to List (of List of 3 params: x, y, z)
44   - val array: List[List[Float]] = List.fromString(source.mkString, '\n').map(List.fromString(_, ' ').map(_.toFloat))
45   -
46   - // Wspólna wielkość dla wszystkich elips
47   -// val map: Element = document.createElement("map")
48   -// map.setAttribute("rx", (geo.longitude_to_pixels(dist)/2).toString)
49   -// map.setAttribute("ry", (geo.latitude_to_pixels(dist)/2).toString)
50   -// root.appendChild(map)
51   -
52   -
53   - // Declare the doctype of XML document
54   - val doctype = DocType("svg", PublicID("-//W3C//DTD SVG 1.0//EN", "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"), Nil)
55 45
56   - // Create root node
57   - val root = <svg>{ list(array) }</svg>
58   -
59   - saveFull("filename", root, "UTF-8", true, doctype)
60   -
61   - }
62   -
63   - // Sort the list so more important nodes will be on top of the image
64   - def list(data: List[List[Float]]): NodeBuffer = {
  46 + // Generates 100 gradiens
  47 + def gradients: NodeBuffer = {
  48 + val result = new NodeBuffer
  49 + for(i <- 1 to 100){
  50 + val hex: String = color(i)
  51 + val gradient = <radialGradient id={"g_" + i}>
  52 + <stop offset="50%" style={"stop-opacity:0.7; stop-color: #" + hex } />
  53 + <stop offset="100%" style={"stop-opacity:0.1; stop-color: #" + hex } />
  54 + </radialGradient>
  55 + result &+ gradient
  56 + }
  57 + result
  58 + }
65 59
66   - // Find min and max value of latitude and longitude
67   - val lats: List[Float] = data.map( row => row(0))
68   - val w: Float = lats.reduceLeft(Math.min(_,_))
69   - val e: Float = lats.reduceLeft(Math.max(_,_))
70   -
71   - val lngs: List[Float] = data.map( row => row(1))
72   - val s: Float = lngs.reduceLeft(Math.min(_,_))
73   - val n: Float = lngs.reduceLeft(Math.max(_,_))
74   -
75   - val factor: Float = this.width / (e-w)
76   - val geo = new Geo(w,s)
  60 + def circles: NodeBuffer = {
77 61
78 62 val result = new NodeBuffer
79   - data.sort(_(2) > _(2)).foreach{ row =>
80   - result &+ (<elipse
81   - cx={ ((row(0)-w)*factor).toString }
82   - cy={ ((row(1)-s)*factor).toString }
83   - />)
84   -
85   -// paint(svgGenerator, (row(0)-w)*factor, (row(1)-s)*factor, (100 - row(2)).toInt, geo)
86   -
87   -// ellipse.setAttribute("rx", (geo.longitude_to_pixels(dist)/2).toString)
88   -// ellipse.setAttribute("ry", (geo.latitude_to_pixels(dist)/2).toString)
  63 +
  64 + // Sort the list so more important nodes will be on top of the image
  65 + geo.circles.sort(_.z > _.z).foreach{ circle =>
  66 + val c = <circle
  67 + style={ "fill: url(#g_" + circle.z + ")"}
  68 + cx={ circle.x.toString }
  69 + cy={ circle.y.toString }
  70 + r={ circle.r.toString }>
  71 + </circle>
  72 +
  73 + result &+ c
89 74 }
90 75 result
91   - }
92   -}
93   -
94   -class Geo(w: Float, s: Float) {
95   -
96   - val longitude_factor: Float = length(w, s, w, s+1).toFloat
97   - val latitude_factor: Float = length(w, s, w+1, s).toFloat
  76 + }
98 77
99   - // Returns length in kilometers from and to given points
100   - // Takes two points
101   - def length(p1_lng: Double, p1_lat: Double, p2_lng: Double, p2_lat: Double): Double = {
102   - val r = 6371
103   - val to_rad = 3.142 / 180
104   -
105   - val d_lat = (p2_lat - p1_lat) * to_rad
106   - val d_lng = (p2_lng - p1_lng) * to_rad
107   -
108   - val a = Math.sin(d_lat / 2) * Math.sin(d_lat / 2) +
109   - Math.cos(p1_lat * to_rad) * Math.cos(p2_lat * to_rad) *
110   - Math.sin(d_lng / 2) * Math.sin(d_lng / 2)
111   - val c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
112   - r * c
113   - }
114   -
115   - // Returns number of pixels which are required to draw horizontal line
116   - // Takes line lenght in kilometers
117   - def longitude_to_pixels(lenght: Float): Int = {
118   - Math.round(lenght * longitude_factor)
119   - }
120   -
121   - // Returns number of pixels which are required to draw vertical line
122   - // Takes line lenght in kilometers
123   - def latitude_to_pixels(lenght: Float): Int = {
124   - Math.round(lenght * latitude_factor)
125   - }
  78 + def polygon(limit: Int): NodeBuffer = {
  79 +
  80 + val set = geo.circles.filter(circle => (circle.z <= limit))
  81 +
  82 + val result = new NodeBuffer
  83 + var poly: Poly = new PolyDefault
  84 +
  85 + set.foreach(circle => poly = poly.union(circle.toPoly))
  86 +
  87 + Console.println("size: " + poly.getArea + " km2")
  88 +
  89 + var points = "M" + poly.getX(0) + " " + poly.getY(0)
  90 +
  91 + for(i <- 1 until poly.getNumPoints){
  92 + points = points + " L" + poly.getX(i) + " " + poly.getY(i)
  93 + }
  94 +
  95 + val polyline = <path
  96 + d={ points + " Z" }
  97 + style="fill:white; fill-opacity:0; stroke:white; stroke-width:0.02">
  98 + </path>
  99 +
  100 + result &+ polyline
  101 + result
  102 + }
126 103 }
7 src/Point.scala
... ... @@ -0,0 +1,7 @@
  1 +class Point(x: Float, y: Float, z: Int) {
  2 +
  3 + val lng = x
  4 + val lat = y
  5 + val mag = z
  6 +
  7 +}
34 src/Svg.scala
... ... @@ -0,0 +1,34 @@
  1 +import scala.io.Source
  2 +import scala.xml.dtd.{DocType, PublicID}
  3 +import scala.xml.XML._
  4 +
  5 +object Svg {
  6 + def main(args: Array[String]) {
  7 +
  8 + // Read file with initial data
  9 + val map = new HeatMap(Source.fromFile("../data/AWF.input"))
  10 +
  11 + // Declare the doctype of XML document
  12 + val doctype = DocType("svg", PublicID("-//W3C//DTD SVG 1.0//EN", "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"), Nil)
  13 +
  14 + // Create root node
  15 + val root =
  16 + <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width={ map.geo.image_width + "px" } height={ map.geo.image_height + "px" } viewBox={ map.geo.viewbox }>
  17 + <defs>
  18 + { map.gradients }
  19 + </defs>
  20 + <g opacity=".5">
  21 + { map.circles }
  22 + <g id="outline" opacity=".8">
  23 + { map.polygon(30) }
  24 + </g>
  25 + </g>
  26 +
  27 + </svg>
  28 +
  29 + print("Zapisuję mapę do pliku: svg/out.svg \n")
  30 + saveFull("svg/out.svg", root, "UTF-8", true, doctype)
  31 + print("Gotowe\n")
  32 +
  33 + }
  34 +}

0 comments on commit 05e55f0

Please sign in to comment.
Something went wrong with that request. Please try again.