/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ #include #include #include #include #include "IfAssert.h" #include "IfHasher.h" ///////////////////////////////////////////////////////////////////////////// // // Constructors for 2- or 3-dimensional vectors. // ///////////////////////////////////////////////////////////////////////////// IfHasher::IfHasher(SoMFVec2f *field, int maxNumVectors, const SbVec2f &min, const SbVec2f &scale) { dimension = 2; field2 = field; field3 = NULL; hashMin[0] = min[0]; hashMin[1] = min[1]; hashMin[2] = 0.0; hashScale[0] = scale[0]; hashScale[1] = scale[1]; hashScale[2] = 1.0; maxNum = maxNumVectors; commonConstructor(); } IfHasher::IfHasher(SoMFVec3f *field, int maxNumVectors, const SbVec3f &min, const SbVec3f &scale) { dimension = 3; field2 = NULL; field3 = field; hashMin = min; hashScale = scale; maxNum = maxNumVectors; commonConstructor(); } ///////////////////////////////////////////////////////////////////////////// // // Stuff common to both constructors. // ///////////////////////////////////////////////////////////////////////////// void IfHasher::commonConstructor() { // Create an array of HashEntry instances entries = new HashEntry[maxNum]; curEntry = 0; // Make room in the field and begin editing if (dimension == 2) { field2->setNum(maxNum); vectors2 = field2->startEditing(); vectors3 = NULL; } else { field3->setNum(maxNum); vectors3 = field3->startEditing(); vectors2 = NULL; } // Set up the dictionary vectorDict = new SbDict(1235); // Multiply the scale values by some arbitrary numbers to make // the hash function more random hashScale[0] *= 233; hashScale[1] *= 72091; hashScale[2] *= 453451; } ///////////////////////////////////////////////////////////////////////////// // // Destructor. // ///////////////////////////////////////////////////////////////////////////// IfHasher::~IfHasher() { } ///////////////////////////////////////////////////////////////////////////// // // These add a vector to the list, returning its index. Room is // made in the field, if necessary. // ///////////////////////////////////////////////////////////////////////////// int IfHasher::addVector(const SbVec2f &newVector) { ASSERT(vectorDict != NULL); ASSERT(dimension == 2); // See if we need to add this one, or is it already there int index; SbBool notThere = addIfNotThere(newVector.getValue(), index); // If it's not there, we need to add it to the field if (notThere) vectors2[index] = newVector; return index; } int IfHasher::addVector(const SbVec3f &newVector) { ASSERT(vectorDict != NULL); ASSERT(dimension == 3); // See if we need to add this one, or is it already there int index; SbBool notThere = addIfNotThere(newVector.getValue(), index); // If it's not there, we need to add it to the field if (notThere) vectors3[index] = newVector; return index; } ///////////////////////////////////////////////////////////////////////////// // // Adds the given vector to the hash table, if it is not already // there. Returns TRUE if the vector was added. // ///////////////////////////////////////////////////////////////////////////// SbBool IfHasher::addIfNotThere(const float *newVector, int &index) { ASSERT(curEntry < maxNum - 1); // Find the hash key uint32_t key = hashVector(newVector); // See if there already is a list of vectors with the same key void *list; if (vectorDict->find(key, list)) { // If so, look through the list for an exact match HashEntry *entry, *prevEntry = NULL; for (entry = (HashEntry *) list; entry != NULL; entry = entry->next) { ASSERT(entry->index < curEntry); // If the vectors are the same, re-use the old one and stop if (sameVector(newVector, entry->index)) { index = entry->index; return FALSE; } prevEntry = entry; } // If there were no matches, add the new vector to the end of // the list ASSERT(prevEntry != NULL); entry = &entries[curEntry]; entry->index = curEntry; entry->next = NULL; prevEntry->next = entry; } // If there were no entries in the dictionary, start one else { HashEntry *entry = &entries[curEntry]; entry->index = curEntry; entry->next = NULL; vectorDict->enter(key, entry); } index = curEntry++; return TRUE; } ///////////////////////////////////////////////////////////////////////////// // // Hash function for finding duplicate vectors. // ///////////////////////////////////////////////////////////////////////////// uint32_t IfHasher::hashVector(const float *v) { float sum = 0.0; for (int i = 0; i < dimension; i++) sum += (v[i] - hashMin[i]) * hashScale[i]; return (int32_t) sum; } ///////////////////////////////////////////////////////////////////////////// // // Returns TRUE if the given vector matches the given existing vector. // ///////////////////////////////////////////////////////////////////////////// SbBool IfHasher::sameVector(const float *vector, int index) { if (dimension == 2) return (vector[0] == vectors2[index][0] && vector[1] == vectors2[index][1]); else return (vector[0] == vectors3[index][0] && vector[1] == vectors3[index][1] && vector[2] == vectors3[index][2]); } ///////////////////////////////////////////////////////////////////////////// // // Finishes up. // ///////////////////////////////////////////////////////////////////////////// void IfHasher::finish() { // Stop editing and set the field to contain the correct number of // values if (dimension == 2) { field2->finishEditing(); field2->setNum(curEntry); } else { field3->finishEditing(); field3->setNum(curEntry); } // Get rid of the dictionary and the HashEntry instances delete vectorDict; delete [] entries; // Make sure nobody uses this again vectorDict = NULL; }