Drawing Shapes in scala - scala

I am having some serious troubles implementing a draw in the scala language. my current code looks like:
package edu.luc.cs.laufer.cs473.shapealgebra
import java.awt.Graphics2D
class Draw {
def draw(g: Graphics2D)(s: Shape): Unit = s match {
case Ellipse(hw, hh) => g.drawArc(-hw, -hh, 2 * hw, 2 * hh, 0, 360)
case Rectangle(w, h) => g.drawRect(0, 0, w, h)
case Location(x: Int, y: Int, shape: Shape) => {
g.translate(x, y)
draw(g)(shape)
g.translate(0,0)
}
case Group(shapes # _*) => {
shapes foreach(draw(g)(_))
}
}
}
object Draw extends Draw {
def apply(g: Graphics2D) = draw(g)(_)
}
The problem here is with my group case. It does not draw a group of shapes properly. The two test cases uses the following shapes:
val simpleLocation = Location(70, 30, Rectangle(80, 120))
val complexGroup = Location(50, 100,
Group(
Ellipse(20, 20),
Location(150, 50,
Group(
Rectangle(50, 30),
Rectangle(300, 60),
Location(100, 200,
Ellipse(50, 50)
)
)
),
Rectangle(100, 200)
)
)
The complex continues to fail and I can't figure out why.
package edu.luc.cs.laufer.cs473.shapealgebra
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite
import java.awt.image.BufferedImage
import TestFixtures._
#RunWith(classOf[JUnitRunner])
class TestDraw extends FunSuite with BufferedImageEquality {
test("simple") {
val s = simpleLocation
val i = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
Draw(i.createGraphics())(s)
val j = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
val g = j.createGraphics()
g.translate(70, 30)
g.drawRect(0, 0, 80, 120)
assertEquals(i, j)
}
test("complex") {
val s = complexGroup
val i = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
Draw(i.createGraphics())(s)
val j = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB)
val g = j.createGraphics()
paintComplexGroup(g)
assertEquals(i, j)
}
}
The test case is shown above. I get a "0 did not equal 255" from the result of the unit test.

If you look at what translate does, the Javadoc says
"Translates the origin of the Graphics2D context to the point (x, y)
in the current coordinate system."
So
g.translate(0,0)
does nothing. Try
g.translate(-x, -y)
Although, if it were me, I wouldn't mess with the Graphics object's origin. I'd modify the drawRect and drawArc statements to take a location, and pass the location co-ordiates as an argument to the method.

I see you are calling translate on g: Graphics2D, which mutates that object. However, you are not undoing that mutation once you finish drawing the translated objects. Furthermore, there's also the question of whether you expect the translation to be cumulative (for example, the second translation be absolute 200, 150, instead of absolute 150, 50).
Might this the problem you see?

Related

How to get node type in graph scala

I am generating a graph using graph-scala library and I need to set the coordinates after building the graph.
My object are Ball and Figure extending from GraphNode. And I generate my Graph using the GraphNode object:
val ball1=new Ball(1,"BALL-A")
val figure1=new Figure(1)
val figure2=new Figure(2)
val figure3=new Figure(3)
val edges = Seq(
(ball1, figure1),
(figure2, ball1),
(ball1, figure3)
)
val graph1: Graph[GraphNode, HyperEdge] = edges
.map({ case (node1, node2) =>
Graph[GraphNode, HyperEdge](node1 ~> node2)
})
.reduce(_ ++ _)
And now I want to set X, Y and Width properties for each node:
graph1.nodes
.map(node => {
node match {
case b: Ball =>
println("is a ball!")
if (b.nodeType.equals("BALL-A"))
b.copy(x = 0, y = 0, width = 100)
else
b.copy(x = 30, y = 30, width = 200)
case otherType =>
val name = otherType.getClass.getSimpleName
println(name)
}
node.toJson
})
.foreach(println)
But I get the type "NodeBase" instead of setting the node. Any suggestions to set properties once I built the graph? My base issue is to get the type for each node to set the property but I am not able to.

Modifying var type of data set in Spark using its own method

