Commit 55eba7e3 authored by h2b's avatar h2b

Parallel shapes added.

parent 1edee838
......@@ -161,6 +161,7 @@ abstract class Screen (override val p0: Pixel, override val width: Int,
* @param col computing function that maps pixel coordinates to colors
* @return a future with no specific value indicating the completion of this
* operation
* @since 1.1.0
*/
def setPixelsParallel (p1: Pixel, p2: Pixel) (col: Pixel Color): Future[Unit] = {
val left = p1.x min p2.x
......@@ -189,6 +190,7 @@ abstract class Screen (override val p0: Pixel, override val width: Int,
* @param col computing function that maps pixel coordinates to colors
* @return a future with no specific value indicating the completion of this
* operation
* @since 1.1.0
*/
def setPixelsParallel (col: Pixel Color): Future[Unit] =
setPixelsParallel(Pixel(0,0), Pixel(width-1,height-1))(col)
......
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.shapes.parallel
import scala.concurrent.Future
import de.h2b.scala.lib.simgraf.{ Color, Pixel, Point, World }
import de.h2b.scala.lib.simgraf.shapes.{ Enclosing, Fillable }
/**
* A computed coloring using parallel operations.
*
* @constructor
*
* @param col computing function that maps point coordinates to colors
*
* @param enc enclosing for this grid; defaults to the full world if not
* explicitly or otherwise implicitly given
*
* @since 1.1.0
* @author h2b
*/
case class Coloring (val col: Point Color) (implicit val enc: Enclosing)
extends Fillable with FutureTracking {
def fill (w: World): Unit = {
val bounds = enc.bounds(w)
def pixcol (p: Pixel): Color = col(w.toPoint(p))
future = w.screen.setPixelsParallel(w.toPixel(bounds.p1), w.toPixel(bounds.p2))(pixcol)
}
}
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.shapes.parallel
import scala.concurrent.Future
import de.h2b.scala.lib.simgraf.{ Pixel, World }
import de.h2b.scala.lib.simgraf.shapes.{ Drawable, Enclosing, Fillable }
/**
* A function as shape using parallel operations.
*
* When filling, this is done from the x axis (i.e. `y==0`).
*
* @constructor
*
* @param f
*
* @param enc enclosing for this function; defaults to the full world if not
* explicitly or otherwise implicitly given
*
* @since 1.1.0
* @author h2b
*/
case class Function (val f: Double Double) (implicit val enc: Enclosing)
extends Drawable with Fillable with FutureTracking {
def draw (w: World): Unit = {
val (wl, wr, wb, wt) = enc.lrbt(w)
val (sl, sr, sb, st) = (w.screenX(wl), w.screenX(wr), w.screenY(wb), w.screenY(wt))
val futures = for (x sl until sr) yield Future {
val y = w.screenY(f(w.worldX(x)))
val l2 = w.lineWidthHint.value/2
for (h -l2 to +l2) {
val yh = y+h
if (sb<=yh && yh<=st) w.screen.setPixel(Pixel(x, yh), w.activeColor)
}
}
future = Future.sequence(futures) map { _ () }
}
def fill (w: World): Unit = {
val (wl, wr, wb, wt) = enc.lrbt(w)
val (sl, sr, sb, st) = (w.screenX(wl), w.screenX(wr), w.screenY(wb), w.screenY(wt))
def clipY (y: Int): Int =
if (y<sb) sb
else if (st<y) st
else y
val s0 = clipY(w.screenY(0))
val futures = for (x sl until sr) yield Future {
w.screen.drawLine(Pixel(x,s0), Pixel(x, clipY(w.screenY(f(w.worldX(x))))))
}
future = Future.sequence(futures) map { _ () }
}
}
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.shapes.parallel
import scala.concurrent.Future
/**
* Provides some measures to check for completion of futures.
*
* @since 1.1.0
* @author h2b
*/
trait FutureTracking {
protected var future = Future.unit
/**
* Indicates whether some concurrent operation is done.
*
* The returned value can be used if further operations need to be informed
* when some operation is completed (e.g., by setting a callback).
*
* @note When calling one or more methods of this instance multiple the result
* is unpredictable: you get the value that the last currently active operation left.
* In this case and also generally when an exception is returned further operations
* might still going on.
*
* @return a future with no specific value indicating the completion of some
* operation
*/
def currentFuture: Future[Unit] = future
}
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.shapes.parallel
import scala.concurrent.Future
import de.h2b.scala.lib.simgraf.{ Pixel, World }
import de.h2b.scala.lib.simgraf.shapes.{ Drawable, Enclosing, Fillable }
/**
* A multivalued function as shape using parallel operations.
*
* When filling, this is done from the lowest to the highest multivalue for each
* x, respectively.
*
* @constructor
*
* @param f
*
* @param enc enclosing for this function; defaults to the full world if not
* explicitly or otherwise implicitly given
*
* @since 1.1.0
* @author h2b
*/
case class MultivaluedFunction (val f: Double Set[Double]) (implicit val enc: Enclosing)
extends Drawable with Fillable with FutureTracking {
def draw (w: World): Unit = {
val (wl, wr, wb, wt) = enc.lrbt(w)
val (sl, sr, sb, st) = (w.screenX(wl), w.screenX(wr), w.screenY(wb), w.screenY(wt))
val futures = for (x sl until sr) yield Future {
for {
y f(w.worldX(x)) map { w.screenY(_) }
if (sb<=y && y<=st)
} w.screen.setPixel(Pixel(x, y), w.activeColor)
}
future = Future.sequence(futures) map { _ () }
}
def fill (w: World): Unit = {
val (wl, wr, wb, wt) = enc.lrbt(w)
val (sl, sr, sb, st) = (w.screenX(wl), w.screenX(wr), w.screenY(wb), w.screenY(wt))
def clipY (y: Int): Int =
if (y<sb) sb
else if (st<y) st
else y
val futures = for (x sl until sr) yield Future {
val yset = f(w.worldX(x)) map { w.screenY(_) }
val ymin = clipY(yset.min)
val ymax = clipY(yset.max)
w.screen.drawLine(Pixel(x, ymin), Pixel(x, ymax))
}
future = Future.sequence(futures) map { _ () }
}
}
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.shapes
/**
* This package provides parallel versions of some shapes.
*
* @since 1.1.0
* @author h2b
*/
package object parallel {
private[parallel] implicit lazy val packageExecutionContext = de.h2b.scala.lib.simgraf.packageExecutionContext
}
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.h2b.scala.lib.simgraf.demo
import scala.math.{ Pi, sin }
import scala.util.Random
import de.h2b.scala.lib.simgraf.{ Color, Pixel, Point, Screen, World }
import de.h2b.scala.lib.simgraf.shapes.Grid
import de.h2b.scala.lib.simgraf.shapes.parallel._
import scala.concurrent.Future
import scala.util.Success
import scala.util.Failure
object ParallelShapesDemo extends App {
private val p1 = Point(-100,-100)
private val p2 = Point(100,100)
private val p0 = p1+(p2-p1)*0.5
private val w = 200
private val h = 200
private val dx = w/10
private val dy = h/10+50
private val wMax = Screen.width
private val hMax = Screen.height
private val x0 = 10
private var x = x0
private var y = 10
private def loc () = {
if (y+h>hMax) throw new RuntimeException("screen overflow")
val p = Pixel(x,y)
x += w+dx
if (x+w>wMax) { x = x0; y += h+dy }
p
}
private def newDefaultWorld (title: String) = World(p1, p2)(loc(), w, h, title)
private def newSinusWorld (title: String) = World(Point(-2*Pi,-1.2), Point(+2*Pi,+1.2))(loc(), w, h, title)
private def onComplete (fut: Future[_], name: String) = fut.onComplete {
case Success(_) println(s"$name succeeded.")
case Failure(f) println(s"$name failed with: " + f.getMessage)
} (scala.concurrent.ExecutionContext.global)
{
val name = "Parallel Random Coloring"
val world = newDefaultWorld(name)
val f = Coloring(_ =>
Color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256)))
world.fill(f)
onComplete(f.currentFuture, name)
}
{
val name = "Parallel Drawing y=sin(x)"
val world = newSinusWorld(name)
world.clear(Color.White)
world.activeColor = Color.Gray
world.draw(Grid(Pi/2, 0.2))
world.activeColor = Color.Red
val f = Function((x: Double) sin(x))
world.draw(f)
onComplete(f.currentFuture, name)
}
{
val name = "Parallel Filling y=sin(x)"
val world = newSinusWorld(name)
world.clear(Color.White)
world.activeColor = Color.Gray
world.draw(Grid(Pi/2, 0.2))
world.activeColor = Color.Blue
val f = Function((x: Double) sin(x))
world.fill(f)
onComplete(f.currentFuture, name)
}
private def fuzzySinus (x: Double) = {
val y = sin(x)
val n = 5
var result = Set.empty[Double]
for (i 1 to n) result += y+(0.5-Random.nextDouble())/2.5
result
}
{
val name = "Parallel Drawing Fuzzy Sinus"
val world = newSinusWorld(name)
world.clear(Color.Yellow)
world.activeColor = Color.Orange
world.draw(Grid(Pi/2, 0.2))
world.activeColor = Color.Magenta
val f = MultivaluedFunction(fuzzySinus)
world.draw(f)
onComplete(f.currentFuture, name)
}
{
val name = "Parallel Filling Fuzzy Sinus"
val world = newSinusWorld(name)
world.clear(Color.Yellow)
world.activeColor = Color.Orange
world.draw(Grid(Pi/2, 0.2))
world.activeColor = Color.Cyan
val f = MultivaluedFunction(fuzzySinus)
world.fill(f)
onComplete(f.currentFuture, name)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment