import remixlab.proscene.*;
PFont font;
Scene scene;
InteractiveFrame repere1, repere2, plan1, plan2, dragueur1, dragueur2, frameM, repere3;
WorldConstraint rotx;
LocalConstraint pivot;
PVector or, n1, n2, n0, pointM, pointM1, pointM2, pointM3, intersec, axe1, axe2, axe3;
float lon, arc1, arc2, arc3;
Orienteur orient1,orient2,orient0;
void setup() {
size(850, 850, P3D);
scene=new Scene(this);
scene.setGridIsDrawn(false);
lon=400;
or=new PVector(0, 0, 0);
n1=new PVector();
n2=new PVector();
n0=new PVector();
pointM=new PVector(-120, -120, 300);
pointM1=new PVector();
pointM2=new PVector();
pointM3=new PVector();
axe1=new PVector();
axe2=new PVector();
axe3=new PVector();
orient1=new Orienteur();
orient2=new Orienteur();
orient0=new Orienteur();
dragueur1=new InteractiveFrame(scene);
dragueur2=new InteractiveFrame(scene);
repere1=new InteractiveFrame(scene);
repere2=new InteractiveFrame(scene);
repere3=new InteractiveFrame(scene);
plan1=new InteractiveFrame(scene);
plan2=new InteractiveFrame(scene);
frameM=new InteractiveFrame(scene);
plan1.setReferenceFrame(repere1);
plan2.setReferenceFrame(repere2);
pivot=new LocalConstraint();
pivot.setTranslationConstraint(AxisPlaneConstraint.Type.FORBIDDEN, new PVector(0, 0, 0));
pivot.setRotationConstraint(AxisPlaneConstraint.Type.AXIS, new PVector(0, 0, 1));
rotx=new WorldConstraint();
rotx.setTranslationConstraint(AxisPlaneConstraint.Type.FREE, new PVector(0, 0, 0));
rotx.setRotationConstraint(AxisPlaneConstraint.Type.FREE, new PVector(0, 0, 0));
//placements
dragueur1.setPosition(new PVector(0, -200, 420));
dragueur2.setPosition(new PVector(0, 200, 420));
repere1.setOrientation(new Quaternion(new PVector(1, 0, 0), -PI/4));
repere1.setPosition(new PVector(0, 0, 0));
plan1.setRotation(new Quaternion(new PVector(0, 0, 1), -PI/5));
plan1.setTranslation(new PVector(0, 0, 0));
frameM.setPosition(pointM);
repere2.setOrientation(new Quaternion(new PVector(1, 0, 0), PI/6.0));
repere2.setPosition(new PVector(0, 0, 0));
plan2.setRotation(new Quaternion(new PVector(0, 0, 1), PI/5));
plan2.setTranslation(new PVector(0, 0, 0));
plan1.setConstraint(pivot);
plan2.setConstraint(pivot);
font = loadFont("SansSerif.plain-48.vlw");
scene.camera().setPosition(new PVector(0, 0, 900));
directionalLight(0,0,55,1,0.2,-1);
directionalLight(55,0,0,0,0,-1);
directionalLight(0,25,0,-1,0,1);
}
void draw() {
background(#333355);
textFont(font, 12);
//directionalLight(195, 195, 235, 1, 0.2, -1);
directionalLight(195, 195, 235, -0.3, -0.2, -0.4);
// directionalLight(185, 185, 235, 0, 0, -1);
ambientLight(180, 150, 150);
pushMatrix();
frameM.applyTransformation();
fill(255, 255, 0);
noStroke();
sphere(8);
fill(255);
popMatrix();
pushMatrix();
dragueur1.applyTransformation();
fill(255, 0, 0);
noStroke();
sphere(8);
fill(255);
popMatrix();
pushMatrix();
dragueur2.applyTransformation();
fill(255, 0, 0);
noStroke();
sphere(8);
fill(255);
popMatrix();
PVector w= dragueur1.position().get();
w.normalize();
axe1=w.get();
w.mult(lon);
repere1.setPosition(w);
PVector w1= dragueur2.position().get();
w1.normalize();
axe2=w1.get();
w1.mult(lon);
repere2.setPosition(w1);
n0=w.cross(w1);
n0.normalize();
w.get().normalize();
w1.get().normalize();
repere1.setZAxis(w);
repere1.setXAxis(n0);
repere2.setZAxis(w1);
repere2.setXAxis(n0);
ligne(or, plan1.position());
ligne(or, plan2.position());
pushMatrix();
repere1.applyTransformation();
// scene.drawAxis(50);
pushMatrix();
plan1.applyTransformation();
fill(255, 255, 0);
box(10);
popMatrix();
popMatrix();
pushMatrix();
repere2.applyTransformation();
// scene.drawAxis(50);
pushMatrix();
plan2.applyTransformation();
fill(255, 255, 0);
box(10);
popMatrix();
popMatrix();
n1=plan1.inverseTransformOf(new PVector(0, lon, 0));
n2=plan2.inverseTransformOf(new PVector(0, lon, 0));
//DESSINER LES 3 PLANS
dessinePlan(repere1.position(), repere2.position(), 50, 50, 135);
intersec= intersection();
dessinePlan(intersec, repere1.position(), 105, 50, 50);
dessinePlan(intersec, repere2.position(), 40, 135, 55);
pointM=frameM.position();
pointM1=calculSym(pointM, n1);
pointM2=calculSym(pointM1, n0);
pointM3=calculSym(pointM1, n2);
PVector proj1=projectionSurDroite(pointM1, axe1);
PVector proj2=projectionSurDroite(pointM1, axe2);
PVector proj3=projectionSurDroite(pointM1, axe3);
repere3.setPosition(proj3);
triangle3D(proj1, pointM1, pointM, 130, 170, 100);
triangle3D(proj1, pointM1, pointM2, 115, 160, 100);
triangle3D(proj2, pointM1, pointM2, 180, 185, 80);
triangle3D(proj2, pointM1, pointM3, 185, 180, 80);
triangle3D(proj3, pointM1, pointM, 70, 90, 135);
triangle3D(proj3, pointM1, pointM3, 75, 85, 135);
orient1.place( repere1.position(), intersec,n1);
orient2.place( repere2.position(), intersec,n2);
orient0.place( repere2.position(),repere1.position(),n0);
orient1.draw();
orient2.draw();
orient0.draw();
stroke(0, 255, 0);
strokeWeight(2);
calculerLesArcs();
//cercle1 --------------------------------------------------------------
PVector tr=repere1.transformOf(comb(1, proj1, -1, repere1.position()));
PVector om=repere1.coordinatesOf(pointM);
float alph=acos(om.x/sqrt(om.x*om.x+om.y*om.y));
if (om.y<0)alph=-alph;
float ra=(comb(1, proj1, -1, pointM)).mag();
pushMatrix();
repere1.applyTransformation();
translate(tr.x, tr.y, tr.z);
stroke(255,0,0);
fill(140, 130, 130,250);
ellipse(0, 0, 2.0*ra, 2.0*ra);
rotateZ(alph);
dessinerArc(arc1, color(255, 0, 0), ra);
popMatrix();
//cercle2----------------------------------------------------------------
tr=repere2.transformOf(comb(1, proj2, -1, repere2.position()));
om=repere2.coordinatesOf(pointM2);
ra=(comb(1, proj2, -1, pointM1)).mag();
alph=acos(om.x/sqrt(om.x*om.x+om.y*om.y));
if (om.y<0)alph=-alph;
pushMatrix();
repere2.applyTransformation();
translate(tr.x, tr.y, tr.z);
stroke(0,0,255);
fill(150,150,180,250);
ellipse(0, 0, 2.0*ra, 2.0*ra);
rotateZ(alph);
dessinerArc(arc2, color(0, 0, 255), ra);
popMatrix();
//cercle3----------------------------------------------------------------
tr=repere3.transformOf(comb(1, proj3, -1, repere3.position()));
om=repere3.coordinatesOf(pointM);
ra=((comb(1, proj3, -1, pointM)).mag());
alph=acos(om.x/sqrt(om.x*om.x+om.y*om.y));
if (om.y<0)alph=-alph;
pushMatrix();
repere3.applyTransformation();
stroke(0,255,0);
fill(130,180,130,250);
ellipse(0, 0, 2.0*ra, 2.0*ra);
rotateZ(alph);
dessinerArc(arc3, color( 0, 255, 0), ra);
popMatrix();//--------------------------------------------------------------
strokeWeight(1);
afficherLettres();
}
void dessinePlan(PVector a, PVector b, int c, int d, int e) {
ligne(a, b);
beginShape();
fill(c, d*0.7, e);
vertex(a.x, a.y, a.z);
fill(c*0.8, d, e);
vertex(0, 0, 0);
fill(c, d, e*0.7);
vertex(b.x, b.y, b.z);
endShape();
}
PVector intersection() {
PVector iter=n1.cross(n2);
iter.normalize();
axe3=iter.get();
repere3.setZAxis(iter);
iter.mult(lon);
line(0, 0, 0, iter.x, iter.y, iter.z);
dessinePlan(iter, plan1.inverseCoordinatesOf(new PVector(0, 0, 0)), 185, 80, 100);
dessinePlan(iter, plan2.inverseCoordinatesOf(new PVector(0, 0, 0)), 40, 255, 55);
return iter;
}
void afficherLettres() {
fill(255);
// textMode(SCREEN);
afficherL("M0", frameM.position());
afficherL("M1", pointM1);
afficherL("M2", pointM2);
afficherL("M3", pointM3);
afficherL("O", or);
afficherL(" quaternion q1", repere1.position());
afficherL(" quaternion q2", repere2.position());
afficherL(" quaternion q2*q1", intersec);
}
void calculerLesArcs() {
arc1=calculAngle(orient1.vorient, orient0.vorient, axe1);
arc2=calculAngle(orient0.vorient, orient2.vorient, axe2);
arc3=calculAngle(orient1.vorient, orient2.vorient, axe3);
}
float calculAngle(PVector uu, PVector vv, PVector nor) {
PVector u=uu.get();
u.normalize();
PVector v=vv.get();
v.normalize();
float rep=acos(u.dot(v));
float si=nor.dot(uu.cross(vv));
if (si<0) rep=-rep;
return rep;
}
class Orienteur {
PVector vorient;
InteractiveFrame repere;
boolean estChange;
color col1=color(0,255,255);
color col2=color(255,0,255);
int facteur;
Orienteur() {
vorient=new PVector();
repere=new InteractiveFrame(scene);
estChange=false;
facteur=1;
}
Orienteur(PVector vo, PVector po) {
vorient=vo;
repere=new InteractiveFrame(scene);
repere.setPosition(po);
estChange=false;
facteur=1;
}
void oppose() {facteur*=-1;
vorient.mult(facteur);
}
void place(PVector p1, PVector p2, PVector v) {
repere.setPosition(comb(0.5, p1, 0.5, p2));
vorient=PVector.mult(v,facteur);
}
void draw() {
pushMatrix();//isInInteraction
if(repere.isInInteraction()){
if(!estChange){color trans=col1;col1=col2;col2=trans;oppose();estChange=true;}
}else{estChange=false;}
repere.applyTransformation();
fill(col1);
noStroke();
sphere(10);
popMatrix();
stroke(205);
strokeWeight(6);
ligne(repere.position(),comb(1,repere.position(),70,vorient));
strokeWeight(1);
}
}
PVector comb(float t1, PVector v1, float t2, PVector v2) {
PVector res=PVector.add(PVector.mult(v1, t1), PVector.mult(v2, t2));
return res;
}
PVector comb(float t1, PVector v1, float t2, PVector v2, float t3, PVector v3) {
PVector res=PVector.add(PVector.mult(v1, t1), PVector.mult(v2, t2));
res=PVector.add(res, PVector.mult(v3, t3));
return res;
}
PVector centreGravite(PVector u, PVector v, PVector r) {
PVector gr= comb(0.5f, u, 0.5f, v);
gr= comb(1.0f/3.0f, r, 2.0f/3.0f, gr);
return gr;
}
PVector barycentre(float lamb, PVector u, PVector v) {
return comb(lamb, u, 1-lamb, v);
}
float barycentre(float lamb, float u, float v) {
return lamb*u+(1-lamb)*v;
}
void ligne(PVector a, PVector b) {
line(a.x, a.y, a.z, b.x, b.y, b.z);
}
void afficher(PVector u) {
println("vecteur = "+u.x+" "+u.y+" "+u.z);
}
void afficher(Quaternion q) {
println("quaternion = x "+q.x+" y "+q.y+" z "+q.z+"... w "+q.z);
}
void rectangle(color c, float dx, float dy, float ax, float ay) {
stroke(150);
fill(c);
beginShape();
vertex(dx, dy, 0);
vertex(ax, dy, 0);
fill(color(red(c)*2, green(c)*2, blue(c)*2));
vertex(ax, ay, 0);
vertex(dx, ay, 0);
endShape(CLOSE);
}
//
void triangle3D(PVector a, PVector b, PVector c) {
beginShape();
fill(255, 200, 0, 200);
vertex( a.x, a.y, a.z);
fill(255, 255, 0, 200);
vertex( b.x, b.y, b.z);
fill(155, 50, 250, 200);
vertex( c.x, c.y, c.z);
endShape();
}
void triangle3D(PVector a, PVector b, PVector c, float k, float l, float m) {
stroke(0, 100, 255);
beginShape();
fill(k*0.9, l, m, 254);
vertex( a.x, a.y, a.z);
fill(k, l*0.5, m, 254);
vertex( b.x, b.y, b.z);
fill(k*0.9, l, 0.8*m, 254);
vertex( c.x, c.y, c.z);
endShape();
}
void triangles3D(PVector a, PVector b, PVector c) {
triangle3D(a, b, or);
triangle3D(b, c, or);
triangle3D(a, c, or);
}
PVector symetriePlan(PVector m, PVector u, PVector v) {
PVector normale=u.cross(v);
normale.normalize();
PVector pm=PVector.mult(normale, m.dot(normale));
return comb(1, m, -2.0, pm);
}
PVector projectionSurDroite(PVector v, PVector droite) {
PVector u=droite.get();
u.normalize();
return PVector.mult(u, u.dot(v));
}
float angleQuaternion(Quaternion q)
{
q.normalize();
return (float) Math.acos(q.w)* 2.0f;
}
PVector normaliser(PVector v, float f) {
v.normalize();
return PVector.mult(v, f);
}
PVector calculSym(PVector m, PVector n) {
n.normalize();
PVector p=PVector.mult(n, n.dot(m));
PVector res=comb(1.0, m, -2.0, p);
return res;
}
void afficherL(String L, PVector po) {
pushMatrix();
translate(po.x, po.y, po.z);
text(L, 10, 10);
popMatrix();
}
void dessinerArc(float angleQn,color c,float r) {
float anglArc=2*angleQn;
// if (angleQnion>PI) anglArc=2*(angleQnion-2.0*PI);
// if (angleQnion<-PI) anglArc=2*(angleQnion+2*PI);
fill(c);
noStroke();
float pta=anglArc/100.0;
beginShape(QUAD_STRIP);
for (int a=0;a<=100;a++) {
float aa=pta*a;
vertex(r*cos(aa), r*sin(aa), 0);
vertex(r*cos(aa), r*sin(aa), 30);
}
endShape();
fill(150, 120, 0);
beginShape(TRIANGLE_FAN);
vertex(0, 0, 0);
;fill(100,155,250);
for (int a=0;a<100;a+=4) {
float aa=anglArc*a/100.0;
vertex(r*cos(aa), r*sin(aa), 0);
}
vertex(r*cos(anglArc), r*sin(anglArc), 0);
endShape();
}
Quaternions are classes composed of oriented arcs, defined by an axis and an algebraic measure between -2*pi and 2 * pi .
To multiply two quaternions simply concatenate their arcs. The only difficulty is the choice of the arc results.
see more explanation (in French) here:
http://www.thematica.fr/
build with Proscene