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.
/* 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; ]
/* 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; }; ]
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<ParticleCount;++i) { int posAlongAxis; if(i==0) posAlongAxis = 0; else if(i==ParticleCount-1) posAlongAxis = a.guCount-1; else{ float ratioAlongAxis = (float)i/(float)(ParticleCount-1); posAlongAxis = (int)(ratioAlongAxis * (a.guCount-1)); } [ a g:GU, (g[rank]==posAlongAxis) ::> { 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<SpringCount;++i) { Springs[i] = Particles[i].pos.distance(Particles[i+1].pos); } //simulate bending for one second (upscaling is done by simply //assuming the one second displacement is for a year) //for each particle for(int i=0; i<ParticleCount;++i) { //compute displacement towards left particle if(i!=0) { Point3d d = displacementTowards(Particles[i], Particles[i-1], Springs[i-1],LEFT,RIGHT); Particles[i].dPos.add(d); //println(Particles[i].dPos); } //compute displacement towards right particle if(i<ParticleCount) { Point3d d = displacementTowards(Particles[i], Particles[i+1], Springs[i],RIGHT,LEFT); Particles[i].dPos.add(d); //println(Particles[i].dPos); } //compute displacement due to gravity Particles[i].dPos.add(Gravity_DISP); } //update positions of all particles for(int i=0; i<ParticleCount;++i) { Particles[i].pos.add(Particles[i].dPos); [ ==>> ^ 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); }
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; ]
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; ]
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; ]
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; ]
/* 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; } ]