#VRML V2.0 utf8
##################################################################
# Copyright 1996-98 ©, the Regents of the University of Michigan #
# The University of Michigan Virtual Reality Laboratory #
##################################################################
WorldInfo {
title "Virtual Lathe"
info [
"by Bert Schoenwaelder and Lars Schumann, 1998"
"http://www-vrl.umich.edu/"
"mailto:{bertsch|larsi}@umich.edu"
]
}
###########################################################
#
# General Adjustements
#
###########################################################
NavigationInfo {
type ["EXAMINE" "ANY"]
}
Viewpoint {
position 0 12 16
orientation -1 0 0 0.7854
description "Front"
}
#DEF LIGHT DirectionalLight {
# intensity 0.7
# direction 1 -1 -1
#}
###########################################################
#
# The Tool, moveable by the plane sensor
#
###########################################################
Transform {
children [
DEF TOOLSENSOR PlaneSensor {
maxPosition 7 -0.5
minPosition -7 -20
autoOffset FALSE
}
DEF TOOLTOUCH TouchSensor {
}
DEF TOOLTRANS Transform {
children [
Transform {
children Shape {
appearance Appearance {
material Material {
diffuseColor 0.2 0.2 1
specularColor 1 1 1
shininess 0.8
}
}
geometry Cylinder {
radius 0.2
height 4
}
}
translation 0 -2.4 0
}
Transform {
children Shape {
appearance Appearance {
material Material {
diffuseColor 0.5 0.5 1
specularColor 0.8 0.8 1
shininess 0.9
}
}
geometry Cone {
bottomRadius 0.2
height 0.4
}
}
translation 0 -0.2 0
}
DEF SPARKTIMER TimeSensor {
cycleInterval 0.3
}
DEF SPARKSWITCH Switch {
whichChoice -1
choice Shape {
appearance Appearance {
material Material {
emissiveColor 1 1 0.5
}
}
geometry DEF SPARKS IndexedLineSet {
coord DEF SPARKCOORD Coordinate {
point []
}
coordIndex []
color DEF SPARKCOLOR Color {
color []
}
}
}
}
Sound {
minFront 10
maxFront 100
minBack 10
maxBack 100
source DEF TOOLSOUND AudioClip {
url "tool.wav"
loop TRUE
startTime 0
stopTime 1
}
}
]
}
]
rotation 1 0 0 -1.57
}
###########################################################
#
# The rotating stock, constructed by the script
#
###########################################################
DEF ROTTRANS Transform {
children [
DEF ROTTOUCH TouchSensor {
}
DEF STOCK Shape {
appearance DEF STOCKAPPR Appearance {
material Material {
diffuseColor 0.5 0.5 1
shininess 0.9
specularColor 0.5 0.5 1
}
}
geometry DEF SHAPE Extrusion {
beginCap FALSE
endCap FALSE
convex FALSE
ccw FALSE
creaseAngle 1
crossSection [-1 -7, 1 -7, 1 7, -1 7]
spine [0 0 1, 0 -0.65 0.77, 0 -0.99 0.17, 0 -0.87 -0.5,
0 -0.35 -0.94, 0 0.34 -0.94, 0 0.87 -0.5,
0 0.98 0.17, 0 0.64 0.77, 0 0 1]
}
}
Sound {
minFront 10
maxFront 100
minBack 10
maxBack 100
source DEF LATHESOUND AudioClip {
url "lathe.wav"
loop TRUE
}
}
]
}
DEF ROTTIME TimeSensor {
cycleInterval 0.5
loop TRUE
}
DEF ROTINT OrientationInterpolator {
key [0, 0.25, 0.5, 0.75, 1]
keyValue [-1 0 0 0, -1 0 0 1.57, -1 0 0 3.14, -1 0 0 4.71, -1 0 0 0]
}
###########################################################
#
# The floating panel
#
###########################################################
#The sensor to measure the viewers position and
#viewing direction
DEF PANELPROX ProximitySensor {
size 500 500 500
}
#This transform follows the viewer, so it appears to be static
DEF PANELTRANS Transform {
children [
Transform {
children [
########### RESET ##############
Transform {
children [
DEF RESETBUTTON TouchSensor {
}
Transform {
children DEF BUTTON Shape {
appearance USE STOCKAPPR
geometry Cylinder {
radius 2
height 14
}
}
rotation 0 0 1 1.5708
scale 0.2 0.2 0.2
}
]
translation -3 0 0
}
########### EXPORT ##############
Transform {
children [
DEF EXPORTBUTTON TouchSensor {
}
USE STOCK
]
translation 3 0 0
scale 0.2 0.2 0.2
}
########### Message ##############
DEF MSGTIMER TimeSensor {
cycleInterval 2
}
Shape {
appearance Appearance {
material Material {
diffuseColor 1 0.8 0
emissiveColor 1 0.8 0
}
}
geometry DEF MESSAGE Text {
maxExtent 1.9
fontStyle DEF BUTTONFONT FontStyle {
family "SANS"
size 0.5
justify ["MIDDLE", "MIDDLE"]
}
}
}
]
translation 0 -3.5 -10
}
]
}
###########################################################
#
# The Script, to construct the piece, and handle interaction
#
###########################################################
DEF SCRIPT Script {
field SFInt32 linSteps 42
field SFInt32 rotSteps 9
field SFFloat radius 1
field SFFloat width 14
field SFInt32 sparks 20
eventOut MFVec2f crossSection
eventOut MFVec3f spine
eventOut MFVec3f sparkCoord
eventOut MFInt32 sparkIndex
eventOut MFColor sparkColor
eventOut SFInt32 sparkChoice
eventOut SFTime sparkTimerRestart
eventOut SFTime toolSoundStart
eventOut SFTime toolSoundStop
eventIn SFBool sparkActive
eventIn SFFloat sparkFraction
eventIn SFVec3f getToolPosition
eventOut SFVec3f setToolPosition
eventOut SFVec3f setSensorOffset
eventIn SFTime stockTouched
eventOut SFBool doRotate
eventOut SFFloat rotFraction
eventOut SFTime startSound
eventOut SFTime stopSound
eventIn SFTime reset
eventIn SFTime export
eventIn SFBool overReset
eventIn SFBool overExport
eventIn SFBool overStock
eventIn SFBool overTool
eventIn SFBool msgActive
eventOut MFString message
eventOut SFTime msgTimerRestart
field SFVec2f last 0 3
field SFTime cutTime 0
url "vrmlscript:
function randomSparks() {
j = 0;
for (i = 1; i < sparks; i++) {
sparkCoord[i] = new SFVec3f(
Math.random() - 0.5,
Math.random() - 0.5,
1 + Math.random()
);
}
}
function initialize() {
spine = new MFVec3f();
crossSection = new MFVec2f();
//Create rotational Spine
step = 2 * Math.PI / rotSteps;
p = Math.PI / 2;
for (i = 0; i < rotSteps; i++) {
spine[i] = new SFVec3f(0, Math.cos(p), Math.sin(p));
p += step;
}
spine[rotSteps] = spine[0];
//Create CrossSection
crossSection[0] = new SFVec2f(-0.999, -0.5 * width);
for (i = 0; i < linSteps + 1; i++) {
crossSection[i+1] = new SFVec2f( radius,
(i * width / linSteps) - (0.5 * width));
}
crossSection[linSteps+2] = new SFVec2f(-0.999, 0.5 * width);
//Create Sparks
sparkCoord = new MFVec3f();
sparkIndex = new MFInt32();
sparkColor = new MFColor();
sparkCoord[0] = new SFVec3f(0, 0, 0);
sparkColor[0] = new SFColor(1, 1, 0.5);
for (i = 1, j = 0; i < sparks; i++) {
sparkIndex[j++] = 0;
sparkIndex[j++] = i;
sparkIndex[j++] = -1;
sparkColor[i] = new SFColor(
0.3+0.6*Math.random(),
0.2+0.6*Math.random(),
0);
}
randomSparks();
//Init last
last.x = Math.round(linSteps / 2);
setToolPosition = setSensorOffset = new SFVec3f( 0, -3, 0);
doRotate = TRUE;
}
function getToolPosition(pos, time) {
// Calculate hitpoint
center = Math.round( 0.5 * linSteps +
pos.x * linSteps / width) + 1;
dist = -pos.y;
val = crossSection[center];
cut = FALSE;
if (doRotate) {
// Rotating - Cut
if (Math.abs(center - last.x) <= 1) {
// Cut one slice
if (val.x + 1 > dist) {
val.x = dist - 1;
crossSection[center] = val;
cut = TRUE;
}
} else {
// Cut some slices - interpolate
if (center < last.x) {
start = center;
end = last.x - 1;
d = dist;
deltaD = (last.y - dist) / (end - start);
} else {
start = last.x + 1;
end = center;
d = last.y;
deltaD = (dist - last.y) / (end - start);
}
for ( i = start; i <= end; i++ ) {
val = crossSection[i];
if (val.x + 1 > d) {
val.x = d - 1;
crossSection[i] = val;
cut = TRUE;
}
d += deltaD;
}
}
} else {
// Not rotating - Collide
if (val.x + 1 > dist) pos.y = -(val.x + 1);
}
last.x = center;
last.y = dist;
setToolPosition = setSensorOffset = pos;
if (cut) {
randomSparks();
sparkTimerRestart = time;
toolSoundStart = time;
cutTime = time;
sparkChoice = 0;
}
}
function sparkActive(active, time)
{
// Switch off sparks and sounds only if
// timer wasn't retriggered
if (!active && time - cutTime >= 0.3) {
sparkChoice = -1;
toolSoundStop = time;
}
}
function sparkFraction(active)
{
randomSparks();
}
function setMessage(msg, time)
{
// Retrigger Messagetimer
msgTimerRestart = time;
message[0] = msg;
}
function overReset(isOver, time)
{
if (isOver) setMessage( 'Reset', time);
}
function overExport(isOver, time)
{
if (isOver) setMessage( 'Export', time);
}
function overStock(isOver, time)
{
if (isOver) setMessage( doRotate ? 'Stop' : 'Start', time);
}
function overTool(isOver, time)
{
if (isOver) setMessage( doRotate ? 'Cut' : 'Move', time);
}
function msgActive(active, time)
{
if (!active) setMessage( '', time);
}
function stockTouched(time)
{
rotFraction = 0;
doRotate = !doRotate;
if (doRotate) startSound = time; else stopSound = time;
overStock(true, time);
}
function reset(time)
{
initialize();
startSound = time;
}
function trim(value) {return Math.round(value * 100) / 100;}
function printSFVec2f(v) {return ''+trim(v[0])+' '+trim(v[1]);}
function printSFVec3f(v) {return printSFVec2f(v)+' '+trim(v[2]);}
function exportString() {
s = '#VRML V2.0 utf8 VirtualLathe
'+
'Shape {
'+
' appearance Appearance {
'+
' material Material {
'+
' diffuseColor 0.5 0.5 1
'+
' shininess 0.9
'+
' specularColor 0.5 0.5 1
'+
' }
'+
' }
'+
' geometry Extrusion {
'+
' beginCap FALSE
'+
' endCap FALSE
'+
' convex FALSE
'+
' ccw FALSE
'+
' creaseAngle 1
'+
' crossSection [';
for (i = 0; i < linSteps+2; i++)
s+= printSFVec2f(crossSection[i]) + ', ';
s+= printSFVec2f(crossSection[i]) + ']
';
s+= ' spine [';
for (i = 0; i < rotSteps; i++)
s+= printSFVec3f(spine[i]) + ', ';
s+= printSFVec3f(spine[i]) + ']
';
s+= ' }
';
s+= '}';
return s;
}
function export(time)
{
// XXX
// A kludge to make export work on at least two
// systems - Netscape with Cosmo 1.0 on SGI and Cosmo 2.0 on NT -
// without using EAI or stuff.
s = 'javascript: /***** Exported Model ******/ ';
s += 'w=window.open(\"\",\"export\",\"menubar=1,resizable=1,scrollbars=1,width=480,height=400\");';
s += 'd=w.document;';
s += 'd.open(\"text/html\");';
s += 'd.clear();';
s += 'd.write(\"
' + exportString() + '\");'; s += 'd.close();'; s += '\"Virtual Lathe Export: Please minimize this window\"'; url = new MFString(); url[0] = s; para = new MFString(); para[0] = 'target=temp'; Browser.loadURL(url, para); }" } ########################################################### # # The Routings # ########################################################### ROUTE SCRIPT.crossSection TO SHAPE.set_crossSection ROUTE SCRIPT.spine TO SHAPE.set_spine ROUTE SCRIPT.sparkCoord TO SPARKCOORD.set_point ROUTE SCRIPT.sparkIndex TO SPARKS.set_coordIndex ROUTE SCRIPT.sparkColor TO SPARKCOLOR.set_color ROUTE SCRIPT.sparkChoice TO SPARKSWITCH.set_whichChoice ROUTE SCRIPT.sparkTimerRestart TO SPARKTIMER.set_stopTime ROUTE SCRIPT.sparkTimerRestart TO SPARKTIMER.set_startTime ROUTE SPARKTIMER.isActive TO SCRIPT.sparkActive ROUTE SPARKTIMER.fraction_changed TO SCRIPT.sparkFraction ROUTE SCRIPT.toolSoundStart TO TOOLSOUND.set_startTime ROUTE SCRIPT.toolSoundStop TO TOOLSOUND.set_stopTime ROUTE TOOLSENSOR.translation_changed TO SCRIPT.getToolPosition ROUTE SCRIPT.setToolPosition TO TOOLTRANS.set_translation ROUTE SCRIPT.setSensorOffset TO TOOLSENSOR.set_offset ROUTE ROTTIME.fraction_changed TO ROTINT.set_fraction ROUTE ROTINT.value_changed TO ROTTRANS.set_rotation ROUTE SCRIPT.rotFraction TO ROTINT.set_fraction ROUTE ROTTOUCH.touchTime TO SCRIPT.stockTouched ROUTE SCRIPT.doRotate TO ROTTIME.set_enabled ROUTE SCRIPT.startSound TO LATHESOUND.set_startTime ROUTE SCRIPT.stopSound TO LATHESOUND.set_stopTime ROUTE RESETBUTTON.touchTime TO SCRIPT.reset ROUTE EXPORTBUTTON.touchTime TO SCRIPT.export ROUTE RESETBUTTON.isOver TO SCRIPT.overReset ROUTE EXPORTBUTTON.isOver TO SCRIPT.overExport ROUTE ROTTOUCH.isOver TO SCRIPT.overStock ROUTE TOOLTOUCH.isOver TO SCRIPT.overTool ROUTE SCRIPT.message TO MESSAGE.set_string ROUTE SCRIPT.msgTimerRestart TO MSGTIMER.set_stopTime ROUTE SCRIPT.msgTimerRestart TO MSGTIMER.set_startTime ROUTE MSGTIMER.isActive TO SCRIPT.msgActive ROUTE PANELPROX.position_changed TO PANELTRANS.set_translation ROUTE PANELPROX.orientation_changed TO PANELTRANS.set_rotation