Решил узнать, Скала. Вот попытка симуляции ткани


Я никогда не делала ничего функциональной раньше. Эти две функции являются уродливые. Думаю первый шаг нужно сделать, это извлечь внутренние биты, а потом карту за мои массивы. Что еще я могу сделать, чтобы сделать код немного более функциональным?

https://github.com/dbousamra/scalacloth/blob/master/src/cloth/Cloth.scala

В частности:

  def verletIntegration() = {   

    for (row <- grid) {
      for (p <- row) {
        if (p.stuck) p.setCurrentPos(p.getPreviousPos)

        var multiplyByTime = Tuple2(p.getForces * timestep * timestep, gravity * timestep * timestep)
        var minusPrevPos = Tuple2(p.getCurrentPos.getX - p.getPreviousPos.getX, p.getCurrentPos.getY - p.getPreviousPos.getY)
        var together = Tuple2(multiplyByTime._1 + minusPrevPos._1 , multiplyByTime._2  + minusPrevPos._2)
        p.setPreviousPos(p.getCurrentPos)
        p.setCurrentPos(new Position(p.getCurrentPos.getX + together._1, p.getCurrentPos.getY + together._2))
      }
    }
  }

  def satisfyConstraints() = {
    for (row <- grid) {
      for (p <- row) {
        if (p.stuck) p.setCurrentPos(p.getPreviousPos)
        else {
          var neighbors = p.getNeighbors
          for (constraint <- neighbors) {
            val c2 = grid(constraint.getX)(constraint.getY).getCurrentPos
            val c1 = p.getCurrentPos
            val delta = Tuple2(c2.getX - c1.getX, c2.getY - c1.getY)
            val deltaLength = math.sqrt(math.pow((c2.getX - c1.getX), 2) + math.pow((c2.getY - c1.getY),2))
            val difference = (deltaLength - 1.0f) / deltaLength
            val dtemp = Tuple2(delta._1 * 0.5f * difference, delta._2 * 0.5f * difference)
            p.setCurrentPos(new Position(c1.getX + dtemp._1.floatValue, c1.getY + dtemp._2.floatValue))
            grid(constraint.getX)(constraint.getY).setCurrentPos(new Position(c2.getX - dtemp._1.floatValue, c2.getY - dtemp._2.floatValue))
//          }

          }
        }
      }
    }
  }


487
5
задан 20 июля 2011 в 04:07 Источник Поделиться
Комментарии
3 ответа

for (row <- grid) {
for (p <- row) {

//should be written as:

for(row <- grid; p <- row) {

Tuple2("bla", 42)

//should be written as

("bla", 42)

Я не очень понимаю, почему вы используете кортежи, когда у вас уже есть класс для ведения именно такого рода математикой, а именно позиция.

Код может быть более функциональным использованием неизменяемых случае занятия должностис (но это зависит от проблемы, если это правильно делать):

case class Position(x: Float, y: Float) {
def -(that:Position) = Position(this.x - that.x, this.y - that.y)
def +(that:Position) = Position(this.x + that.x, this.y + that.y)
}

Тогда вы можете писать такие вещи, как pos1 + pos2. Обратите внимание, что вам не нужен геттер методы, как вы можете писать pos1.х, и не сеттер методы, как можно писать и pos1.копия(х=12). На новый не требуется больше: вал Р = Позиция(1, 3).

Как продолжить рефакторинг будет зависеть от вашего решения, если вы держите позицию как она есть, или если вы хотите пойти с незыблемыми позицииС.

[Править]

Вот как я бы рефакторинг это:

Бежать.скала:

package cloth

object Run {

def main(args: Array[String]): Unit = {

import javax.swing.JFrame

val test = new Screen
val frame = new JFrame("scalacloth")
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
frame.setPreferredSize(new java.awt.Dimension(640, 720))
frame.getContentPane().add(test)
test.init
frame.pack
frame.setVisible(true)
}

}

import processing.core._

class Screen extends PApplet {

val cloth = new Cloth(
rows = 20,
columns = 20,
gravity = 0.001f,
timestep = 0.8f,
fixedParticles = List(Coordinate(19,0))
)

override def setup() {
cloth.createGrid()
size(640, 720)
background(255)
smooth()
noStroke()
fill(0, 102)
}

override def draw() {
background(255)
fill(255)
stroke(0)

def drawLines(particle: Particle):Unit = particle.neighbors.foreach { n =>
line(particle.currentPos.x * 20 + 20, particle.currentPos.y * 20 + 20,
cloth.grid(n.x)(n.y).currentPos.x * 20 + 20, cloth.grid(n.x)(n.y).currentPos.y* 20 + 20)
}

for(column <- cloth.grid; particle <- column) drawLines(particle)
cloth.verletIntegration
cloth.satisfyConstraints
}
}

Положение.скала:

package cloth

case class Position(x: Float, y: Float) {
def -(that:Position) = Position(this.x - that.x, this.y - that.y)
def +(that:Position) = Position(this.x + that.x, this.y + that.y)
def *(scalar:Float) = Position(this.x * scalar, this.y * scalar)
def length = math.sqrt(x*x + y*y).toFloat
}

Частиц.скала:

package cloth

class Particle(
var currentPos: Position,
var previousPos: Position,
val gridIndex: Coordinate,
val restLength: Float,
val neighbors: Array[Coordinate],
var stuck: Boolean
) {

val forces = 0.0f
}

... и тряпкой.скала:

package cloth

import scala.collection

case class Coordinate(x: Int, y: Int)

class Cloth(
val rows: Int,
val columns: Int,
var gravity: Float,
val timestep: Float,
val fixedParticles: List[Coordinate]
) {

val grid = new Array[Array[Particle]](rows, columns)

def createGrid(): Unit = for (x <- 0 until rows; y <- 0 until columns) {
val coord = Coordinate(x, y)
val pos = Position(x, y)
grid(x)(y) = new Particle(pos, pos, coord, 1.0f, findNeighbors(coord),
fixedParticles.contains(coord))
}

def findNeighbors(coord: Coordinate): Array[Coordinate] = Array(
coord.copy(x = coord.x - 1),
coord.copy(y = coord.y - 1),
coord.copy(x = coord.x + 1),
coord.copy(y = coord.y + 1)
).filter(isOccupied(_))

def isOccupied(coord: Coordinate): Boolean =
(0 <= coord.x && coord.x < rows &&
0 <= coord.y && coord.y < columns)

def verletIntegration(): Unit = for (row <- grid; p <- row)
p.currentPos =
if (p.stuck) p.previousPos else {
val multiplyByTime = Position(p.forces * timestep * timestep, gravity * timestep * timestep)
val together = multiplyByTime + p.currentPos - p.previousPos
p.previousPos = p.currentPos
p.currentPos + together
}

def satisfyConstraints() {

def calculateConstraint(constraint: Coordinate, p: Particle) {
val c2 = grid(constraint.x)(constraint.y).currentPos
val c1 = p.currentPos
val delta = c2 - c1
val difference = 0.5f * (1.0f - 1.0f / delta.length)
val dtemp = delta * difference
p.currentPos = c1 + dtemp
grid(constraint.x)(constraint.y).currentPos = c2 - dtemp
}

for(row <- grid; p <- row)
if (p.stuck) p.currentPos = p.previousPos
else p.neighbors.foreach(calculateConstraint(_, p))
}

}

Надеюсь, что помогает...

7
ответ дан 20 июля 2011 в 06:07 Источник Поделиться

Есть идея для Scala для-петли: вы можете включать задания в производственной части:

for (constraint <- neighbors) {
val c2 = grid (constraint.getX) (constraint.getY).getCurrentPos
val c1 = p.getCurrentPos
val delta = Tuple2 (c2.getX - c1.getX, c2.getY - c1.getY)
// ...

Тогда вам не нужны ключевое слово "вал":

for (constraint <- neighbors;
c2 = grid (constraint.getX) (constraint.getY).getCurrentPos
c1 = p.getCurrentPos
delta = Tuple2 (c2.getX - c1.getX, c2.getY - c1.getY)
// ...

однако - я ожидаю урожай, следуя за

val x = for (y)
yield z

И методы, которые не принимают параметров и не возвращают которые либо бесполезны, либо делают побочные эффекты. Слишком много Варс такие же запахи: изменяемое состояние.

Пытаться достичь своей цели без изменяемого состояния, и вы найдете более функциональных моделей.

2
ответ дан 20 июля 2011 в 05:07 Источник Поделиться

Ох, обработка Скала! Хорошее сочетание...

Я взял отличный переписывание кода с Landei как основу для своих экспериментов...
Я исправил устаревании предупреждение (время инициализации), сделал еще несколько переменных неизменными, улучшились стороны (не забывайте: размер() должен быть первым вызов настройки())... потом я сошел с ума от рефакторинга, изменив имена, чтобы соответствовать моему пониманию алгоритма и т. д.

Так как я новичок в Scala себя, я обнаружил, что это хорошее упражнение, но она до сих пор работает...
Возможно, Вам будет интересно увидеть мой вариант кода:
http://bazaar.launchpad.net/~philho/+барахло/Скала/файлы/руководитель:/_SmallPrograms/ClothSimulation/

1
ответ дан 22 июля 2011 в 03:07 Источник Поделиться