The following is a minimal example of the problem I am facing. I have an array that I want to modify in-place as it has about a million elements. the following code works except for the very last statement.
import spark.implicits._
case class Frame(x: Double, var y: Array[Double]) {
def total(): Double = {
return y.sum
}
def modifier(): Unit = {
for (i <- 0 until y.length) {
y(i) += 10
}
return
}
}
val df = Seq(
(1.0, Array(0, 2, 1)),
(8.0, Array(1, 2, 3)),
(9.0, Array(11, 21, 23))
).toDF("x", "y")
val ds = df.as[Frame]
ds.show
ds.map(_.total()).show // works
ds.map(_.modifier()).show // does not work
The error is as follows:
scala> ds.map(_.modifier()).show
<console>:50: error: Unable to find encoder for type Unit. An implicit Encoder[Unit] is needed to store Unit instances in a Dataset. Primitive types (Int, String, etc) and Product types (case classes) are supported by importing spark.implicits._ Support for serializing other types will be added in future releases.
ds.map(_.modifier()).show
I cannot see the origin of the problem. I would be grateful for any help in fixing the bug.
Actually, this has nothing to do with 'var' or 'val', its about mutable data structures. The problem is that modifier returns Unit (e.g. nothing), so you cannot map on this results. You can run it using :
case class Frame(x: Double, var y: Array[Double]) {
def total(): Double = {
return y.sum
}
def modifier(): Frame = {
for (i <- 0 until y.length) {
y(i) += 10
}
return this
}
}
But I does not make much sense in my opinion, you should avoid mutable state. In addition, I would keep case classes simple (i.e. without logic) in spark, use them as data containers only. If you must increase every element by then, you can do it also like this:
case class Frame(x: Double, val y: Array[Double])
ds.map(fr => fr.copy(y = fr.y.map(_+10.0))).show

How to reduce each individual ingredient according to another seq of 'applied' ingredients in a recipe

So I have a soup that is compromised of a sequence of ingredient.
I need to determine what ingredients I still need to apply to the soup, based on a sequence of mixtures I have already added to the soup that I am making.
case class Ingredient(name: String)
case class Mixture(ingredient: Ingredient, amount: Int)
// ingredient required to make soup
val i1 = Ingredient("water")
val i2 = Ingredient("salt")
val i3 = Ingredient("sugar")
val soupRequirements = Seq(Mixture(i1, 100), Mixture(i2, 200), Mixture(i3, 50))
println(soup)
val addedIngrediants = Seq(Mixture(i1, 50), Mixture(i2, 200), Mixture(i3, 40))
def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] = ???
Reference: https://scastie.scala-lang.org/X6PIG7zYQOGuZX7zcebgRQ
How exactly can I reduce each mixture by the correct amount in a functional way?
First define way of reducing two Mixtures via infix operator
implicit class ReduceMixtures(a: Mixture) {
def +(b: Mixture): Mixture =
if (a.ingredient == b.ingredient) Mixture(a.ingredient, a.amount - b.amount)
else a
}
Note how if the ingredients do not match we return a unchanged. Now we can implement determineWhatsLeft using foldLeft
def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] = {
addedIngredients.foldLeft(soupRequirements) { case (acc, next) => acc.map(_ + next) }
}
Using foldLeft the order does not matter, however if the order of soupRequirements and addedIngredients was always mirrored then we could zip and map like so
def determineWhatsLeft(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] =
(soupRequirements zip addedIngredients).map { case (a, b) => a + b }
Semigroup seems to be the least powerful abstraction fitting the requirement
import cats.implicits._
import cats.Semigroup
implicit object mixtureSemigroup extends Semigroup[Mixture] {
def combine(a: Mixture, b: Mixture): Mixture =
if (a.ingredient == b.ingredient) Mixture(a.ingredient, a.amount - b.amount)
else a
}
implicit object seqMixtureSemigroup extends Semigroup[Seq[Mixture]] {
def combine(soupRequirements: Seq[Mixture], addedIncredients: Seq[Mixture]): Seq[Mixture] =
addedIngredients.foldLeft(soupRequirements) { case (acc, next) =>
acc.map(_ |+| next)
}
}
soupRequirements |+| addedIngredients

NPE in using scala Array.fill

