/* * Copyright (c) 2008, 2009, 2010, 2011 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <stdlib.h> #include <string.h> #include <math.h> #import "OFFloatVector.h" #import "OFFloatMatrix.h" #import "OFString.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "macros.h" static Class floatMatrix = Nil; @implementation OFFloatVector + (void)initialize { if (self == [OFFloatVector class]) floatMatrix = [OFFloatMatrix class]; } + vectorWithDimension: (size_t)dimension { return [[[self alloc] initWithDimension: dimension] autorelease]; } + vectorWithDimension: (size_t)dimension data: (float)data, ... { id ret; va_list arguments; va_start(arguments, data); ret = [[[self alloc] initWithDimension: dimension data: data arguments: arguments] autorelease]; va_end(arguments); return ret; } - init { Class c = isa; [self release]; @throw [OFNotImplementedException newWithClass: c selector: _cmd]; } - initWithDimension: (size_t)dimension_ { self = [super init]; @try { dimension = dimension_; if (SIZE_MAX / dimension < sizeof(float)) @throw [OFOutOfRangeException newWithClass: isa]; if ((data = malloc(dimension * sizeof(float))) == NULL) @throw [OFOutOfMemoryException newWithClass: isa requestedSize: dimension * sizeof(float)]; memset(data, 0, dimension * sizeof(float)); } @catch (id e) { [self release]; @throw e; } return self; } - initWithDimension: (size_t)dimension_ data: (float)data_, ... { id ret; va_list arguments; va_start(arguments, data_); ret = [self initWithDimension: dimension_ data: data_ arguments: arguments]; va_end(arguments); return ret; } - initWithDimension: (size_t)dimension_ data: (float)data_ arguments: (va_list)arguments { self = [super init]; @try { size_t i; dimension = dimension_; if (SIZE_MAX / dimension < sizeof(float)) @throw [OFOutOfRangeException newWithClass: isa]; if ((data = malloc(dimension * sizeof(float))) == NULL) @throw [OFOutOfMemoryException newWithClass: isa requestedSize: dimension * sizeof(float)]; data[0] = data_; for (i = 1; i < dimension; i++) data[i] = (float)va_arg(arguments, double); } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { free(data); [super dealloc]; } - (void)setValue: (float)value atIndex: (size_t)index { if (index >= dimension) @throw [OFOutOfRangeException newWithClass: isa]; data[index] = value; } - (float)valueAtIndex: (size_t)index { if (index >= dimension) @throw [OFOutOfRangeException newWithClass: isa]; return data[index]; } - (size_t)dimension { return dimension; } - (void)setDimension: (size_t)dimension_ { float *newData; size_t i; if ((newData = realloc(data, dimension_ * sizeof(float))) == NULL) @throw [OFOutOfMemoryException newWithClass: isa requestedSize: dimension_ * sizeof(float)]; data = newData; for (i = dimension; i < dimension_; i++) data[i] = 0; dimension = dimension_; } - (BOOL)isEqual: (id)object { OFFloatVector *otherVector; if (![object isKindOfClass: [OFFloatVector class]]) return NO; otherVector = object; if (otherVector->dimension != dimension) return NO; if (memcmp(otherVector->data, data, dimension * sizeof(float))) return NO; return YES; } - (uint32_t)hash { size_t i; uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < dimension; i++) { union { float f; uint32_t i; } u; u.f = data[i]; OF_HASH_ADD_INT32(hash, u.i); } OF_HASH_FINALIZE(hash); return hash; } - copy { OFFloatVector *copy = [[isa alloc] initWithDimension: dimension]; memcpy(copy->data, data, dimension * sizeof(float)); return copy; } - (OFString*)description { OFMutableString *description; size_t i; description = [OFMutableString stringWithFormat: @"<%@: (", [self className]]; for (i = 0; i < dimension; i++) { if (i != dimension - 1) [description appendFormat: @"%g, ", data[i]]; else [description appendFormat: @"%g)>", data[i]]; } [description makeImmutable]; return description; } - (float*)cArray { return data; } - (float)magnitude { float magnitude; size_t i; magnitude = 0.0f; for (i = 0; i < dimension; i++) magnitude += data[i] * data[i]; magnitude = sqrtf(magnitude); return magnitude; } - (void)normalize { float magnitude; size_t i; magnitude = 0.0f; for (i = 0; i < dimension; i++) magnitude += data[i] * data[i]; magnitude = sqrtf(magnitude); for (i = 0; i < dimension; i++) data[i] /= magnitude; } - (void)addVector: (OFFloatVector*)vector { size_t i; if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; for (i = 0; i < dimension; i++) data[i] += vector->data[i]; } - (void)subtractVector: (OFFloatVector*)vector { size_t i; if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; for (i = 0; i < dimension; i++) data[i] -= vector->data[i]; } - (void)multiplyWithScalar: (float)scalar { size_t i; for (i = 0; i < dimension; i++) data[i] *= scalar; } - (void)divideByScalar: (float)scalar { size_t i; for (i = 0; i < dimension; i++) data[i] /= scalar; } - (void)multiplyWithComponentsOfVector: (OFFloatVector*)vector { size_t i; if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; for (i = 0; i < dimension; i++) data[i] *= vector->data[i]; } - (void)divideByComponentsOfVector: (OFFloatVector*)vector { size_t i; if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; for (i = 0; i < dimension; i++) data[i] /= vector->data[i]; } - (float)dotProductWithVector: (OFFloatVector*)vector { float dotProduct; size_t i; if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; dotProduct = 0.0f; for (i = 0; i < dimension; i++) dotProduct += data[i] * vector->data[i]; return dotProduct; } - (OFFloatVector*)crossProductWithVector: (OFFloatVector*)vector { OFFloatVector *crossProduct; if (dimension != 3) @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; if (vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; crossProduct = [OFFloatVector vectorWithDimension: 3]; crossProduct->data[0] = data[1] * vector->data[2] - data[2] * vector->data[1]; crossProduct->data[1] = data[2] * vector->data[0] - data[0] * vector->data[2]; crossProduct->data[2] = data[0] * vector->data[1] - data[1] * vector->data[0]; return crossProduct; } - (void)multiplyWithMatrix: (OFFloatMatrix*)matrix { float *newData; size_t i, j, k; if (matrix->isa != floatMatrix || dimension != matrix->columns) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; if ((newData = malloc(matrix->rows * sizeof(float))) == NULL) @throw [OFOutOfMemoryException newWithClass: isa requestedSize: matrix->rows * sizeof(float)]; memset(newData, 0, matrix->rows * sizeof(float)); for (i = j = k = 0; i < matrix->rows * matrix->columns; i++) { newData[j] += matrix->data[i] * data[k]; if (++j == matrix->rows) { k++; j = 0; } } free(data); data = newData; dimension = matrix->rows; } @end