====== A list of examples ======
Some examples of multi scale usage (mostly syntax and prof of concept):
Well it is a copy of their content because I cannot upload rgg files. deal with it.
They are not ordered, they mostly come from Ong PhD.
Files 4, 5, 6 are the most simple ones (if you want to get started) and File 8 is the most complete.
====== ======
===== File 1 =====
/* ex_msc1.rgg: simple example with 3 scales */
scaleclass SPlant;
scaleclass SAx;
scaleclass SOrgan;
module Plant extends Sphere
// {{ setLayer(2); }}
;
module Ax extends Cylinder
//{{ setLayer(1); }}
;
module B; /* bud of main axis */
module C; /* bud of lateral axis */
protected void init()
[
@256; TypeAxiom, s:SRoot ==> p:Plant /> a:Ax /> {# b:B c:C f:F0 rh:RH ru:RU l:L d:D #},
s /> sp:SPlant /> sa:SAx /> so:SOrgan, sp +> p, sa +> a, so +> {# b c f rh ru l d #};
Axiom ==> p:Plant a:Ax L(10) D(0.5) B
{ p[radius] = 0.1; a[length] = 0.2; };
]
public void run()
[
B ==> F0 RH(180) [ RU(45) a:Ax C ] B
{ a[length] = 0.2; };
C ==> F0 C;
p:Plant ::> p[radius] += 5;
a:Ax ::> a[length] += 10;
]
===== File 2 =====
/* ex_msc2b.rgg: simple example with 2 scales,
implemented with type graph and s-o-s */
scaleclass SGU;
scaleclass SOrgan;
module A;
module GU extends Cylinder
{{ setLayer(1); }};
module B; /* bud of main axis */
protected void init()
[
@256; TypeAxiom, s:SRoot ==> {# g:GU a:A #} /> {# b:B f:F #} ,
s /> sg:SGU /> so:SOrgan,
sg +> g, sg +> a, so +> {# b f #};
Axiom ==> A;
]
public void run()
[
A ==> g:GU /> B [ <+ ^ ]
{ g[length] = 0.2; };
(* v:GU /> *) B ==> g:GU [ < v ] F(10) F(10) B
{ g[length] = 20; };
]
===== File 3 =====
scaleclass STree(super.rgg);
scaleclass SAxis(super.rgg);
scaleclass SOrgan(super.rgg);
//modules at tree scale
module Trunk(super.length) extends F;
module Crown(super.length, super.baseRadius, super.topRadius)
extends Frustum;
module Tree(float ht, float htbc, float cw, float htcw)
//height(ht), height to base of crown(htbc), crown width(cw),
//height at max crown width(htcw)
==> Trunk(htbc) Crown(htcw-htbc,cw/5.0,cw) Crown(ht-htcw,cw,cw/5.0);
//modules at axis scale
module Axis(float length, float diameter, int guCount, int age, int order);
//modules at organ scale
module GU(int order, super.length, super.diameter, int rank) extends F
{
//variables for bending
float mass = 0.5; // kg - mass of branch section marked by this GU
Point3d pos = new Point3d();
// 3d coords - location during bending simulation
// (independent of scene graph location)
Point3d dPos = new Point3d();
// 3d coords - delta of location (vector) during bending simulation
Point3d vel = new Point3d();
// cm/s - velocity in 3 directions (particle on the left,
//particle on the right, gravity)
}
module Bud(int order, int type, int rank) extends Sphere(0.1);
//observer signal code - "extrapolate" tree scale from organ scale developments
int SIGNAL_TREE1=0;
int SIGNAL_AXIS1=1;
int SIGNAL_ORGAN1=2;
//structural parameters
static int GUType_l = 0; //long
static int GUType_m = 1; //medium
static int GUType_s = 2; //short
static int GUType_f = 3; //floral
static float GULenMin[] = {20,5,1,1};
//min length for long,med,short,flowering GUs
static float GULenMax[] = {30,20,5,5};
//max length for long,med,short,flowering GUs
static float GUFSMMin[][] = {{0.0,0.5,0,0.9},{0,0.0,0.4,0.8},
{0,0,0.0,0.5},{0,0.0,0.5,0}};
static float GUFSMMax[][] = {{0.5,0.9,0,1.0},{0,0.4,0.8,1.0},
{0,0,0.5,1.0},{0,0.5,1.0,0}};
static float GUDiaInit = 0.3;
static int AxisAgeMortality = 30;
//bending mechanism - variables used for the simulation of bending on one axis
static int ParticleCount = 3;
static int SpringCount = ParticleCount-1;
static GU Particles[] = new GU[ParticleCount];
static float Springs[] = new float[SpringCount];
static float Frame_RATE = 1.0/30.0; // s/step
static float Particle_MASS = 0.5;
static float Particle_VELOCITY = 0;
static float Spring_STIFFNESS = 50.0; //kg/s^2
static float Spring_DAMPING = 0.5; //kg/s
static float Gravity_ACCEL = -980.0; //m/s^2
static float Gravity_VELOCITY = Gravity_ACCEL * Frame_RATE; //m/s^2
static Point3d Gravity_DISP = new Point3d(0,0,
Gravity_VELOCITY * Frame_RATE); //m/s^2
static int LEFT=0;
static int RIGHT=1;
static int GRAVITY=2;
protected void init ()
[
//Construct structure-of-scales (sos) and type graph
@256; TypeAxiom, sr:SRoot ==>> {# t:Tree tr:Trunk c:Crown #} /> {# a:Axis #} /> {# gu:GU b:Bud rh:RH ru:RU #}
//structure-of-scales (sos) nodes
, sr /> st:STree(this) /> sa:SAxis(this) /> so:SOrgan(this)
, st +> {# t tr c #}, sa +> {# a #},so +> {# gu b rh ru #}
//connecting s-o-s nodes to type graph nodes
{
st.observe(so,SIGNAL_TREE1, "runTree");
//register tree scale dependency on organ scale
sa.observe(so,SIGNAL_AXIS1, "runAxis");
//register axis scale dependency on organ scale
so.observe(sa,SIGNAL_ORGAN1, "runOrgan");
//register organ scale dependency on axis scale
};
//Construct initial instanced graph
Axiom ==> [t:Tree][a:Axis(0,0,0,0,0)][b:Bud(0,0,0)], t /> a /> b;
]
public void run ()
[
//execute rules that develop the tree's organs
Bud(order,type,rank), (order<=1) ==>
{
int typeNew = nextGUType(type);
float lenNew1 = random(GULenMin[typeNew],GULenMax[typeNew]);
float lenNew2 = random(GULenMin[typeNew],GULenMax[typeNew]);
}
GU(order, lenNew1,GUDiaInit,rank)
if(typeNew==GUType_f)(RH(137) [Axis(0,GUDiaInit,0,0,
order+1) RU(40) Bud(order+1,type,0)])
GU(order,lenNew2,GUDiaInit,rank+1) Bud(order,typeNew,rank+2);
{derive();}
//notify macro scales to extrapolate development
//from fine scale developments
@256; so:SOrgan ::> {so.notify(SIGNAL_TREE1);}
@256; so:SOrgan ::> {so.notify(SIGNAL_AXIS1);}
]
/**
* Tree scale - update height, crown width, etc. according to
organ scale developments
*/
protected void runTree()
[
{println("runTree");}
{
float ht=0; //new height of tree
float htbc=Float.MAX_VALUE; //new height to base of crown of tree
float cw=0; //new crown width of tree
float cwtemp=0; //temp variable containing distance to trunk of a particular GU.
float htcw=0;
htbc = min(location((* GU(order,len,dia,rank), (order > 0) *)).z);
if(htbc <0.1)
println("strange");
}
//get new macro scale values (height, crown width, etc.) from fine scale
b:Bud ::> {
//max GU height
Point3d loc = endlocation(b);
if(loc.z > ht)
ht=loc.z;
//distance to origin
cwtemp = Math.sqrt((loc.x*loc.x)+(loc.y*loc.y));
if(cwtemp > cw){
cw = cwtemp;
htcw = loc.z;
}
}
//update macro scale (tree) with new values
t:Tree ::> {
t[ht] = ht;
t[htbc] = htbc;
t[cw] = cw;
t[htcw] = htcw;
}
]
/**
* Axis scale - dependent on organ scale developments to update
length, diameter, bending
*/
protected void runAxis()
[
//{println("runAxis");}
//update length,diameter,GU count of axes
a:Axis ::> {
a[length]=sum((* a GU *).length);
a[diameter]=diaFromLen(a[length]);
a[guCount] = (int)count((* a GU *));
a[age]++;}
//remove old axes - mortality
a:Axis, (a[age]>AxisAgeMortality && a[order]==1) ::>
{killAxis(a);} //note: recursive is killing is necessary
//bending simulation - separate call from length,diameter
//updates to avoid computing bending of dead branches
a:Axis, ((a[guCount] >= ParticleCount) && (a[order]==1) ) ::> {runAxisBend(a);}
sa:SAxis ::> {sa.notify(SIGNAL_ORGAN1);}
//notify organ scale updates based ona axis changes
]
/**
* Axis scale - simulates bending of an axis using selected points
(GUs) along axis
*/
private void runAxisBend(Axis a)
{
//select GUs according to rank along axes (of order 1) 0-----1-----2
for(int i=0; i {
Particles[i]=g;
//println(g[rank]);
//reset original position, velocity and delta position in particles
Particles[i].vel.x = 0; Particles[i].vel.y = 0;
Particles[i].vel.z = 0;
Particles[i].dPos.x = 0; Particles[i].dPos.y = 0;
Particles[i].dPos.z = 0;
Point3d l = location(g);
Particles[i].pos.x = l.x; Particles[i].pos.y = l.y;
Particles[i].pos.z = l.z;
//println(Particles[i].pos);
}
]
}
//update mass for each particle //KIV
//assume a spring connects each pair of consecutive particle
//update lengths of springs according to distance between them
for(int i=0; i> ^ Translate(Particles[i].pos.x, Particles[i].pos.y,
Particles[i].pos.z) Sphere(1.0);
]
}
//update RU nodes in organ scale to match simulated bend
}
/**
* Axis scale - Computes displacement of selected GU towards another.
*/
private Point3d displacementTowards(GU a, GU b, float springLen,
int velIndexA, int velIndexB)
{
//Point3d loca = location(a);
Point3d loca = new Point3d(a.pos);
//Point3d locb = location(b);
Point3d locb = new Point3d(b.pos);
//vector from a to b
Point3d ab = new Point3d(locb);
ab.sub(loca);
//vector magnitude
float vLen = loca.distance(locb);
//unit vector from a to b
Point3d abUnit = new Point3d(ab);
abUnit.x = abUnit.x/vLen;
abUnit.y = abUnit.y/vLen;
abUnit.z = abUnit.z/vLen;
//compute force (spring) of a towards b
float fSpring = Spring_STIFFNESS * (vLen-springLen);
//compute force (damping) of a towards b
float velab =
(velIndexA==LEFT)?a[vel].x:((velIndexA==RIGHT)?a[vel].y:a[vel].z);
float velba =
(velIndexB==LEFT)?b[vel].x:((velIndexB==RIGHT)?b[vel].y:b[vel].z);
float fDamp = Spring_DAMPING * (-velba-velab);
//compute acceleration (m/s^2) of pa towards pb using F=ma
float acc = (fSpring+fDamp)/a[mass];
//println("accel: " + acc);
//compute velocity (m/s) of pa towards pb -
//stored in member variable of pa, using acceleration
float vel = acc * Frame_RATE;
if(velIndexA==LEFT)
a[vel].x = vel;
else if(velIndexA==RIGHT)
a[vel].y = vel;
else
a[vel].z = vel;
//compute displacement using velocity
float disp = vel * Frame_RATE;
abUnit.x *= disp;
abUnit.y *= disp;
abUnit.z *= disp;
return abUnit;
}
/**
* Axis scale - recursive killing method
*/
private void killAxis(Axis a)
[
a [b:Axis] ::> {killAxis(b);} //kill higher order ones first
a /> Node ==>> ;
]
/**
* Organ scale method. Updates diameters of GUs (tapering)
according to diameter at axis scale.
*/
protected void runOrgan()
[
a:Axis g:GU ::> {g[diameter]= GUDiaInit +
(1.0f-((float)(g[rank])/(float)a[guCount]))*
(a[diameter]-GUDiaInit);}
]
/**
* Returns next GU type based on current GU type and
FSM transition table
*/
private int nextGUType(int typeCurr)
{
float r = random(0.0,1.0);
if((r >= GUFSMMin[typeCurr][GUType_l])&&
(r <= GUFSMMax[typeCurr][GUType_l]))
return GUType_l;
else if((r >= GUFSMMin[typeCurr][GUType_m])&&
(r <= GUFSMMax[typeCurr][GUType_m]))
return GUType_m;
else if((r >= GUFSMMin[typeCurr][GUType_s])&&
(r <= GUFSMMax[typeCurr][GUType_s]))
return GUType_s;
else
return GUType_f;
}
/**
* Returns diameter in cm given height or length in cm
*/
private float diaFromLen(float len)
{
return Math.pow((len/100.0f),1.2);
}
===== File 4 =====
scaleclass ScaleA;
scaleclass ScaleB;
module A;
module B;
protected void init ()
[
@256; TypeAxiom, s:SRoot ==> a:A /> b:B, s /> sa:ScaleA /> sb:ScaleB, sa [a], sb [b];
Axiom ==> [a:A] b:B, a /> b;
]
public void run ()
[
B ==> B B;
]
===== File 5 =====
scaleclass ScaleTree;
scaleclass ScaleOrgan;
module Tree;
module Bud;
module Internode;
protected void init ()
[
@256; TypeAxiom, s:SRoot ==> t:Tree /> {# b:Bud i:Internode #},
s /> st:ScaleTree /> so:ScaleOrgan,
st +> t,
so +> {# b i #};
Axiom ==> [t:Tree] b:Bud, t /> b;
]
public void run ()
[
Bud ==> Internode Bud;
]
===== File 6 =====
scaleclass ScaleTree;
scaleclass ScaleOrgan;
module Tree;
module Bud extends Sphere(0.1);
module Internode extends F;
protected void init ()
[
@256; TypeAxiom, s:SRoot ==> t:Tree /> {# b:Bud i:Internode #},
s /> st:ScaleTree /> so:ScaleOrgan,
st +> t,
so +> {# b i #};
Axiom ==> [t:Tree] b:Bud, t /> b;
]
public void run ()
[
Bud ==> Internode Bud;
]
===== File 7 =====
module A extends Cylinder(3, 1);
module B extends Cylinder(3, 0.5);
module C extends Sphere(2);
scaleclass S1;
scaleclass S2;
protected void init()
[
@256; TypeAxiom, s:SRoot ==> c:C /> {# a:A b:B #},
s /> s1:S1 /> s2:S2 ,
s2 +> {# a b #}, s1 +> c;
Axiom ==> A;
]
public void run()
[
A ==> c:C A, B c;
]
===== File 8 =====
/* treebend2.rgg, W.K., 22.06.2015;
derived from: treebend.rgg;
branchbend.rgg; parts from Yongzhi Ong */
const float SEG_LEN = 10.0;
const float CFORCE = 0.0002;
const float P_FRUIT = 0.5;
const float OFFSET = 0.4;
const float rIncr = 0.5;
const float initR = 2.0;
const float fsize = 15;
const float lsize = 20;
const int axisMortAge = 10;
static float tMatrix[][] =
{{0.2, 0.2, 0.3, 0.3},
{0.0, 0.0, 1.0, 0.0},
{0.0, 0.0, 0.0, 1.0},
{1.0, 0.0, 0.0, 0.0}};
static float guLength[] =
{ 40.0, 20.0, 5.0, 35.0 };
scaleclass STree(super.rgg);
//scaleclass SAxis(super.rgg);
//scaleclass SOrgan(super.rgg);
//module STree(RGG r);
module SAxis(RGG r);
module SOrgan(RGG r);
module GU(super.length, super.baseRadius, super.topRadius,
int rank, int state, Shader color)
extends Frustum.(setShader(color), setTransform(0, 0, -OFFSET))
{ float tippos; };
/* state: 0=long, 1=medium, 2=short, 3=floral */
module Leaf(float length, float width, int age)
==> F(6, 0.5, 2) Parallelogram(length, width).(setShader(GREEN));
module FBud(int rank, int age)
{ float pos; };
module Fruit(float size, int rank)
==> RG F(12+size, 2, 6) Sphere(size).(setShader(RED));
module Bud(int rank, int state) extends Sphere(2).(setShader(GREEN));
module TBud(int rank) extends Sphere(5);
module Axis
{
float length;
int nbSeg;
int age;
};
module AxisBase;
module AxisBud(int rank) extends Sphere(4)
{{ setShader(YELLOW); setLayer(1); }};
module AGU(super.length, super.baseRadius, super.topRadius,
int rank, Shader color)
extends Frustum.(setShader(color), setTransform(0, 0, -OFFSET),
setLayer(1));
module ARH(super.angle) extends RH;
module ARU(super.angle) extends RU;
module Rx;
module Load(float size, int index) ==>
b:Box(size, size, size)
{{ b.setShader(BLUE); b.setLayer(1); }};
module Segment(int index) extends Cylinder(SEG_LEN, 1.5)
{{ setShader(GRAY); setLayer(1); }};
module RBend(super.argument, int index) extends RV(argument);
module Trunk(super.length) extends F(length, 18, 6)
{{ setLayer(2); }};
module Crownpart(super.length, super.baseRadius, super.topRadius)
extends Frustum
{{ setLayer(2); setShader(EGA_6); }};
module Tree(float ht, float htbc, float cw, float htcw)
==> Trunk(htbc) Crownpart(htcw-htbc, cw/5.0, cw)
Crownpart(ht-htcw, cw, cw/5.0);
protected Shader coloration(int state)
{
if (state == 0) return EGA_4;
if (state == 1) return PINK;
if (state == 2) return ORANGE;
if (state == 3) return MAGENTA;
return BLACK;
}
public int segIndex(Axis a, float p)
{
int k = 0;
if (a.length > 0)
k = (int) Math.floor(p*((float) a.nbSeg) / a.length);
if (k >= a.nbSeg)
k = a.nbSeg - 1;
return k;
}
public Segment findSeg(Axis a, float p)
{
int k;
Segment res;
k = segIndex(a, p);
if (! empty((* a -descendants-> s:Segment, (s[index] == k) *)) )
res = first((* a -descendants-> s:Segment, (s[index] == k) *));
else
res = new Segment(-1);
return res;
}
protected void init()
[
@256; TypeAxiom, sr:SRoot ==> {# t:Tree tr:Trunk cp:Crownpart #} />
{# a:Axis abu:AxisBud agu:AGU l:Load s:Segment rb:RBend bo:Box arh:ARH aru:ARU #} />
{# ab:AxisBase gu:GU lf:Leaf fb:FBud f:Fruit b:Bud tb:TBud rh:RH ru:RU rp:RP rx:Rx ff:F pa:Parallelogram rg:RG sp:Sphere #} ,
sr /> st:STree(this) /> sa:SAxis(this) /> so:SOrgan(this),
st +> {# t tr cp #},
sa +> {# a abu agu l s rb bo arh aru #},
so +> {# ab gu lf fb f b tb rh ru rp rx ff pa rg sp #}
{
// sa.observe(so, 1, "bend");
//so.observe(sa, 2, "adjust");
// st.observe(so, 3, "runTree");
};
Axiom ==> [ tb:TBud(0) ] [ abu:AxisBud(0) ] [ t:Tree(0, 0, 0, 0) ],
t /> abu /> tb;
]
public void run()
{
secondary(); derive();
growGU(); derive();
makeAxis(); derive();
growFruits(); derive();
[
// @256; so:SOrgan ::> so.notify(1);
//@256; so:SOrgan ::> so.notify(3);
]
}
protected void growGU()
[
AxisBud(rank) TBud ==> {float angle = random(-4, 4);}
AGU(50.0, initR+rIncr, initR, rank, YELLOW)
GU(50.0, initR+rIncr, initR, rank, 4, LIGHT_GRAY)
ARH(137) RH(137) ARU(angle) RU(angle)
[ ARU(70) RU(70) a:Axis AxisBase
{ a.length = 0.0; a.nbSeg = 0; a.age = 0; }
Bud(0, 0) ]
AxisBud(rank+1) TBud(rank+1);
(* a:Axis /> AxisBase -descendants-> *) Bud(i, tp) ==>
Rx if (tp == 3) ( [ f:FBud(i, 0) { f.pos = a.length; } ] )
g:GU(guLength[tp]+OFFSET, initR+rIncr, initR, i,
tp, coloration(tp))
{ a.length += guLength[tp];
g.tippos = a.length; }
[ RH(i*137) RU(-60) Leaf(25, 20, 0) ]
Bud(i+1, distribution(tMatrix[tp]));
]
protected void makeAxis()
[
a:Axis ==> a
{
a.age++;
a.nbSeg = (int) Math.floor(a.length / SEG_LEN);
if (a.nbSeg <= 0) a.nbSeg = 1;
}
[
/* Translate(100, 0, 0) preliminary */
for (int j=0; j < a.nbSeg; j++)
( RBend(0, j) Segment(j) )
]; /* branch prelim. */
]
protected void growFruits()
[
(* a:Axis /> AxisBase -descendants-> *) f:FBud(i, age) ==> fn:FBud(i, age+1)
{ fn.pos = f.pos; }
if ((age==0) || probability(P_FRUIT))
( Fruit(fsize, 0),
findSeg(a, f.pos) +> Load(lsize, segIndex(a, f.pos)) );
]
protected void secondary()
[
a:Axis, (a.age >= axisMortAge) ==>> ;
Fruit ==>> ;
g:GU(l, br, tr, i, tp, c) ==> gn:GU(l, br+rIncr, tr+rIncr, i, tp, c)
{ gn.tippos = g.tippos; };
Leaf(l, w, age), (age < 2) ==> Leaf(l, w, age+1);
Leaf(l, w, age), (age >= 2) ==> ;
Segment ==>> ;
RBend ==>> ;
RP ==> Rx;
]
public void bend()
[
r:RBend(s, i) ==>
RBend(s + CFORCE * sum( (* r -descendants-> l:Load *)[size]
* (l[index] - r[index])), i);
//sa:SAxis ::> sa.notify(2); /* notify organ scale adjustment */
]
public void adjust()
{
for (applyUntilFinished())
[ // begin workaround
(* a:Axis /> AxisBase *) Rx g:GU ==>
RP(endlocation(findSeg(a, g.tippos)), 1.0) g;
(* a:Axis /> AxisBase -descendants-> RP GU *) Rx [ fb:FBud f:Fruit ] g:GU ==>
RP(endlocation(findSeg(a, g.tippos)), 1.0) [ fb f ] g;
(* a:Axis /> AxisBase -descendants-> RP GU *) Rx g:GU ==>
RP(endlocation(findSeg(a, g.tippos)), 1.0) g;
] // end workaround
/* replace the workaround by the following version when bug is removed:
[
(* a:Axis AxisBase *) Rx (* g:GU *) ==>
RP(endlocation(findSeg(a, g.tippos)), 1.0);
(* a:Axis -descendants-> RP GU *) Rx (* g:GU *) ==>
RP(endlocation(findSeg(a, g.tippos)), 1.0);
]
*/
}
public void runTree()
[
{
float ht = 0; //new height of tree
float htbc = Float.MAX_VALUE; //new height to base of crown of tree
float cw = 0; //new crown width of tree
float cwtemp = 0; //temp variable containing distance to trunk of a particular GU
float htcw = 0; //heigth at maximal crown width
htbc = min(location((* GU(l, br, tr, i, tp, c), (tp != 4) *)).z);
/* if(htbc < 0.1) println("strange"); */
}
//get new macro scale values (height, crown width, etc.) from fine scale
tb:TBud ::> { ht = endlocation(tb).z; }
b:Bud ::> { //distance to origin
Point3d loc = endlocation(b);
cwtemp = Math.sqrt((loc.x*loc.x)+(loc.y*loc.y));
if(cwtemp > cw)
{ cw = cwtemp; htcw = loc.z; }
}
//update macro scale (tree) with new values
t:Tree ::> { t[ht] = ht;
t[htbc] = htbc;
t[cw] = cw;
t[htcw] = htcw; }
]