quakeforge/ruamoko/gatest/algebra.r
Bill Currie 0fbcd90e37 [gatest] Fix up layout issues for null vectors
e0 is created only if there are null vectors in the algebra, and the 3d
and 2d basis groups have been rearranged to compensate in the changed
ordering in the basis blade array.
2023-06-08 22:13:23 +09:00

171 lines
3.7 KiB
R

#include <stdlib.h>
#include <string.h>
#include "algebra.h"
#include "metric.h"
#include "basisblade.h"
#include "basisgroup.h"
#include "basislayout.h"
#include "multivector.h"
#include "util.h"
@implementation Algebra
+(Algebra *) R:(int)p, int m, int z
{
Algebra *a = [[[Algebra alloc] init] autorelease];
a.metric = [[Metric R:p, m, z] retain];
a.plus = p;
a.minus = m;
a.zero = z;
int d = p + m + z;
a.dimension = d;
a.num_components = 1 << d;
BasisBlade **blades = obj_malloc (a.num_components * sizeof (BasisBlade *));
int *counts = binomial (d);
int *indices = obj_malloc ((d + 1) * sizeof (int));
indices[0] = 0;
for (int i = 0; i < d; i++) {
indices[i + 1] = counts[i];
}
prefixsum (indices, d + 1);
for (int i = 0; i < a.num_components; i++) {
int grade = count_bits (i);
int ind = indices[grade]++;
unsigned mask = i;
if (!z) {
// e0 is best for the null vector, but this geometry has no null
// vectors, so skip it;
mask <<= 1;
}
blades[ind] = [BasisBlade basis:i];
}
a.grades = obj_malloc ((d + 1) * sizeof (BasisGroup *));
for (int i = 0; i < d + 1; i++) {
int c = counts[i];
int ind = indices[i];
a.grades[i] = [[BasisGroup new:c basis:blades + ind - c] retain];
}
if (p == 3 && m == 0 && z == 1) {
// 3d PGA (w squares to 0, x y z square to +1):
// : x y z w
// : yz zx xy 1
// : wx wy wz wxyz
// : wzy wxz wyx xyz
BasisBlade *pga_blades[16] = {
blades[2], blades[3], blades[4], blades[1],
blades[10], blades[9], blades[7], blades[0],
blades[5], blades[6], blades[8], blades[15],
blades[13], blades[12], blades[11], blades[14],
};
BasisGroup *pga_groups[4] = {
[BasisGroup new:4 basis:pga_blades + 0],
[BasisGroup new:4 basis:pga_blades + 4],
[BasisGroup new:4 basis:pga_blades + 8],
[BasisGroup new:4 basis:pga_blades + 12],
};
a.layout = [[BasisLayout new:4 groups: pga_groups] retain];
} else if (p == 2 && m == 0 && z == 1) {
// 2d PGA (w squares to 0, x y square to +1):
// : x y w 1
// : yw wx xy wxy
BasisBlade *pga_blades[8] = {
blades[2], blades[3], blades[1], blades[0],
blades[5], blades[4], blades[6], blades[7],
};
BasisGroup *pga_groups[2] = {
[BasisGroup new:4 basis:pga_blades + 0],
[BasisGroup new:4 basis:pga_blades + 4],
};
a.layout = [[BasisLayout new:2 groups: pga_groups] retain];
} else {
// just use the grades as the default layout
a.layout = [[BasisLayout new:d + 1 groups: a.grades] retain];
}
obj_free (indices);
obj_free (counts);
obj_free (blades);
return a;
}
+(Algebra *) PGA:(int)n
{
return [Algebra R:n, 0, 1];
}
-(void)dealloc
{
obj_free (grades);
[metric release];
[layout release];
[super dealloc];
}
-(BasisGroup *)grade:(int)k
{
return grades[k];
}
-(BasisLayout *)layout
{
return layout;
}
-(Metric *) metric
{
return metric;
}
-(int)count
{
return num_components;
}
-(int)dimension
{
return dimension;
}
-(MultiVector *) group:(int)group
{
return [MultiVector new:self group:[layout group:group]];
}
-(MultiVector *) group:(int)group values:(double *)values
{
return [MultiVector new:self group:[layout group:group] values:values];
}
-(MultiVector *) ofGrade:(int)grade
{
return [MultiVector new:self group:grades[grade]];
}
-(MultiVector *) ofGrade:(int)grade values:(double *)values
{
return [MultiVector new:self group:grades[grade] values:values];
}
-(void) print
{
int count = [layout count];
for (int i = 0; i < count; i++) {
BasisGroup *g = [layout group:i];
int c = [g count];
printf ("%d %d %@\n", i, c, [g set]);
for (int j = 0; j < c; j++) {
printf (" %@\n", [g bladeAt:j]);
}
}
}
-(string) describe
{
return sprintf ("R(%d,%d,%d)", plus, minus, zero);
}
@end