mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
4e441d359a
Currently only PGA(3) is supported, but that's because the parser is rather simple (recursive descent with a lame lexer), but it works well enough for playing with geometric algebra without having to recompile every time.
282 lines
6.3 KiB
R
282 lines
6.3 KiB
R
#include <string.h>
|
|
#include "algebra.h"
|
|
#include "basisblade.h"
|
|
#include "basislayout.h"
|
|
#include "multivector.h"
|
|
#include "util.h"
|
|
|
|
@implementation MultiVector
|
|
static MultiVector *new_mv (Algebra *algebra, BasisLayout *layout)
|
|
{
|
|
MultiVector *mv = [[[MultiVector alloc] init] autorelease];
|
|
mv.algebra = [algebra retain];
|
|
layout = layout ? layout : [algebra layout];
|
|
mv.layout = [layout retain];
|
|
mv.num_components = [layout num_components];
|
|
mv.components = obj_malloc (mv.num_components * sizeof (double));
|
|
return mv;
|
|
}
|
|
|
|
+(MultiVector *) new:(Algebra *) algebra
|
|
{
|
|
MultiVector *mv = new_mv (algebra, nil);
|
|
for (int i = 0; i < mv.num_components; i++) {
|
|
mv.components[i] = 0;
|
|
}
|
|
return mv;
|
|
}
|
|
|
|
+(MultiVector *) new:(Algebra *) algebra values:(double *) values
|
|
{
|
|
MultiVector *mv = new_mv (algebra, nil);
|
|
for (int i = 0; i < mv.num_components; i++) {
|
|
mv.components[i] = values[i];
|
|
}
|
|
return mv;
|
|
}
|
|
|
|
+(MultiVector *) new:(Algebra *) algebra group:(BasisGroup *) group
|
|
{
|
|
BasisLayout *layout = [BasisLayout new:1 groups:&group];
|
|
MultiVector *mv = new_mv (algebra, layout);
|
|
for (int i = 0; i < mv.num_components; i++) {
|
|
mv.components[i] = 0;
|
|
}
|
|
return mv;
|
|
}
|
|
|
|
+(MultiVector *) new:(Algebra *) algebra group:(BasisGroup *) group values:(double *) values
|
|
{
|
|
BasisLayout *layout = [BasisLayout new:1 groups:&group];
|
|
MultiVector *mv = new_mv (algebra, layout);
|
|
for (int i = 0; i < mv.num_components; i++) {
|
|
mv.components[i] = values[i];
|
|
}
|
|
return mv;
|
|
}
|
|
|
|
+(MultiVector *) copy:(MultiVector *) src
|
|
{
|
|
MultiVector *mv = new_mv (src.algebra, src.layout);
|
|
for (int i = 0; i < mv.num_components; i++) {
|
|
mv.components[i] = src.components[i];
|
|
}
|
|
return mv;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[algebra release];
|
|
[layout release];
|
|
obj_free (components);
|
|
[super dealloc];
|
|
}
|
|
|
|
-(string)describe
|
|
{
|
|
string str = nil;
|
|
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
BasisBlade *b = [layout bladeAt:i];
|
|
str = sprintf ("%s%s%g%s", str, str ? " + " : "", components[i], [b name]);
|
|
}
|
|
if (!str) {
|
|
str = "0";
|
|
}
|
|
return str;
|
|
}
|
|
|
|
-(double *) components
|
|
{
|
|
return components;
|
|
}
|
|
|
|
-(int)indexFor:(unsigned)mask
|
|
{
|
|
return [layout bladeIndex:mask];
|
|
}
|
|
|
|
-(double *) componentFor:(BasisBlade *) blade
|
|
{
|
|
return &components[[layout bladeIndex:[blade mask]]];
|
|
}
|
|
|
|
-(MultiVector *) product:(MultiVector *) rhs
|
|
{
|
|
MultiVector *prod = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double lc = components[i];
|
|
BasisBlade *lb = [layout bladeAt:i];
|
|
for (int j = 0; j < rhs.num_components; j++) {
|
|
if (!rhs.components[j]) {
|
|
continue;
|
|
}
|
|
double rc = rhs.components[j];
|
|
BasisBlade *rb = [rhs.layout bladeAt:j];
|
|
BasisBlade *b = [lb geometricProduct:rb metric:[algebra metric]];
|
|
double s = [b scale];
|
|
if (!s) {
|
|
continue;
|
|
}
|
|
int ind = [prod.layout bladeIndex:[b mask]];
|
|
prod.components[ind] += s * lc * rc;
|
|
}
|
|
}
|
|
return prod;
|
|
}
|
|
|
|
-(MultiVector *) wedge:(MultiVector *) rhs
|
|
{
|
|
MultiVector *prod = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double lc = components[i];
|
|
BasisBlade *lb = [layout bladeAt:i];
|
|
for (int j = 0; j < rhs.num_components; j++) {
|
|
if (!rhs.components[j]) {
|
|
continue;
|
|
}
|
|
double rc = rhs.components[j];
|
|
BasisBlade *rb = [rhs.layout bladeAt:j];
|
|
BasisBlade *b = [lb outerProduct:rb];
|
|
double s = [b scale];
|
|
if (!s) {
|
|
continue;
|
|
}
|
|
int ind = [prod.layout bladeIndex:[b mask]];
|
|
prod.components[ind] += s * lc * rc;
|
|
}
|
|
}
|
|
return prod;
|
|
}
|
|
|
|
-(MultiVector *) dot:(MultiVector *) rhs
|
|
{
|
|
MultiVector *prod = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double lc = components[i];
|
|
BasisBlade *lb = [layout bladeAt:i];
|
|
int lg = [lb grade];
|
|
for (int j = 0; j < rhs.num_components; j++) {
|
|
if (!rhs.components[j]) {
|
|
continue;
|
|
}
|
|
double rc = rhs.components[j];
|
|
BasisBlade *rb = [rhs.layout bladeAt:j];
|
|
int rg = [rb grade];
|
|
BasisBlade *b = [lb geometricProduct:rb metric:[algebra metric]];
|
|
int g = [b grade];
|
|
if ((lg <= rg) && (g != rg - lg)) {
|
|
continue;
|
|
}
|
|
if ((lg > rg) && (g != lg - rg)) {
|
|
continue;
|
|
}
|
|
double s = [b scale];
|
|
if (!s) {
|
|
continue;
|
|
}
|
|
int ind = [prod.layout bladeIndex:[b mask]];
|
|
prod.components[ind] += s * lc * rc;
|
|
}
|
|
}
|
|
return prod;
|
|
}
|
|
|
|
-(MultiVector *) plus:(MultiVector *) rhs
|
|
{
|
|
MultiVector *plus = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
double c = components[i];
|
|
if (!c) {
|
|
continue;
|
|
}
|
|
BasisBlade *b = [layout bladeAt:i];
|
|
int ind = [plus.layout bladeIndex:[b mask]];
|
|
plus.components[ind] += c;
|
|
}
|
|
for (int i = 0; i < rhs.num_components; i++) {
|
|
double c = rhs.components[i];
|
|
if (!c) {
|
|
continue;
|
|
}
|
|
BasisBlade *b = [rhs.layout bladeAt:i];
|
|
int ind = [plus.layout bladeIndex:[b mask]];
|
|
plus.components[ind] += c;
|
|
}
|
|
return plus;
|
|
}
|
|
|
|
-(MultiVector *) minus:(MultiVector *) rhs
|
|
{
|
|
MultiVector *minus = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
double c = components[i];
|
|
if (!c) {
|
|
continue;
|
|
}
|
|
BasisBlade *b = [layout bladeAt:i];
|
|
int ind = [minus.layout bladeIndex:[b mask]];
|
|
minus.components[ind] += c;
|
|
}
|
|
for (int i = 0; i < rhs.num_components; i++) {
|
|
double c = rhs.components[i];
|
|
if (!c) {
|
|
continue;
|
|
}
|
|
BasisBlade *b = [rhs.layout bladeAt:i];
|
|
int ind = [minus.layout bladeIndex:[b mask]];
|
|
minus.components[ind] -= c;
|
|
}
|
|
return minus;
|
|
}
|
|
|
|
-(MultiVector *) dual
|
|
{
|
|
MultiVector *dual = new_mv (algebra, nil);
|
|
unsigned dual_mask = (1 << [algebra dimension]) - 1;
|
|
printf ("dual: %x %d\n", dual_mask, [algebra dimension]);
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double lc = components[i];
|
|
BasisBlade *lb = [layout bladeAt:i];
|
|
unsigned mask = [lb mask] ^ dual_mask;
|
|
double s = 1;
|
|
int ind = [layout bladeIndex:mask];
|
|
printf (" : %x %d\n", mask, ind);
|
|
dual.components[ind] += s * lc;
|
|
}
|
|
return dual;
|
|
}
|
|
|
|
-(MultiVector *) reverse
|
|
{
|
|
MultiVector *reverse = new_mv (algebra, nil);
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double c = components[i];
|
|
BasisBlade *b = [layout bladeAt:i];
|
|
int g = [b grade];
|
|
unsigned mask = [b mask];
|
|
double s = g & 2 ? -1 : 1;//FIXME do in BasisBlade?
|
|
int ind = [layout bladeIndex:mask];
|
|
reverse.components[ind] += s * c;
|
|
}
|
|
return reverse;
|
|
}
|
|
@end
|