All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.barrybecker4.simulation.reactiondiffusion.InteractionHandler.scala Maven / Gradle / Ivy

There is a newer version: 1.6.2
Show newest version
// Copyright by Barry G. Becker, 2016-2017. Licensed under MIT License: http://www.opensource.org/licenses/MIT
package com.barrybecker4.simulation.reactiondiffusion

import java.awt.event.{MouseEvent, MouseListener, MouseMotionListener}

import com.barrybecker4.simulation.reactiondiffusion.algorithm.GrayScottModel
import InteractionHandler.SQRT2

object InteractionHandler {
  val SQRT2: Double = Math.sqrt(2)
}

/**
  * Handle mouse interactions - converting them in to physical manifestations.
  * Using this handler, you can add more chemicals to the reaction.
  * @author Barry Becker
  */
class InteractionHandler(var model: GrayScottModel, var scale: Double)
  extends MouseListener with MouseMotionListener {

  private var currentX = 0
  private var currentY = 0
  private var brushRadius = GrayScottModel.DEFAULT_BRUSH_RADIUS
  private var brushStrength = GrayScottModel.DEFAULT_BRUSH_STRENGTH
  private var lastX = 0
  private var lastY = 0
  private var mouse1Down = false
  private var mouse3Down = false

  def setScale(scale: Double) {this.scale = scale }
  def setBrushRadius(rad: Int){ brushRadius = rad}
  def setBrushStrength(strength: Double) {brushStrength = strength}

  /** adds chemical U or V depending on the button pressed. */
  override def mouseDragged(e: MouseEvent): Unit = {
    currentX = e.getX
    currentY = e.getY
    doBrush()
    lastX = currentX
    lastY = currentY
  }

  private def doBrush() = {
    val i = (currentX / scale).toInt
    val j = (currentY / scale).toInt
    // apply the change to a convolution kernel area
    val startX = Math.max(1, i - brushRadius)
    val stopX = Math.min(model.getWidth - 1, i + brushRadius)
    val startY = Math.max(1, j - brushRadius)
    val stopY = Math.min(model.getHeight - 1, j + brushRadius)
    // adjust by this so that there is not a discontinuity at the periphery
    val minWt = 0.9 / (SQRT2 * brushRadius )
    for (ii <- startX to stopX)
      for (jj <- startY to stopY) {
        val weight = getWeight(i, j, ii, jj, minWt)
        applyChange(ii, jj, weight)
      }
  }

  /** @return the weight is 1 / distance. */
  private def getWeight(i: Int, j: Int, ii: Int, jj: Int, minWt: Double) = {
    val deltaX = i.toDouble - ii
    val deltaY = j.toDouble - jj
    var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
    if (distance < 0.5) distance = 1.0
    1.0 / distance - minWt
  }

  /** Make waves or adds ink depending on which mouse key is being held down. */
  private def applyChange(i: Int, j: Int, weight: Double) = {
    val amountToAdd = brushStrength * weight
    //println("m1 = " + mouse1Down + " m3 = " + mouse3Down + " amountToAdd " + amountToAdd + " at " + i + " " + j + " curY=" + model.u(i)(j) + " curV=" + model.v(i)(j))
    // if the left mouse is down, make waves
    if (mouse1Down) model.u(i)(j) += amountToAdd
    else if (mouse3Down) model.v(i)(j) += amountToAdd
  }

  override def mouseMoved(e: MouseEvent): Unit = {
    currentX = e.getX
    currentY = e.getY
    lastX = currentX
    lastY = currentY
  }

  /** The following methods implement MouseListener */
  override def mouseClicked(e: MouseEvent) {doBrush() }

  /** Remember the mouse button that is pressed. */
  override def mousePressed(e: MouseEvent): Unit = {
    mouse1Down = e.getButton == MouseEvent.BUTTON1
    mouse3Down = e.getButton == MouseEvent.BUTTON3
  }

  override def mouseReleased(e: MouseEvent) {}
  override def mouseEntered(e: MouseEvent) {}
  override def mouseExited(e: MouseEvent){}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy