Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Questions on parallel lines and l*l motors #172

Open
obliviand opened this issue Jul 24, 2024 · 2 comments
Open

Questions on parallel lines and l*l motors #172

obliviand opened this issue Jul 24, 2024 · 2 comments

Comments

@obliviand
Copy link

I'm still learning GA, but I've been running into confusing issues with what I thought should be simple examples with what I thought were simple lines given the examples provided with ganja.js. I'm unsure if these are issues or the way it is supposed to work.

I've tried to document two of the items below.

The PGA3D "distances and angles" example seems to give the correct positive angle because of ordering of points to make the line directions opposite at point (i.e. tip to tail like vectors). If I'm reading them correctly (and I'm probably not) the SIGGRAPH 2019 Figure 9 and PGA3D cheat sheet provide acos(l1|l2). Based on the direction arrows on the two lines in Figure 9, they are in the same direction entering the point and that it should give the smaller positive angle for two lines in the same direction including parallel.

I checked this using klein c++ and it appears to have the same result as ganja.js, and if I understand correctly that library is based off of the SIGGRAPH 2019 paper, not the PGA4CS v2.0 setup for e0.

Here are parallel lines with reversed direction result in an angle of 0:

Algebra(3,0,1,()=>{ 
  var point = (x,y,z)=>1e123-x*1e012+y*1e013+z*1e023;
  var angle_ll = (l1,l2)=>Math.acos(l1.Normalized<<l2.Normalized)*180/Math.PI; // Angle between lines 
  var A=point(1,1,0), B=point(1,-1,0), C=point(1,-1,0), D=point(1,1,0); 

  document.body.appendChild(this.graph(()=>{
    return [0x444444,A,"A",B,"B",C,"C",D,"D",
            0x884488,[A,B],[C,D],(angle_ll(A&B,C&D).toFixed(2))+"&deg;"
           ];
  },{animate:false,grid:1,labels:1,lineWidth:3})); 
  
});

and parallel lines in the same direction result in an angle of 180:

Algebra(3,0,1,()=>{ 
  var point = (x,y,z)=>1e123-x*1e012+y*1e013+z*1e023;
  var angle_ll = (l1,l2)=>Math.acos(l1.Normalized<<l2.Normalized)*180/Math.PI; // Angle between lines 
  var A=point(1,1,0), B=point(1,-1,0), C=point(1,1,0), D=point(1,-1,0); 

  document.body.appendChild(this.graph(()=>{
    return [0x444444,A,"A",B,"B",C,"C",D,"D",
            0x884488,[A,B],[C,D],(angle_ll(A&B,C&D).toFixed(2))+"&deg;"
           ];
  },{animate:false,grid:1,labels:1,lineWidth:3})); 
});

Is the difference because of the PGA4CS V2.0 sign change of e to -e0, or something else I'm missing?


Another example is creating lines on the axis at the origin from points and trying to move from one to the other with a motor between them:

Algebra(3,0,1,()=>{
  var line  = (...plucker)=>(plucker*[1e01,1e02,1e03,1e12,1e13,1e23]).Normalized,
      point = (x,y,z)=>!(1e0 + x*1e1 + y*1e2 + z*1e3);
  var motor = (line,angle_or_distance)=>Math.E**(angle_or_distance/2 * line);
  var sqrt = motor => ((Math.sign(motor.s) + motor)*(1 + 0.5*(motor.s + motor.Grade(4)))).Normalized;
  var lerp = (motor, x) => (Math.sign(motor().s)*(1-x) + x*motor).Normalized;

  var l1 = (point(0,0,0)&point(0,1,0)).Normalized, l2 = (point(0,0,0)&point(0,0,1)).Normalized;

  var l1tol2 = ()=>sqrt(l2 * l1);
  var l3 = l1tol2() >>> l1;

  document.body.appendChild(this.graph(()=>{
    var t = 0.5+0.5*Math.sin(performance.now()/1000);

    return [
      0x882288,lerp(l1tol2,t) >>> l1,          // move between lines
      0x228844,l1,"l1",l2,"l2",                // our two lines.
      0xff0000,l3,"l3"
    ];
  },{grid:true, labels:true,lineWidth:3, h:-0.4, p:-0.1, scale:1.4, animate:true}));
});

This doesn't work and l1 stays where it is. Looking at the values for the original l2 case where it doesn't appear to move, it appears the operation swaps the direction of l1.
If l2 is given a small y offset such as l2 = (point(0,0,0)&point(0,0.00000000000000001,1)).Normalized the example works and the line goes from l1 to l2.

This example sort of works with klein without the small y offset. In the case of klein it does a rotation to the x axis instead of the z axis, so I'm guessing this case has a different issue in both libraries?

@obliviand
Copy link
Author

