void ViewObject::setHallu(bool b) { if (!hallu && b) { shuffledCreatures = randomPermutation(creatureIds); shuffledItems = randomPermutation(itemIds); } hallu = b; }
// create a random graph graph createGraph(int n, int m, double minWeight, double maxWeight) { graph graph; graph.n = n; graph.m = 0; int i; // allocate the memory for the adjacency lists graph.edges = malloc(sizeof(edge) * m); if (graph.edges == NULL) error("Impossible d'allouer le graphe."); // force the graph to be connex int *ord = randomPermutation(n); for (i = 1; i < n; ++i) { graph.edges[graph.m].x = ord[i]; graph.edges[graph.m].y = ord[uniformDistributionInt(0, i)]; graph.edges[graph.m].w = uniformDistributionDouble(minWeight, maxWeight); graph.m++; } for (i = graph.m; i < m; ++i) { int ec = uniformDistributionInt(0, n * n); graph.edges[graph.m].x = ec % n; graph.edges[graph.m].y = ec / n; graph.edges[graph.m].w = uniformDistributionDouble(minWeight, maxWeight); graph.m++; } graph.m = m; return graph; }
Vec2 Level::landCreature(vector<Vec2> landing, Creature* creature) { CHECK(creature); if (creature->isPlayer()) player = creature; if (entryMessage != "") { creature->playerMessage(entryMessage); entryMessage = ""; } queue<pair<Vec2, Vec2>> q; for (Vec2 pos : randomPermutation(landing)) q.push(make_pair(pos, pos)); while (!q.empty()) { pair<Vec2, Vec2> v = q.front(); q.pop(); if (squares[v.first]->canEnter(creature)) { putCreature(v.first, creature); return v.second; } else for (Vec2 next : v.first.neighbors8(true)) if (next.inRectangle(squares.getBounds()) && squares[next]->canEnterEmpty(creature)) q.push(make_pair(next, v.second)); } FAIL << "Failed to find any square to put creature"; return Vec2(0, 0); }
void KdTree::naiveBuild (LineSegments &lineSegments) { // Compute a random permutation p5, p6, . . . , pn of the remaining points. int n = lineSegments.size(); int *p = new int [n]; randomPermutation (n, p); for (int i = 0; i < lineSegments.size(); ++i) { insert(lineSegments[p[i]]); } }
void convexHull3 (Points &points, vector<int> &hull) { if (points.size() < 4) { return; } Arrangement arr; // add vertices for (int i = 0; i < points.size(); ++i) { Vertex *v = arr.addVertex(points[i]); v->id = vertex_id++; } init(arr); // Compute a random permutation p5, p6, . . . , pn of the remaining points. int n = points.size() - 4; int *p = new int [n]; randomPermutation (n, p); for (int i = 4; i < arr.vertices.size(); ++i) { int r = p[i - 4] + 4; // Fconflict(Pr) is empty (that is, Pr lies inside C), nothing changes. if (arr.vertices[r]->visibleFaces.size() == 0) continue; // Compute the horizon Edges horizon; findHorizon(arr, arr.vertices[r], horizon); // list up all the vertices that have to be tested for the conflict graph Vertices vertices; listUpdateVertices(arr, arr.vertices[r], horizon, vertices); // delete all the visible faces and edges except the horizon deleteVisibleCone(arr, arr.vertices[r]); // add all the outgoing edges from Pr, and all the new faces addCone(arr, arr.vertices[r], horizon, vertices); } // build the return values buildHull(arr, hull); // debug std::ofstream ofs("test.vtk"); outputVTK(points, hull, ofs); }
GuidedLocalSearch::Candidate GuidedLocalSearch::search(const std::vector<std::pair<float, float>>& cities, const int kIterLimit, const int kNoImproveLimit, const float kLambda) { srand(static_cast<unsigned>(time(nullptr))); std::vector<std::vector<float>> penalties(cities.size(), std::vector<float>(cities.size(), 0.0f)); GuidedLocalSearch::Candidate current, best; current.permutation = randomPermutation(cities); for (int iter = 0; iter < kIterLimit; ++iter) { localSearch(current, cities, penalties, kNoImproveLimit, kLambda); std::vector<float> utilities = calcualateFeaturesUtilities(cities, current.permutation, penalties); updatePenalties(penalties, cities, current.permutation, utilities); if (!iter || current.ordinaryCost < best.ordinaryCost) { best.permutation = current.permutation; best.ordinaryCost = current.ordinaryCost; best.augmentedCost = current.augmentedCost; } } return best; }
void resetPlayerData(void) { int i; Data *data; AI *ai; int not_playing = 0; int *startIndex; startIndex = malloc( game->players * sizeof(int) ); randomPermutation(game->players, startIndex); for(i = 0; i < game->players; i++) { float startpos[][2] = { { 0.5, 0.25 }, { 0.75, 0.5 }, { 0.5, 0.75 }, { 0.25, 0.5 } }; float x, y; data = game->player[i].data; ai = game->player[i].ai; /* init ai */ switch(i) { case 0: ai->active = getSettingi("ai_player1"); break; case 1: ai->active = getSettingi("ai_player2"); break; case 2: ai->active = getSettingi("ai_player3"); break; case 3: ai->active = getSettingi("ai_player4"); break; default: fprintf(stderr, "[error] player index #%d not caught!\n", i); ai->active = AI_NONE; } ai->tdiff = 0; /* arrange players in circle around center */ /* randomize position on the grid */ x = startpos[ startIndex[i] ][0] * getSettingi("grid_size"); y = startpos[ startIndex[i] ][1] * getSettingi("grid_size"); /* randomize starting direction */ data->dir = trand() & 3; /* data->dir = startdir[i]; */ data->last_dir = data->dir; /* if player is playing... */ if(ai->active != AI_NONE) { data->speed = getSettingf("speed"); data->booster = getSettingf("booster_max"); data->boost_enabled = 0; data->trail_height = TRAIL_HEIGHT; } else { data->speed = SPEED_GONE; data->trail_height = 0; not_playing++; } // data->trail = data->trails; data->trailOffset = 0; data->trails[ data->trailOffset ].vStart.v[0] = x; data->trails[ data->trailOffset ].vStart.v[1] = y; data->trails[ data->trailOffset ].vDirection.v[0] = 0; data->trails[ data->trailOffset ].vDirection.v[1] = 0; { int camType; Camera *cam = game->player[i].camera; camType = (game->player[i].ai->active == AI_COMPUTER) ? CAM_CIRCLE : gSettingsCache.camType; initCamera(cam, data, camType); } } free(startIndex); game->running = game->players - not_playing; /* not everyone is alive */ /* printf("starting game with %d players\n", game->running); */ game->winner = -1; }
void Deity::onPrayer(Creature* c) { bool prayerAnswered = false; for (Epithet epithet : randomPermutation(epithets)) { if (contains(usedEpithets, epithet)) continue; bool noEffect = false; switch (epithet) { case Epithet::DEATH: { PCreature death = CreatureFactory::fromId(CreatureId::DEATH, Tribes::get(TribeId::KILL_EVERYONE)); for (Vec2 v : c->getPosition().neighbors8(true)) if (c->getLevel()->inBounds(v) && c->getLevel()->getSquare(v)->canEnter(death.get())) { c->privateMessage("Death appears before you."); c->getLevel()->addCreature(v, std::move(death)); break; } if (death) noEffect = true; break; } case Epithet::WAR: grantGift(c, chooseRandom( {ItemId::SPECIAL_SWORD, ItemId::SPECIAL_BATTLE_AXE, ItemId::SPECIAL_WAR_HAMMER}), name); break; case Epithet::WISDOM: grantGift(c, chooseRandom({ItemId::MUSHROOM_BOOK, ItemId::POTION_BOOK, ItemId::AMULET_BOOK}), name); break; case Epithet::DESTRUCTION: applyEffect(c, EffectType::DESTROY_EQUIPMENT, ""); break; case Epithet::SECRETS: grantGift(c, ItemId::INVISIBLE_POTION, name); break; case Epithet::LIGHTNING: c->bleed(0.9); c->you(MsgType::ARE, "struck by a lightning bolt!"); break; case Epithet::FEAR: applyEffect(c, EffectType::PANIC, name + " puts fear in your heart"); break; case Epithet::MIND: if (Random.roll(2)) applyEffect(c, EffectType::RAGE, name + " fills your head with anger"); else applyEffect(c, EffectType::HALLU, ""); break; case Epithet::CHANGE: if (Random.roll(2) && c->getEquipment().getItem(EquipmentSlot::WEAPON)) { PCreature snake = CreatureFactory::fromId(CreatureId::SNAKE, Tribes::get(TribeId::PEST)); for (Vec2 v : c->getPosition().neighbors8(true)) if (c->getLevel()->inBounds(v) && c->getLevel()->getSquare(v)->canEnter(snake.get())) { c->getLevel()->addCreature(v, std::move(snake)); c->steal({c->getEquipment().getItem(EquipmentSlot::WEAPON)}); c->privateMessage("Ouch!"); c->you(MsgType::YOUR, "weapon turns into a snake!"); break; } if (!snake) break; } for (Item* it : randomPermutation(c->getEquipment().getItems())) { if (it->getType() == ItemType::POTION) { c->privateMessage("Your " + it->getName() + " changes color!"); c->steal({it}); c->take(ItemFactory::potions().random()); break; } if (it->getType() == ItemType::SCROLL) { c->privateMessage("Your " + it->getName() + " changes label!"); c->steal({it}); c->take(ItemFactory::scrolls().random()); break; } if (it->getType() == ItemType::AMULET) { c->privateMessage("Your " + it->getName() + " changes shape!"); c->steal({it}); c->take(ItemFactory::amulets().random()); break; } } break; case Epithet::HEALTH: if (c->getHealth() < 1 || c->lostLimbs()) applyEffect(c, EffectType::HEAL, "You feel a healing power overcoming you"); else { if (Random.roll(4)) grantGift(c, ItemId::HEALING_AMULET, name); else grantGift(c, ItemId::HEALING_POTION, name, Random.getRandom(1, 4)); } break; case Epithet::NATURE: grantGift(c, ItemId::FRIENDLY_ANIMALS_AMULET, name); break; // case Epithet::LOVE: grantGift(c, ItemId::PANIC_MUSHROOM, name); break; case Epithet::WEALTH: grantGift(c, ItemId::GOLD_PIECE, name, Random.getRandom(100, 200)); break; case Epithet::DEFENSE: grantGift(c, ItemId::DEFENSE_AMULET, name); break; case Epithet::DARKNESS: applyEffect(c, EffectType::BLINDNESS, ""); break; case Epithet::CRAFTS: applyEffect(c, chooseRandom({EffectType::ENHANCE_ARMOR, EffectType::ENHANCE_WEAPON}), ""); break; // case Epithet::HUNTING: grantGift(c, ItemId::PANIC_MUSHROOM, name); break; default: noEffect = true; } usedEpithets.push_back(epithet); if (!noEffect) { prayerAnswered = true; break; } } if (!prayerAnswered) c->privateMessage("Your prayer is not answered."); }
AlphaReal SigmoidSingleStumpLearner::run() { const int numClasses = _pTrainingData->getNumClasses(); const int numColumns = _pTrainingData->getNumAttributes(); const int numExamples = _pTrainingData->getNumExamples(); FeatureReal bestEdge = -numeric_limits<FeatureReal>::max(); vector<AlphaReal> bestv(numClasses); _v.resize(numClasses); AlphaReal gammat = _initialGammat; if (_verbose>4) cout << "-->Init gamma: " << gammat << endl; // set the smoothing value to avoid numerical problem // when theta=0. setSmoothingVal( 1.0 / (AlphaReal)_pTrainingData->getNumExamples() * 0.01 ); vector<FeatureReal> sigmoidSlopes( numColumns ); vector<FeatureReal> sigmoidOffSets( numColumns ); vector<vector<AlphaReal> > vsArray(numColumns); fill( sigmoidSlopes.begin(), sigmoidSlopes.end(), 0.1 ); fill( sigmoidOffSets.begin(), sigmoidOffSets.end(), 0.0 ); for(int i=0; i<numColumns; ++i ) { vsArray[i].resize(numClasses); for (int k=0; k<numClasses; ++k ) { vsArray[i][k] = (rand() % 2) * 2 - 1; } normalizeLength( vsArray[i] ); //fill(vsArray[i].begin(),vsArray[i].end(),0.0); } if ( _gMethod == OPT_SGD ) { vector<int> randomPermutation(numExamples); for (int i = 0; i < numExamples; ++i ) randomPermutation[i]=i; random_shuffle( randomPermutation.begin(), randomPermutation.end() ); AlphaReal gammaDivider = 1.0; for (int i = 0; i < numExamples; ++i ) { if ((i>0)&&((i%_gammdivperiod)==0)) gammaDivider += 1.0; AlphaReal stepOffSet, stepSlope, stepV; //int randomTrainingInstanceIdx = (rand() % _pTrainingData->getNumExamples()); int randomTrainingInstanceIdx = randomPermutation[i]; vector<Label> labels = _pTrainingData->getLabels(randomTrainingInstanceIdx); for (int j = 0; j < numColumns; ++j) { FeatureReal val = _pTrainingData->getValue(randomTrainingInstanceIdx, j); FeatureReal tmpSigVal = sigmoid(val,sigmoidSlopes[j],sigmoidOffSets[j]); AlphaReal deltaQ = 0.0; switch (_tFunction) { case TF_EXPLOSS: for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { deltaQ += exp( -vsArray[j][it->idx] * it->y * ( 2*tmpSigVal-1 ) ) *2.0 * it->weight*vsArray[j][it->idx]*it->y*tmpSigVal*(1.0-tmpSigVal); } stepOffSet = -deltaQ; stepSlope = -deltaQ * val; break; case TF_EDGE: for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { deltaQ += 2.0 * it->weight*vsArray[j][it->idx]*it->y*tmpSigVal*(1.0-tmpSigVal); } // because edge should be maximized stepOffSet = -deltaQ; stepSlope = -deltaQ * val; break; default: break; } // gradient step FeatureReal tmpSigmoidOffSet = sigmoidOffSets[j] - numExamples * static_cast<FeatureReal>(gammat * stepOffSet); FeatureReal tmpSigmoidSlopes = sigmoidSlopes[j] - numExamples * static_cast<FeatureReal>(gammat * stepSlope); // update the parameters for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { switch (_tFunction) { case TF_EXPLOSS: stepV = -exp( - vsArray[j][it->idx] * it->y * ( 2*tmpSigVal-1 ) ) * ( it->weight * (2.0 * tmpSigVal - 1.0) * it->y); break; case TF_EDGE: // + gradient since it a maximization task stepV = - ( it->weight * (2.0 * tmpSigVal - 1.0) * it->y); break; } vsArray[j][it->idx] = vsArray[j][it->idx] - gammat * stepV; } normalizeLength( vsArray[j] ); sigmoidOffSets[j] = tmpSigmoidOffSet; sigmoidSlopes[j] = tmpSigmoidSlopes; } // decrease gammat gammat = gammat / gammaDivider; } } else if (_gMethod == OPT_BGD ) { AlphaReal gammaDivider = 1.0; for (int gradi=0; gradi<_maxIter; ++gradi) { if ((gradi>0)&&((gradi%_gammdivperiod)==0)) gammaDivider += 1.0; for (int j = 0; j < numColumns; ++j) { AlphaReal slopeImporvemement = 0.0; AlphaReal offsetImporvemement = 0.0; vector<AlphaReal> vImprovement(numClasses); fill(vImprovement.begin(),vImprovement.end(),0.0); switch (_tFunction) { case TF_EXPLOSS: for (int i = 0; i < numExamples; ++i ) { vector<Label> labels = _pTrainingData->getLabels(i); FeatureReal val = _pTrainingData->getValue(i,j); // update the parameters FeatureReal tmpSigVal = sigmoid(val,sigmoidSlopes[j],sigmoidOffSets[j]); AlphaReal deltaQ = 0.0; for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { deltaQ += exp( -vsArray[j][it->idx] * it->y * ( 2*tmpSigVal-1 ) ) * 2.0 * it->weight*vsArray[j][it->idx]*it->y*tmpSigVal*(1.0-tmpSigVal); } offsetImporvemement -= deltaQ; slopeImporvemement -= (deltaQ*val); for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { // + gradient since it a maximization task vImprovement[it->idx] -= exp( -vsArray[j][it->idx] * it->y * ( 2*tmpSigVal-1 ) ) * ( it->weight * (2.0 * tmpSigVal - 1.0) * it->y); } } break; case TF_EDGE: for (int i = 0; i < numExamples; ++i ) { vector<Label> labels = _pTrainingData->getLabels(i); FeatureReal val = _pTrainingData->getValue(i,j); // update the parameters FeatureReal tmpSigVal = sigmoid(val,sigmoidSlopes[j],sigmoidOffSets[j]); AlphaReal deltaQ = 0.0; for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { deltaQ += 2.0 * it->weight*vsArray[j][it->idx]*it->y*tmpSigVal*(1.0-tmpSigVal); } offsetImporvemement -= deltaQ; slopeImporvemement -= (deltaQ*val); for( vector< Label >::iterator it = labels.begin(); it != labels.end(); it++ ) { // + gradient since it a maximization task vImprovement[it->idx] -= ( it->weight * (2.0 * tmpSigVal - 1.0) * it->y); } } break; } //update the current parameter vector for( int iimp=0; iimp < vImprovement.size(); ++iimp ) { // + gradient since it a maximization task vsArray[j][iimp] -= gammat * vImprovement[iimp]; //vsArray[j][iimp] += 100.0 * gammat * vImprovement[iimp]; } normalizeLength( vsArray[j] ); sigmoidOffSets[j] -= gammat * offsetImporvemement; //sigmoidOffSets[j] += 100.0 * gammat * offsetImporvemement; sigmoidSlopes[j] -= gammat * slopeImporvemement; //sigmoidSlopes[j] += 100.0 * gammat * slopeImporvemement; // decrease gammat gammat = gammat / gammaDivider; } // j } } else { cout << "Unknown optimization method!" << endl; exit(-1); } int bestColumn = -1; // find the best feature for (int j = 0; j < numColumns; ++j) { _selectedColumn = j; _sigmoidSlope = sigmoidSlopes[j]; _sigmoidOffset = sigmoidOffSets[j]; _v = vsArray[j]; for(int k=0; k<numClasses; ++k ) _v[k]= _v[k] < 0 ? -1.0 : 1.0; AlphaReal tmpEdge = this->getEdge(); if ((tmpEdge>0.0) && (tmpEdge>bestEdge)) { bestEdge = tmpEdge; bestv = _v; bestColumn = j; } } _selectedColumn = bestColumn; if (_verbose>3) cout << "Selected column: " << _selectedColumn << endl; if ( _selectedColumn != -1 ) { stringstream parameterString; parameterString << _sigmoidSlope << "_" << _sigmoidOffset; _id = _pTrainingData->getAttributeNameMap().getNameFromIdx(_selectedColumn) + _id + parameterString.str(); } else { return numeric_limits<AlphaReal>::signaling_NaN(); } _sigmoidSlope = sigmoidSlopes[_selectedColumn]; _sigmoidOffset = sigmoidOffSets[_selectedColumn]; _v = bestv; //normalizeLength( _v ); if (_verbose>3) { cout << "Sigmoid slope:\t" << _sigmoidSlope << endl; cout << "Sigmoid offset:\t" << _sigmoidOffset << endl; } //calculate alpha this->_alpha = 0.0; AlphaReal eps_min = 0.0, eps_pls = 0.0; //_pTrainingData->clearIndexSet(); for( int i = 0; i < _pTrainingData->getNumExamples(); i++ ) { vector< Label> l = _pTrainingData->getLabels( i ); for( vector< Label >::iterator it = l.begin(); it != l.end(); it++ ) { AlphaReal result = this->classify( _pTrainingData, i, it->idx ); result *= (it->y * it->weight); if ( result < 0 ) eps_min -= result; if ( result > 0 ) eps_pls += result; } } this->_alpha = getAlpha( eps_min, eps_pls ); // calculate the energy (sum of the energy of the leaves //AlphaReal energy = this->getEnergy( eps_min, eps_pls ); return bestEdge; }
/************************************************************************************* * Function: randomMode() * Description: This is the function to handle User Input Mode * Return: 0-Success, 1-Unsucessful * Input: N/A ************************************************************************************/ void randomMode(){ int inputCase1[5000], operation, randomData, iCase, nTime; int ipCase[7] = {100, 500, 1000, 2000, 3000, 4000, 5000}; clock_t Start, Time, fTime=0; printf("Calculating Processing Time for Fibonacci Heap & Leftist Tree...\n"); //Fibonacci Heap for(iCase = 0; iCase<7; iCase++){ fTime=0; for(nTime=0; nTime<5; nTime++){ randomPermutation(inputCase1, iCase); //Generating Random Permutation of Inputs MIN = intializeFMinHeap(MIN, inputCase1, iCase); //Initializing Fibbonacci Heap Start = clock(); //Start time //Operation Generator Sequence for(operation=1;operation<=MAX_OPERATIONS; operation++){ if(log == DEBUG) printf("\nPeforming operation #%d\n", operation); D = rand() % 2; randomData = rand() % 10000; //Data's range is b/w 0-9999 if(D == 0){ if(log == DEBUG) printf("Deleting MIN............\n"); MIN = deleteMin_MinFHeap(MIN); } else{ if(log == DEBUG) printf("Inserting %d............\n", randomData); //Insert MIN = insert_MinFHeap(MIN, randomData); } } Time = clock() - Start; fTime +=(Time/5000L); } printf("********************************************************************\n"); printf("Time taken for input size %d in Fibonacci Heap is %ldms: \n", ipCase[iCase], (fTime/5L)); printf("********************************************************************\n"); } //Leftist Tree for(iCase = 0; iCase<7; iCase++){ fTime=0; for(nTime=0; nTime<5; nTime++){ randomPermutation(inputCase1, iCase); //Generating Random Permutation of Inputs ROOT = initializeLeftistTree(ROOT, inputCase1, iCase); //Initializing Fibbonacci Heap Start = clock(); //Start time //Operation Generator Sequence for(operation=1;operation<=MAX_OPERATIONS; operation++){ if(log == DEBUG) printf("\nPeforming operation #%d\n", operation); D = rand() % 2; randomData = rand() % 10000; //Data's range is b/w 0-9999 if(D == 0){ if(log == DEBUG) printf("Deleting MIN............\n"); ROOT = deleteMinLeftistTree(ROOT); } else{ if(log == DEBUG) printf("Inserting %d............\n", randomData); //Insert ROOT = insertMinLeftistTree(ROOT, randomData); } } Time = clock() - Start; fTime +=(Time/5000L); } printf("********************************************************************\n"); printf("Time taken for input size %d in Leftist Tree is %ldms: \n", ipCase[iCase], (fTime/5L)); printf("********************************************************************\n"); } }
API void initPerlin() { permutation = randomPermutation(256); }
/** * Delaunay triangulation using the same algorithm as convexHull3. */ void triangulate (Points2D &points2D, vector<int> &triangles) { if (points2D.size() < 4) { triangles.push_back(0); triangles.push_back(1); triangles.push_back(2); return; } Arrangement arr; // arrange the 3D points Points points; for (int i = 0; i < points2D.size(); ++i) { double x = points2D[i]->getP().getX().mid(); double y = points2D[i]->getP().getY().mid(); double z = x * x + y * y; points.push_back(new InputPoint(x * 2, y * 2, z)); } // add vertices for (int i = 0; i < points.size(); ++i) { Vertex *v = arr.addVertex(points[i]); v->id = vertex_id++; } init(arr); // Compute a random permutation p5, p6, . . . , pn of the remaining points. int n = points.size() - 4; int *p = new int [n]; randomPermutation (n, p); for (int i = 4; i < arr.vertices.size(); ++i) { int r = p[i - 4] + 4; // Fconflict(Pr) is empty (that is, Pr lies inside C), nothing changes. if (arr.vertices[r]->visibleFaces.size() == 0) continue; // compute the horizon Edges horizon; findHorizon(arr, arr.vertices[r], horizon); // list up all the vertices that have to be tested for the conflict graph Vertices vertices; listUpdateVertices(arr, arr.vertices[r], horizon, vertices); // delete all the visible faces and edges except the horizon deleteVisibleCone(arr, arr.vertices[r]); // add all the outgoing edges from Pr, and all the new faces addCone(arr, arr.vertices[r], horizon, vertices); } // list up all the faces that are visible from (0, 0, -oo) for (Faces::iterator f = arr.faces.begin(); f != arr.faces.end(); ++f) { Vertex *v0 = (*f)->edge->tail; Vertex *v1 = (*f)->edge->twin->next->tail; Vertex *v2 = (*f)->edge->twin->next->twin->next->tail; // if it is not visible, then skip it. PV3 u = v1->p->getP() - v0->p->getP(); PV3 v = v2->p->getP() - v0->p->getP(); PV3 w(0, 0, -1); if (w.tripleProduct(u, v).sign() <= 0) continue; // if it is visible, then copy the indices to the result. // Note that since the triangle is in counter-clockwise order viewed from the bottom, // we have to reverse the order to get the counter-clockwise order viewed from the top. triangles.push_back(v0->id); triangles.push_back(v2->id); triangles.push_back(v1->id); } }