mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-25 13:51:36 +00:00
a40fee2513
I was aware in the beginning that the signs were probably incorrect, but I had left them as I wasn't sure how they worked. Thanks to enki (bivector community), I was pointed in the right direction for getting the calculations right: the product of a basis blade with its dual (x !x) must product the positive pseudo-scalar.
293 lines
6.6 KiB
R
293 lines
6.6 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 = [MultiVector new:algebra];
|
|
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 *) divide:(MultiVector *) rhs
|
|
{
|
|
MultiVector *sqr = [rhs product:rhs];
|
|
double smag = sqr.components[[sqr indexFor:0]];
|
|
MultiVector *div = [self product:rhs];
|
|
for (int i = 0; i < div.num_components; i++) {
|
|
div.components[i] /= smag;
|
|
}
|
|
return div;
|
|
}
|
|
|
|
-(MultiVector *) wedge:(MultiVector *) rhs
|
|
{
|
|
MultiVector *prod = [MultiVector new:algebra];
|
|
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 = [MultiVector new:algebra];
|
|
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 = [MultiVector new:algebra];
|
|
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 = [MultiVector new:algebra];
|
|
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 = [MultiVector new:algebra];
|
|
unsigned dual_mask = (1 << [algebra dimension]) - 1;
|
|
for (int i = 0; i < num_components; i++) {
|
|
if (!components[i]) {
|
|
continue;
|
|
}
|
|
double lc = components[i];
|
|
BasisBlade *lb = [layout bladeAt:i];
|
|
unsigned lb_mask = [lb mask];
|
|
unsigned mask = lb_mask ^ dual_mask;
|
|
double ls = [lb scale];
|
|
double s = count_flips (lb_mask, mask) & 1 ? -1 : 1;
|
|
int ind = [dual.layout bladeIndex:mask];
|
|
dual.components[ind] += s * lc;
|
|
}
|
|
return dual;
|
|
}
|
|
|
|
-(MultiVector *) reverse
|
|
{
|
|
MultiVector *reverse = [MultiVector new:algebra];
|
|
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
|