biVector forum

Notes on cheatsheet (2DPGA specifically)

  1. They mention “polar”, but ganja nor the code generator define polar. The definition aI is useful, but then again I is only mentioned up top where it says “I=PSS” - what is PSS? I have no idea.

Simply, “polar” is aI, and I is 1e012 in 2DPGA, but this is hard to grasp from the cheatsheet.

  1. What are those “hats” for, such as in the formula for distance between points P1 and P2? They don’t seem to have any significance that I know of. They signify normalization (I figured it out through ganja). The cheatsheet should not use any symbols it has not defined previously (besides an agreed set of widely known operations, like inner product and outer product, and for those there should be a separate cheatsheet.
  1. Translator is given for “orthogonal to ideal point”. It would be more useful and understandable, if “direction” was used as the name instead of “ideal point”, and if the formula for translation “along” the direction, not orthongal to it, would be given.

@xixixao, Thanks for the feedback. We have a limited amount of real estate, the cheat sheets were designed as a companion for the Course Notes which are available on bivector.net/doc also.

  1. There you will a find a definition of “polarity” for example. In the left hand column of the cheat sheet, the polar map is defined as aI.
  2. We’ll try to define \bf{\hat{x}} in the left hand column as the normalized version of a blade (which can mean different things in different situations), before we use it.
  3. I don’t think the translation formula is easy to improve in the direction you propose. Suppose \bf{v} is the direction of translation in PGA. Then the orthogonal direction is \bf{P}_\infty = (\bf{v} \vee \bf{P})^\perp: first you have to join to some finite point \bf{P} and then polarize. But beginners will not understand this formula and it will take up important space. I recommend instead to compare the given formula to the formula for a rotation: the \bf{P}_\infty is the “center” of the “translation”.
    Thanks for your comments. Please don’t hesitate to post further questions. Especially if you find that the course notes don’t provide enough info to understand the cheat sheets.

I might as well continue this thread with other questions.

Context: I’m working on 2D drawing tool which includes rectangles, diamonds, ellipses and curves.

  1. Translation (v∨P) ⊥ = this is computationally very expensive. I can instead do for direction (x e20 y e01) direction (-y e20 x e01). But is this gonna break/not work for some direction?

  2. Segments. In CG, and with shapes like a rectangle (but this applies to most polygons) a lot of the code I need to write requires checking for intersections with segments, not lines. What is the cheapest check for intersection with a line (so really “does a point lie between two other points”). In our existing code we use this method:

// For the ordered points p, q, r, return
// 0 if p, q, r are colinear
// 1 if Clockwise
// 2 if counterclickwise
const orderedColinearOrientation = (p: Point, q: Point, r: Point) => {
  const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
  if (val === 0) {
    return 0;
  }
  return val > 0 ? 1 : 2;
};

I could of course use three distances, but computing those seems to be quite expensive, which brings me to my last question:

  1. Normalization. It seems to be quite an expensive operation but in the cheatsheet and in ganja examples it’s often done at the time it’s needed. I wonder when and if I should aggressively normalize, and whether it’s gonna cause any problems. If I say normalize every direction, or every point, when it’s created, is that gonna hurt my ability to construct algorithms down the line? And what does the normalization of a point in 2D PGA do, in layman terms?
    To add: Following the cheatsheet the notion of “magnitude” is kinda missed out, so when we get to the pesky translation things won’t work: The translation only works as expected if we either ideal-normalize the direction, or if had constructed the direction using a normalized line. Which again makes me think: When is the magnitude of a line useful, should I always normalize a line upon creation?

This is the motivating example for why I wanted to give GA a try in my application:

https://enkimute.github.io/ganja.js/examples/coffeeshop.html#x0yhXr7td

I would be curious whether there’s a simpler solution (ie more computationally efficient).

You nearly have it with your orderedColinerOrientation function. Just write that with you Geometric Algebra.

The best strategy I’ve found for collision detection in GA is to wedge your way up to the psuedoscalar and check the resulting signs ( orientation ).

I tend to work with homogeneous coords for intersections queries, but I assume the dualized algebra works out the same.
For segment segment intersection find the meet of your two lines (p,q) and (a,b), Call it r. Then compare the signs of join(q, r) and join(r,p), multiply them together and you’ll get the orderedColinearOrientation in GA. join of two points will give you an oriented pseudoscalar/scalar. Metric free, coordinate free, efficient.

I came up with this on my own, so there might be better ways of doing it.

1 Like

@xixixao Ack, realized that I’m short one dimension.
join(q, r) isn’t 3/0 dimension.
For a triangle in 3D I used the normal ( dual/polar( join(a,b,c) ) to get the last dimension wedge out to pseudoscalar.
So for 2D, If you apply the polar/dual to join(q,p) to get a point that is perpendicular to that segment. So for 2D segments you’d want scalar of join( p, r, polar(join(p,q))) compared to scalar of join(r, q, polar(join(p,q)))

I say polar/dual because, as I mentioned I would work in a (3,0,0) homogenous algebra ( uses “polar” ) for 2D rather than (2,0,1) and haven’t actually tried this in that algebra ( the one that uses “dual” )

To answer my own question about my use case example:
https://enkimute.github.io/ganja.js/examples/coffeeshop.html#7yP039K8r

(I realized this isn’t actually even GA, just plain old algebraic geometry :slight_smile: )

@xixixao I’ve been inspired by this thread to write an observable notebook on the theme of “Point in segment?” You can find it here. Feedback welcome.

@xixixao: In answer to your questions:

  1. The code you’ve written will work for all 2D translations (I’m assuming you’ve checked to make sure you’ve verified it should be -y e20 + x e01 and not y e20 - x e01.)
  2. I’ve updated the beginning of the observable notebook on this theme to include an even simpler treatment of “point in segment” that is more closely aligned with your code, since it is based on vectors rather than lines.
  3. A general rule-of-thumb is that for pure geometry, the magnitude often isn’t relevant. In contrast, when working with movements and mechanics, it is. For example: if a bivector B represents the axis of a rotation, then its magnitude will determine the speed of the rotation: twice the magnitude rotates twice as fast. This follows from the exponential formula for the versor: e^{(2t)B} as a versor rotates twice as fast as the versor e^{tB}. But I can also write that as e^{t(2B)}. Similar remarks apply to forces and momenta. Finally, whenever you add together points, or add together lines, then the magnitude of the arguments will influence the resulting point or line.