1

I have the following test code where I have a ClothMesh (from FXyz lib) that I can drag, rotate and drag my circle handles. All works well, FXyz is great. Now I want to use SegmentedSphereMesh, it mostly work except that my circle handles are 2D and not wrapped around the sphere. I know the possible problems mixing 2D and 3D. However, it is so close to working; how can I make my handles work with the sphere, or what would be another way to do the same function. Note, I do not want to control the shape/mesh by moving the camera around.

import org.fxyz.shapes.complex.cloth.ClothMesh
import org.fxyz.shapes.primitives.SegmentedSphereMesh

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.DoubleProperty
import scalafx.collections.ObservableFloatArray
import scalafx.scene.image.Image
import scalafx.scene.input.{MouseButton, MouseEvent}
import scalafx.scene.paint.PhongMaterial
import scalafx.scene.shape._
import scalafx.scene.transform.Rotate
import scalafx.scene._
import scalafx.scene.paint.Color

/**
 * left mouse to drag the meshView and also to drag the handles
 * right mouse drag + ctrl to rotate about X axis
 * right mouse drag + alt to rotate about Y axis
 * right mouse drag + shift to rotate about Z axis
 */

object ClothTest2 extends JFXApp {
  private var dx = 0.0
  private var dy = 0.0

  stage = new PrimaryStage {
    scene = new Scene(600, 600, true, SceneAntialiasing.Balanced) {
      fill = Color.LightGray
      val testImg = "https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png"
      val img = new Image(testImg, 400, 400, false, true)

      val meshView = new SegmentedSphereMesh(20, 4, 2, 200d)
    //  val meshView = new ClothMesh(4, 4, 200, 200, 0.5, 0.5, 1.0)

      meshView.setDrawMode(DrawMode.Fill)
      meshView.setCullFace(CullFace.None)
      meshView.style = "-fx-background-color: #00000000"
      meshView.setMaterial(new PhongMaterial(Color.White, img, null, null, null))
      val controller = new MeshController(meshView.getMesh().asInstanceOf[javafx.scene.shape.TriangleMesh].points)
      val viewGroup = new Group(meshView, controller)
      root = new Group(new AmbientLight(Color.White), viewGroup) { translateX = 70; translateY = 70 }
      camera = new PerspectiveCamera(true) {
        nearClip = 0.0
        farClip = 100000.0
        fieldOfView = 42
        verticalFieldOfView = true
        translateZ = -900
      }
      val rotHandler = new RotHandler(viewGroup)
      onMouseDragged = (event: MouseEvent) => {
        rotHandler.onMouseDragged(event)
        if (event.button == MouseButton.PRIMARY) {
          viewGroup.layoutX = event.sceneX + dx
          viewGroup.layoutY = event.sceneY + dy
          event.consume()
        }
      }
      onMousePressed = (event: MouseEvent) => {
        rotHandler.onMousePressed(event)
        dx = viewGroup.layoutX.value - event.sceneX
        dy = viewGroup.layoutY.value - event.sceneY
        event.consume()
      }
    }
  }
}

class CircleHandle(color: Color) extends Circle {
  radius = 8
  var dx = 0.0
  var dy = 0.0
  fill <== when(hover) choose Color.Red.deriveColor(1, 1, 1, 0.4) otherwise color.deriveColor(1, 1, 1, 0.4)
  strokeWidth <== when(hover) choose 3 otherwise 2
  stroke = color
  onMousePressed = (event: MouseEvent) => {
    dx = centerX.value - event.x
    dy = centerY.value - event.y
    event.consume()
  }
  onMouseDragged = (event: MouseEvent) => {
    centerX = event.x + dx
    centerY = event.y + dy
    event.consume()
  }
}

class MeshController(thePoints: ObservableFloatArray) extends Group {
  children = for (i <- 0 until thePoints.size by 3) yield new CircleHandle(Color.Yellow) {
      centerX() = thePoints.get(i)
      centerX.onChange { (obs, oldVal, newVal) => thePoints.set(i, newVal.floatValue()) }
      centerY() = thePoints.get(i + 1)
      centerY.onChange { (obs, oldVal, newVal) => thePoints.set(i + 1, newVal.floatValue()) }
    }
}

class RotHandler(val viewer: Group) {
  private val angleX = DoubleProperty(0)
  private val angleY = DoubleProperty(0)
  private val angleZ = DoubleProperty(0)
  private var anchorX = 0d
  private var anchorY = 0d
  private val rotX = new Rotate { angle <== angleX; axis = Rotate.XAxis }
  private val rotY = new Rotate { angle <== angleY; axis = Rotate.YAxis }
  private val rotZ = new Rotate { angle <== angleZ; axis = Rotate.ZAxis }
  viewer.transforms = Seq(rotX, rotY, rotZ)
  def onMousePressed(event: MouseEvent) = {
    anchorX = event.sceneX
    anchorY = event.sceneY
    event.consume()
  }
  def onMouseDragged(event: MouseEvent) = {
    // right mouse only
    if (event.button == MouseButton.SECONDARY) {
      event match {
        // rotation about the Y axis, dragging the mouse in the x direction
        case ev if ev.altDown => angleY() = anchorX - event.sceneX
        // rotation about the X axis, dragging the mouse in the y direction
        case ev if ev.controlDown => angleX() = anchorY - event.sceneY
        // rotation about the Z axis, dragging the mouse in the x direction
        case ev if ev.shiftDown => angleZ() = anchorX - event.sceneX
        case _ => // ignore everything else
      }
    }
    event.consume()
  }
}
workingdog
  • 43
  • 4
  • I am part of the FXyz team and would like to help but could you post an image or provide an image link to the effect you currently have. I'm not currently setup to compile and run Scala. Also can you describe in more detail how you want when you say "make my handles work with the sphere" ? Thx. – Birdasaur Aug 28 '15 at 12:39
  • Thanks Birdasaur for taking the time to look at my question. I have updated the code (and some pictures) at: https://github.com/workingDog/testcode Basically my original question was how to attached my handles to the vertices of a SegmentedSphereMesh. I have done that now, I think, although I still cannot drag them like I can do with a ClothMesh. I'll be away for a week. When I come back I'll convert the code into java. – workingdog Aug 31 '15 at 00:33

0 Answers0