Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -241,10 +241,12 @@ 4BB25E8B139C388A00F574EA /* OFString+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB25E85139C388A00F574EA /* OFString+Serialization.m */; }; 4BB25E8C139C388A00F574EA /* OFXMLElement+Serialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB25E86139C388A00F574EA /* OFXMLElement+Serialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB25E8D139C388A00F574EA /* OFXMLElement+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB25E87139C388A00F574EA /* OFXMLElement+Serialization.m */; }; 4BD98C03133814220048DD5B /* objfw-defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD98C011338140B0048DD5B /* objfw-defs.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BDF37B51338055600F9A81A /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDF37B41338055600F9A81A /* config.h */; }; + 4BE920A813A2ECEF00154B94 /* OFFloatVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BE920A613A2ECEF00154B94 /* OFFloatVector.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BE920A913A2ECEF00154B94 /* OFFloatVector.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE920A713A2ECEF00154B94 /* OFFloatVector.m */; }; 4BF33AFB133807590059CEF7 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3D23761337FBC800DD29B8 /* ObjFW.framework */; }; 4BF33AFC133807A20059CEF7 /* OFArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6EF66E1235358D0076B512 /* OFArrayTests.m */; }; 4BF33AFD133807A20059CEF7 /* OFBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0E412DF4259005C7A0C /* OFBlockTests.m */; }; 4BF33AFE133807A20059CEF7 /* OFDataArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6EF66F1235358D0076B512 /* OFDataArrayTests.m */; }; 4BF33AFF133807A20059CEF7 /* OFDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0E512DF4259005C7A0C /* OFDateTests.m */; }; @@ -556,10 +558,12 @@ 4BE5F0D812DF4225005C7A0C /* OFConstantString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFConstantString.m; path = src/OFConstantString.m; sourceTree = SOURCE_ROOT; }; 4BE5F0D912DF4225005C7A0C /* OFDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFDate.h; path = src/OFDate.h; sourceTree = SOURCE_ROOT; }; 4BE5F0DA12DF4225005C7A0C /* OFDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDate.m; path = src/OFDate.m; sourceTree = SOURCE_ROOT; }; 4BE5F0E412DF4259005C7A0C /* OFBlockTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFBlockTests.m; path = tests/OFBlockTests.m; sourceTree = SOURCE_ROOT; }; 4BE5F0E512DF4259005C7A0C /* OFDateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDateTests.m; path = tests/OFDateTests.m; sourceTree = SOURCE_ROOT; }; + 4BE920A613A2ECEF00154B94 /* OFFloatVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFFloatVector.h; path = src/OFFloatVector.h; sourceTree = ""; }; + 4BE920A713A2ECEF00154B94 /* OFFloatVector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFFloatVector.m; path = src/OFFloatVector.m; sourceTree = ""; }; 4BF0749512DFAFCA00A4ADD1 /* OFURLTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFURLTests.m; path = tests/OFURLTests.m; sourceTree = SOURCE_ROOT; }; 4BF1BCBF11C9663F0025511F /* objfw-defs.h.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "objfw-defs.h.in"; path = "src/objfw-defs.h.in"; sourceTree = ""; }; 4BF1BCC011C9663F0025511F /* OFHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFHash.h; path = src/OFHash.h; sourceTree = ""; }; 4BF1BCC111C9663F0025511F /* OFHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFHash.m; path = src/OFHash.m; sourceTree = ""; }; 4BF1BCC211C9663F0025511F /* OFMD5Hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMD5Hash.h; path = src/OFMD5Hash.h; sourceTree = ""; }; @@ -787,10 +791,12 @@ 4B6799631099E7C50041064A /* OFDictionary.m */, 4B0108C910EB8C9300631877 /* OFEnumerator.h */, 4B0108CA10EB8C9300631877 /* OFEnumerator.m */, 4B6799661099E7C50041064A /* OFFile.h */, 4B6799671099E7C50041064A /* OFFile.m */, + 4BE920A613A2ECEF00154B94 /* OFFloatVector.h */, + 4BE920A713A2ECEF00154B94 /* OFFloatVector.m */, 4BF1BCC011C9663F0025511F /* OFHash.h */, 4BF1BCC111C9663F0025511F /* OFHash.m */, 4B99250F12E0780000215DBE /* OFHTTPRequest.h */, 4B99251012E0780000215DBE /* OFHTTPRequest.m */, 4B67996C1099E7C50041064A /* OFList.h */, @@ -968,10 +974,11 @@ 4B3D23C41337FC8300DD29B8 /* OFDate.h in Headers */, 4B3D23C51337FCB000DD29B8 /* OFDictionary.h in Headers */, 4B3D23C61337FCB000DD29B8 /* OFEnumerator.h in Headers */, 4B17FF74133A2AAB003E6DCD /* OFException.h in Headers */, 4B3D23C81337FCB000DD29B8 /* OFFile.h in Headers */, + 4BE920A813A2ECEF00154B94 /* OFFloatVector.h in Headers */, 4B3D23C91337FCB000DD29B8 /* OFHash.h in Headers */, 4B3D23CA1337FCB000DD29B8 /* OFHTTPRequest.h in Headers */, 4B3D23CB1337FCB000DD29B8 /* OFList.h in Headers */, 4B3D23CC1337FCB000DD29B8 /* OFMD5Hash.h in Headers */, 4B3D23CD1337FCB000DD29B8 /* OFMutableArray.h in Headers */, @@ -1219,10 +1226,11 @@ 4B3D23911337FC0D00DD29B8 /* OFDataArray+Hashing.m in Sources */, 4B3D23921337FC0D00DD29B8 /* OFDate.m in Sources */, 4B3D23931337FC0D00DD29B8 /* OFDictionary.m in Sources */, 4B3D23941337FC0D00DD29B8 /* OFEnumerator.m in Sources */, 4B3D23961337FC0D00DD29B8 /* OFFile.m in Sources */, + 4BE920A913A2ECEF00154B94 /* OFFloatVector.m in Sources */, 4B3D23971337FC0D00DD29B8 /* OFHash.m in Sources */, 4B3D23981337FC0D00DD29B8 /* OFHTTPRequest.m in Sources */, 4B3D23991337FC0D00DD29B8 /* OFList.m in Sources */, 4B3D239A1337FC0D00DD29B8 /* OFMD5Hash.m in Sources */, 4B3D239B1337FC0D00DD29B8 /* OFMutableArray.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -14,14 +14,15 @@ OFConstantString.m \ OFDataArray.m \ OFDataArray+Hashing.m \ OFDate.m \ OFDictionary.m \ + OFEnumerator.m \ OFFile.m \ + OFFloatVector.m \ OFHash.m \ OFHTTPRequest.m \ - OFEnumerator.m \ OFList.m \ OFMD5Hash.m \ OFMutableArray.m \ OFMutableDictionary.m \ OFMutableString.m \ ADDED src/OFFloatVector.h Index: src/OFFloatVector.h ================================================================== --- src/OFFloatVector.h +++ src/OFFloatVector.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * 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 + +#import "OFObject.h" + +/** + * \brief A class for storing and manipulating vectors of floats. + */ +@interface OFFloatVector: OFObject +{ + size_t dimension; + float *data; +} + +/** + * \brief Creates a new vector with the specified dimension. + * + * \param dimension The dimension for the vector + * \return A new autoreleased OFFloatVector + */ ++ vectorWithDimension: (size_t)dimension; + +/** + * \brief Creates a new vector with the specified dimension and data. + * + * \param dimension The dimension for the vector + * \return A new autoreleased OFFloatVector + */ ++ vectorWithDimensionAndData: (size_t)dimension, ...; + +/** + * \brief Initializes the vector with the specified dimension. + * + * \param dimension The dimension for the vector + * \return An initialized OFFloatVector + */ +- initWithDimension: (size_t)dimension; + +/** + * \brief Initializes the vector with the specified dimension and data. + * + * \param dimension The dimension for the vector + * \return An initialized OFFloatVector + */ +- initWithDimensionAndData: (size_t)dimension, ...; + +/** + * \brief Initializes the vector with the specified dimension and arguments. + * + * \param dimension The dimension for the vector + * \param arguments A va_list with data for the vector + * \return An initialized OFFloatVector + */ +- initWithDimension: (size_t)dimension + arguments: (va_list)arguments; + +/** + * \brief Sets the value for the specified index. + * + * \param value The value + * \param index The index for the value + */ +- (void)setValue: (float)value + atIndex: (size_t)index; + +/** + * \brief Returns the value for the specified index. + * + * \param index The index for which the value should be returned + * \return The value for the specified index + */ +- (float)valueAtIndex: (size_t)index; + +/** + * \brief Returns the dimension of the vector. + * + * \return The dimension of the vector + */ +- (size_t)dimension; + +/** + * \brief Returns an array of floats with the contents of the vector. + * + * Modifying the returned array is allowed and will change the vector. + * + * \brief An array of floats with the contents of the vector + */ +- (float*)floatArray; + +/** + * \brief Adds the specified vector to the receiver. + * + * \param vector The vector to add + */ +- (void)addVector: (OFFloatVector*)vector; + +/** + * \brief Subtracts the specified vector from the receiver. + * + * \param vector The vector to subtract + */ +- (void)subtractVector: (OFFloatVector*)vector; + +/** + * \brief Multiplies the receiver with the specified scalar. + * + * \param scalar The scalar to multiply with + */ +- (void)multiplyWithScalar: (float)scalar; + +/** + * \brief Divides the receiver by the specified scalar. + * + * \param scalar The scalar to divide by + */ +- (void)divideByScalar: (float)scalar; + +/** + * \brief Multiplies the components of the receiver with the components of the + * specified vector. + * + * \param vector The vector to multiply the receiver with + */ +- (void)multiplyWithComponentsOfVector: (OFFloatVector*)vector; + +/** + * \brief Divides the components of the receiver by the components of the + * specified vector. + * + * \param vector The vector to divide the receiver by + */ +- (void)divideByComponentsOfVector: (OFFloatVector*)vector; + +/** + * \brief Returns the dot product of the receiver and the specified vector. + * + * \return The dot product of the receiver and the specified vector + */ +- (float)dotProductWithVector: (OFFloatVector*)vector; + +/** + * \brief Returns the magnitude or length of the vector. + * + * \return The magnitude or length of the vector + */ +- (float)magnitude; + +/** + * \brief Normalizes the vector. + */ +- (void)normalize; +@end ADDED src/OFFloatVector.m Index: src/OFFloatVector.m ================================================================== --- src/OFFloatVector.m +++ src/OFFloatVector.m @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * 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 +#include + +#import "OFFloatVector.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" +#import "OFNotImplementedException.h" +#import "OFOutOfRangeException.h" + +#import "macros.h" + +@implementation OFFloatVector ++ vectorWithDimension: (size_t)dimension +{ + return [[[self alloc] initWithDimension: dimension] autorelease]; +} + ++ vectorWithDimensionAndData: (size_t)dimension, ... +{ + id ret; + va_list arguments; + + va_start(arguments, dimension); + ret = [[[self alloc] initWithDimension: dimension + 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_; + + data = [self allocMemoryForNItems: dimension + withSize: sizeof(float)]; + + memset(data, 0, dimension * sizeof(float)); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithDimensionAndData: (size_t)dimension_, ... +{ + id ret; + va_list arguments; + + va_start(arguments, dimension_); + ret = [self initWithDimension: dimension_ + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithDimension: (size_t)dimension_ + arguments: (va_list)arguments +{ + self = [super init]; + + @try { + size_t i; + + dimension = dimension_; + + data = [self allocMemoryForNItems: dimension + withSize: sizeof(float)]; + + for (i = 0; i < dimension; i++) + data[i] = va_arg(arguments, double); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (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; +} + +- (BOOL)isEqual: (id)object +{ + OFFloatVector *otherVector; + size_t i; + + if (object->isa != isa) + return NO; + + otherVector = object; + + if (otherVector->dimension != dimension) + return NO; + + for (i = 0; i < dimension; i++) + if (otherVector->data[i] != data[i]) + 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] init]; + + copy->dimension = dimension; + copy->data = [copy allocMemoryForNItems: dimension + withSize: sizeof(float)]; + 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]]; + } + + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + description->isa = [OFString class]; + return description; +} + +- (float*)floatArray +{ + return data; +} + +- (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.0; + + for (i = 0; i < dimension; i++) + dotProduct += data[i] * vector->data[i]; + + return dotProduct; +} + +- (float)magnitude +{ + float magnitude; + size_t i; + + magnitude = 0.0; + + for (i = 0; i < dimension; i++) + magnitude += data[i] * data[i]; + + magnitude = sqrtf(magnitude); + + return magnitude; +} + +- (void)normalize +{ + float magnitude; + size_t i; + + magnitude = [self magnitude]; + + for (i = 0; i < dimension; i++) + data[i] /= magnitude; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -50,10 +50,12 @@ #import "OFXMLAttribute.h" #import "OFXMLElement.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" + +#import "OFFloatVector.h" #import "OFSerialization.h" #import "OFApplication.h"