I am reading Programming in Scala, Third Edition (Also present in Fourth Edition), by Lex Spoon; Bill Venners; Martin Odersky, and trying out examples along the way.
Following example form the book | Run in ScalaFiddle
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class UniformElement(
ch: Char,
override val width: Int,
override val height: Int
) extends Element {
private val line = ch.toString * width
def contents = Array.fill(height)(line)
}
val e: Element = new UniformElement('x', 2, 3)
gives java.lang.NullPointerException, when tried in REPL, or in Eclipse worksheet.
If I change
private val line = ch.toString * width
to
private def line = ch.toString * width
no error occurs.
Can someone explain, please?
I am using scala 2.11.8
The problem here is that contents is still not defined in the constructor, when you define line. If line is a val, it does not pick the overridden width, instead it uses the abstract one which in turn uses contents, which is still undefined and you get the NPE. You can see this by looking at the stacktrace and noting that the NPE is thrown by the definition of width in the abstract class.
When line is defined as a method, it does not execute until you call it and by that time contents will be fully defined, because it can call line (another method) which will be fully defined.
Run on ScalaFiddle
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class UniformElement(
ch: Char,
override val width: Int,
override val height: Int
) extends Element {
private def line: String = ch.toString * width
def contents = Array.fill(height)(line)
}
val e3: Element = new UniformElement('x', 2, 3)
Bottom line: you have a kind of "circular dependency" between line and contents.

Rendering an "Inter-"CategoryMarker in JFreeChart

I've got a box plot (CategoryPlot) with a customBoxAndWhiskerRenderer`. A series of bins forms the categories. I want to mark the transition from one category to another with a vertical line.
For example in the following figure, a line marks the sixth category, however I want it to appear between the fifth and sixth category:
val mark = new CategoryMarker(splitBin)
mark.setDrawAsLine(true)
plot.addDomainMarker(mark, Layer.BACKGROUND)
What is the best/easiest way to achieve this?
Since I already had a custom renderer, I hooked into the drawDomainMarker method, checking for the presence of a custom sub type of CategoryMarker:
class LeftCategoryMarker(key: Comparable[_], paint: Paint, stroke: Stroke)
extends CategoryMarker(key, paint, stroke) {
def this(key: Comparable[_]) = this(key, Color.gray, new BasicStroke(1.0f))
}
Then the draw method diverts:
override def drawDomainMarker(g2: Graphics2D, plot: CategoryPlot, axis: CategoryAxis,
marker: CategoryMarker, dataArea: Rectangle2D): Unit =
marker match {
case _: LeftCategoryMarker => drawLeftMarker(g2, plot, axis, marker, dataArea)
case _ => super.drawDomainMarker(g2, plot, axis, marker, dataArea)
}
 
private def drawLeftMarker(g2: Graphics2D, plot: CategoryPlot, axis: CategoryAxis,
marker: CategoryMarker, dataArea: Rectangle2D): Unit = {
val cat = marker.getKey
val dataset = plot.getDataset(plot.getIndexOf(this))
val catIdx = dataset.getColumnIndex(cat)
if (catIdx < 0) return
val savedComposite = g2.getComposite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, marker.getAlpha))
axis.getCategoryMargin
val numCat = dataset.getColumnCount
val domainEdge = plot.getDomainAxisEdge
val left = axis.getCategoryStart (catIdx, numCat, dataArea, domainEdge)
val gap = calculateCategoryGapSize(axis , numCat, dataArea, domainEdge)
val v = left - gap/2
val line = if (plot.getOrientation == PlotOrientation.HORIZONTAL)
new Line2D.Double(dataArea.getMinX, v, dataArea.getMaxX, v)
else
new Line2D.Double(v, dataArea.getMinY, v, dataArea.getMaxY)
g2.setPaint (marker.getPaint )
g2.setStroke(marker.getStroke)
g2.draw(line)
g2.setComposite(savedComposite)
}
And the following protected method from CategoryAxis is needed to calculate the gap:
private def calculateCategoryGapSize(axis: CategoryAxis, categoryCount: Int,
area: Rectangle2D, e: RectangleEdge): Double = {
if (categoryCount == 0) return 0.0
val available = if ((e == RectangleEdge.TOP) || (e == RectangleEdge.BOTTOM))
area.getWidth
else if ((e == RectangleEdge.LEFT) || (e == RectangleEdge.RIGHT))
area.getHeight
else
0.0
available * axis.getCategoryMargin / (categoryCount - 1)
}