Here's a more complete example of the second issue with l*l motors.

// Create a Clifford Algebra with 3,0,1 metric.
Algebra(3,0,1,()=>{

  const point = (x, y, z) => !(1e0 + x * 1e1 + y * 1e2 + z * 1e3);
  const motor = (line, angle_or_distance) => Math.E ** (angle_or_distance / 2 * line);
  const sqrt = motor => ((Math.sign(motor.s) + motor) * (1 + 0.5 * (motor.s + motor.Grade(4)))).Normalized;

  const SV = 0.0000000000000000000001;
  const o = point(0, 0, 0);
  let x = point(1, 0, 0);
  let y = point(0, 1, 0);
  let z = point(0, 0, 1);
  let x_sv = point(1, SV, SV);
  let y_sv = point(SV, 1, SV);
  let z_sv = point(SV, SV, 1);

  let lx = (o & x).Normalized;
  let ly = (o & y).Normalized;
  let lz = (o & z).Normalized;
  let lx_sv = (o & x_sv).Normalized;
  let ly_sv = (o & y_sv).Normalized;
  let lz_sv = (o & z_sv).Normalized;

  // broken?
  let lx_out;
  lx_out = sqrt(ly*lx) >>> lx; // swaps direction of x-axis instead of moving it to y-axis
  //lx_out = sqrt(lz*lx) >>> lx; // swaps direction of x-axis instead of moving it to z-axis
  // working?
  //lx_out = sqrt(ly*lx_sv) >>> lx; // moves x-axis to y-axis keeping positive direction
  //lx_out = sqrt(lz*lx_sv) >>> lx; // moves x-axis to z-axis keeping positive direction
  
  let Mx = motor(!lx_out, 1);

  // broken?
  let ly_out;
  ly_out= sqrt(lz*ly) >>> ly; // swaps direction of y-axis instead of moving it to z-axis
  //ly_out = sqrt(lx*ly) >>> ly; // swaps direction of y-axis instead of moving it to x-axis
  // working?
  //ly_out = sqrt(lz*ly_sv) >>> ly; // moves y-axis to z-axis keeping positive direction
  //ly_out = sqrt(lx*ly_sv) >>> ly; // moves y-axis to x-axis keeping positive direction

  let My = motor(!ly_out, 1);

  // broken?
  let lz_out;
  lz_out = sqrt(lx*lz) >>> lz; // swaps direction of z-axis instead of moving it to x-axis
  //lz_out = sqrt(ly*lz) >>> lz; // swaps direction of z-axis instead of moving it to y-axis
  // working?
  //lz_out = sqrt(lx*lz_sv) >>> lz; // moves z-axis to x-axis keeping positive direction
  //lz_out = sqrt(ly*lz_sv) >>> lz; // moves z-axis to y-axis keeping positive direction

  let Mz = motor(!lz_out, 1);

  // Graph it
  document.body.appendChild(this.graph(()=>{
    return [
      0xff0000, lx_out,
      0x00ff00, ly_out,
      0x0000ff, lz_out,
      0xff0000, Mx >>> o, "x dir",
      0x00ff00, My >>> o, "y dir",
      0x0000ff, Mz >>> o, "z dir"
    ];
  },{grid:true, labels:true,lineWidth:3, h:-0.4, p:-0.1, scale:1.4, animate:false}));

});

Output of the code with motors moving a point in the negative direction with zeros:

image

And then the output of the above with the first "working" selections uncommented with small values

  lx_out = sqrt(ly*lx_sv) >>> lx; // moves x-axis to y-axis keeping positive direction
  ly_out = sqrt(lz*ly_sv) >>> ly; // moves y-axis to z-axis keeping positive direction
  lz_out = sqrt(lx*lz_sv) >>> lz; // moves z-axis to x-axis keeping positive direction

image

@obliviand obliviand changed the title Questions on how parallel objects work Questions on parallel lines and l*l motors Jul 26, 2024
@obliviand
Copy link
Author

obliviand commented Jul 28, 2024

Edited: Added Object.is check for -0 since javascript still considers -0 as 0 for a regular compare.

Based on checking each term, the Math.sign(motor.s) in the sqrt function from the PGA3D examples is returning +/-0 when I think the first term of the motor is expecting +/-1? The small bias value prevents Math.sign from returning 0 which is why it appeared to "fix" the problem.

Changing the sqrt function to the following fixes the problems when lines and planes are through the origin:

const sqrt = motor => ((((motor.s>=0 && Object.is(motor.s,-0))?1:-1) + motor) * (1 + 0.5 * (motor.s + motor.Grade(4)))).Normalized;

Motors constructed between planes have the same orientation as the original destination plane after applying the motor to the starting plane.

Motors between lines are now drawing on the correct axis and correct orientation without the small bias value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant