void Preferences::applyDefaults() { fl::Engine* engine = Model::Default()->engine(); if (engine->numberOfRuleBlocks() == 0) { QMessageBox::critical(this, "Error", "Current engine has no rule blocks. " "At least one ruleblock was expected.", QMessageBox::Ok); return; } std::string tnorm = Minimum().className(); std::string snorm = Maximum().className(); std::string activation = Minimum().className(); RuleBlock* ruleblock = engine->getRuleBlock(0); if (ruleblock->getTnorm()) tnorm = ruleblock->getTnorm()->className(); if (ruleblock->getSnorm()) snorm = ruleblock->getSnorm()->className(); if (ruleblock->getActivation()) activation = ruleblock->getActivation()->className(); std::string defuzzifier = Centroid().className(); int divisions = fl::fuzzylite::defaultDivisions(); std::string accumulation = Maximum().className(); if (engine->numberOfOutputVariables() > 0) { OutputVariable* variable = engine->getOutputVariable(0); if (variable->getDefuzzifier()) { defuzzifier = variable->getDefuzzifier()->className(); divisions = variable->getDefuzzifier()->getDivisions(); } if (variable->output()->getAccumulation()) accumulation = variable->output()->getAccumulation()->className(); } engine->configure(tnorm, snorm, activation, accumulation, defuzzifier, divisions); }
int main(int, const char * []) { IloEnv env; try { IloIntVarArray x(env); for (IloInt i = 0; i < 10; i++) { char name[6]; sprintf(name, "X%ld", i); x.add(IloIntVar(env, 0, 100 - 2*(i / 2), name)); } IloModel mdl(env); mdl.add(IloAllDiff(env, x)); mdl.add(x); IloIntVarChooser varChooser = ChooseSmallestCentroid(env); IloIntValueChooser valChooser = ChooseSmallestDistanceFromCentroid(env); IloSearchPhase sp1(env, x, varChooser, valChooser); IloIntVarEval varEval = Centroid(env); IloIntValueEval valEval = DistanceFromCentroid(env); IloSearchPhase sp2(env, x, IloSelectSmallest(varEval), IloSelectSmallest(valEval)); // sp2 can have ties as two variable or values could evaluate // to the same values. sp3 shows how to break these ties // choosing, for equivalent centroid and distance-to-centroid // evaluations, the lowest indexed variable in x and the // lowest value. IloVarSelectorArray selVar(env); selVar.add(IloSelectSmallest(varEval)); selVar.add(IloSelectSmallest(IloVarIndex(env, x))); // break ties on index IloValueSelectorArray selValue(env); selValue.add(IloSelectSmallest(valEval)); selValue.add(IloSelectSmallest(IloValue(env))); // break ties on smallest IloSearchPhase sp3(env, x, selVar, selValue); IloCP cp(mdl); cp.setParameter(IloCP::Workers, 1); cp.setParameter(IloCP::SearchType, IloCP::DepthFirst); cp.setParameter(IloCP::LogPeriod, 1); cp.out() << "Choosers" << std::endl; cp.solve(sp1); cp.out() << cp.domain(x) << std::endl; cp.out() << "Evaluators" << std::endl; cp.solve(sp2); cp.out() << cp.domain(x) << std::endl; cp.out() << "Evaluators (with tie-break)" << std::endl; cp.solve(sp3); cp.out() << cp.domain(x) << std::endl; cp.end(); } catch (IloException & ex) { env.out() << "Caught: " << ex << std::endl; } env.end(); return 0; }
const R3Sphere R3Triangle:: BSphere(void) const { // Return bounding sphere (is this right???) R3Point centroid = Centroid(); RNLength radius = R3Distance(centroid, v[0]->Position()); return R3Sphere(centroid, radius); }
void Polygon::ScaleCenter(Vector3 scale_amount) { if(vertices.empty()) return; Vector3 centroid = Centroid(); Translate(-centroid); Scale(scale_amount); Translate(centroid); }
void R3Box:: Inflate (RNScalar fraction) { // Scale box around centroid by fraction if (IsEmpty()) return; R3Point centroid = Centroid(); R3Vector diagonal = Max() - centroid; Reset(centroid - fraction * diagonal, centroid + fraction * diagonal); }
float IndicativeAngle(Array* points) { Vec2 centroid = Centroid(points); PointObject* firstPoint = (PointObject*)points->getObjectAtIndex(0); float x = (centroid.x - firstPoint->x); float y = (centroid.y - firstPoint->y); return atan2f(y, x); }
DefuzzifierFactory::DefuzzifierFactory() { registerClass(Bisector().className(), &(Bisector::constructor)); registerClass(Centroid().className(), &(Centroid::constructor)); registerClass(LargestOfMaximum().className(), &(LargestOfMaximum::constructor)); registerClass(MeanOfMaximum().className(), &(MeanOfMaximum::constructor)); registerClass(SmallestOfMaximum().className(), &(SmallestOfMaximum::constructor)); registerClass(WeightedAverage().className(), &(WeightedAverage::constructor)); registerClass(WeightedSum().className(), &(WeightedSum::constructor)); }
void BinarySpaceTree<BoundType, StatisticType, MatType, SplitType>::SplitNode( MatType& data, std::vector<size_t>& oldFromNew, const size_t maxLeafSize, SplitType& splitter) { // This should be a single function for Bound. // We need to expand the bounds of this node properly. bound |= data.cols(begin, begin + count - 1); // Calculate the furthest descendant distance. furthestDescendantDistance = 0.5 * bound.Diameter(); // First, check if we need to split at all. if (count <= maxLeafSize) return; // We can't split this. // splitCol denotes the two partitions of the dataset after the split. The // points on its left go to the left child and the others go to the right // child. size_t splitCol; // Split the node. The elements of 'data' are reordered by the splitting // algorithm. This function call updates splitCol and oldFromNew. const bool split = splitter.SplitNode(bound, data, begin, count, splitCol, oldFromNew); // The node may not be always split. For instance, if all the points are the // same, we can't split them. if (!split) return; // Now that we know the split column, we will recursively split the children // by calling their constructors (which perform this splitting process). left = new BinarySpaceTree<BoundType, StatisticType, MatType>(data, begin, splitCol - begin, oldFromNew, splitter, this, maxLeafSize); right = new BinarySpaceTree<BoundType, StatisticType, MatType>(data, splitCol, begin + count - splitCol, oldFromNew, splitter, this, maxLeafSize); // Calculate parent distances for those two nodes. arma::vec centroid, leftCentroid, rightCentroid; Centroid(centroid); left->Centroid(leftCentroid); right->Centroid(rightCentroid); const double leftParentDistance = bound.Metric().Evaluate(centroid, leftCentroid); const double rightParentDistance = bound.Metric().Evaluate(centroid, rightCentroid); left->ParentDistance() = leftParentDistance; right->ParentDistance() = rightParentDistance; }
void TranslateToOrigin(PointVector& points) { PointPtr c = Centroid(points); PointVector newpoints; for (size_t i = 0; i < points.size(); ++i) { double qx = points[i]->X - c->X; double qy = points[i]->Y - c->Y; newpoints.push_back(PointPtr(new Point(qx, qy))); } points.clear(); points.insert(points.begin(), newpoints.begin(), newpoints.end()); }
/**--------------------------------------------------------------------------<BR> C2DPolyArc::GetCentroid <BR> \brief Calculates the centroid of the shape by calculating the centroid of the simple polygon then shifting it by the area weighted centroids of the segments defined by the arcs. <P>---------------------------------------------------------------------------*/ C2DPoint C2DPolyArc::GetCentroid(void) const { // Find the centroid and area of the straight line polygon. C2DPoint Centroid(0, 0); C2DPoint pti; C2DPoint ptii; double dArea = 0; for (unsigned int i = 0; i < m_Lines.size(); i++) { pti = m_Lines[i].GetPointFrom(); ptii = m_Lines[i].GetPointTo(); Centroid.x += (pti.x + ptii.x) * (pti.x * ptii.y - ptii.x * pti.y); Centroid.y += (pti.y + ptii.y) * (pti.x * ptii.y - ptii.x * pti.y); dArea += pti.x * ptii.y - ptii.x * pti.y; } dArea = dArea / 2.0; Centroid.x = Centroid.x / (6.0 * dArea); Centroid.y = Centroid.y / (6.0 * dArea); std::vector<double> dSegAreas; double dTotalArea = dArea; std::vector<C2DPoint> SegCentroids; for (unsigned int i = 0; i < m_Lines.size(); i++) { if (m_Lines[i].GetType() == C2DLineBase::ArcedLine) { C2DSegment Seg( dynamic_cast<const C2DArc&>( m_Lines[i] ) ); double dSegArea = Seg.GetAreaSigned(); dTotalArea += dSegArea; dSegAreas.push_back( dSegArea ); SegCentroids.push_back( Seg.GetCentroid() ); } } Centroid = Centroid * dArea; for (unsigned int i = 0; i < dSegAreas.size(); i++) { Centroid += SegCentroids[i] * dSegAreas[i]; } Centroid = Centroid / dTotalArea; return Centroid; }
const Vector & QuadCell::getCentroidPosition(void) { int i, i1; double yi, zi, yi1, zi1, dyi, dzi; double area, integ; double CGy = 0.0, CGz = 0.0; area = this->getArea(); for (i = 0; i < 4; i++) { i1 = (i+1)%4; yi = vertCoord(i,0); zi = vertCoord(i,1); yi1 = vertCoord(i1,0); zi1 = vertCoord(i1,1); dyi = yi1 - yi; dzi = zi1 - zi; integ = yi*zi + (yi*dzi + zi*dyi)/2.0 + dyi*dzi/3.0; CGy -= dyi * integ; CGz += dzi * integ; } CGy /= area; CGz /= area; Centroid(0) = CGy; Centroid(1) = CGz; // opserr << "\narea : " << area << " centroid: " << Centroid; return Centroid; }
const R3Box R3Box:: Octant (RNDirection xdir, RNDirection ydir, RNDirection zdir) const { // Return box in octant (xdir, ydir, zdir) R3Box result; R3Point centroid = Centroid(); if (xdir == RN_HI) { result[RN_LO][RN_X] = centroid[RN_X]; result[RN_HI][RN_X] = maxpt[RN_X]; } else { result[RN_LO][RN_X] = minpt[RN_X]; result[RN_HI][RN_X] = centroid[RN_X]; } if (ydir == RN_HI) { result[RN_LO][RN_Y] = centroid[RN_Y]; result[RN_HI][RN_Y] = maxpt[RN_Y]; } else { result[RN_LO][RN_Y] = minpt[RN_Y]; result[RN_HI][RN_Y] = centroid[RN_Y]; } if (zdir == RN_HI) { result[RN_LO][RN_Z] = centroid[RN_Z]; result[RN_HI][RN_Z] = maxpt[RN_Z]; } else { result[RN_LO][RN_Z] = minpt[RN_Z]; result[RN_HI][RN_Z] = centroid[RN_Z]; } return result; }
float Fuzzy(int** regle, int TAILLE, float** MF_X, float A_norm, float B_norm, char* And, char* Or) { // Initialisation des variables utilisées dans le main // Compteurs int i = 0; int j = 0; // Variables d'échanges entre fonctions int MF_And[4] = {-1, -1, -1, -1}; float Y_And[4] = {-1, -1, -1, -1}; int N_And = 0; float Y_Or[14] = {0}; float X_Or[14] = {0}; int N_Or = 0; float Centroide = 0.0; // Variables de test int test_And; int test_Or; // On appele la fonction choisie pour le And pour commencer if ( strcmp(And, "Min") == 0) test_And = Min_Fun(TAILLE, regle, A_norm, B_norm, MF_X, MF_And, Y_And, &N_And); else if ( strcmp(And, "Product") == 0) test_And = ProdFun(TAILLE, regle, A_norm, B_norm, MF_X, MF_And, Y_And, &N_And); else return -2; // TO DO : définir les valeurs de sorties suivant les erreurs if (test_And != 0) return -1; // Ensuite, on appele la fonction pour le Or if ( strcmp(Or, "Max") == 0) test_Or = MaxFun(TAILLE, MF_X, MF_And, Y_And, N_And, X_Or, Y_Or, &N_Or); else if ( strcmp(Or, "ProbSum") == 0) i = 1;// à écrire else return -3; // cf. line 48 // Ensuite on calcule le centroide de tout ca Centroide = Centroid(X_Or, Y_Or, N_Or); // On a fini, on retourne le centroide return Centroide; }
Array* TranslateToOrigin(Array* points) { Array* translated = Array::create(); Vec2 centroid = Centroid(points); float qx; float qy; for (int i = 0; i < points->count(); i++) { PointObject* point = (PointObject*)points->getObjectAtIndex(i); qx = point->x - centroid.x; qy = point->y - centroid.y; translated->addObject(PointObject::create(qx, qy)); } return translated; }
void RotateBy(PointVector& points, double theta) { PointPtr c = Centroid(points); double cosine = cos(theta); double sine = sin(theta); PointVector newpoints; for (size_t i = 0; i < points.size(); ++i) { double qx = (points[i]->X - c->X) * cosine - (points[i]->Y - c->Y) * sine + c->X; double qy = (points[i]->X - c->X) * sine + (points[i]->Y - c->Y) * cosine + c->Y; newpoints.push_back(PointPtr(new Point(qx, qy))); } points.clear(); points.insert(points.begin(), newpoints.begin(), newpoints.end()); }
/*----------------------------------------------------------------------* | make a triangulization of a polygon (private) mwgee 10/05| *----------------------------------------------------------------------*/ bool MOERTEL::Overlap::Triangulation() { // we have a polygon that is in clockwise order at this moment // if more than 3 points, find a center point int np = SizePointPolygon(); if (np<3) { std::cout << "***ERR*** MOERTEL::Overlap::Triangulization:\n" << "***ERR*** # point in polygon < 3 ... very strange!!!\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; exit(EXIT_FAILURE); } if (np>3) // we have to add a center point { double xi[2]; std::vector<Teuchos::RCP<MOERTEL::Point> > points; PointView(points); #if 1 // compute center point xi as centroid Centroid(xi,points,np); //std::cout << "Centroid xi : " << xi[0] << " / " << xi[1] << endl; fflush(stdout); #endif #if 0 // compute center point as nodal avergage xi[0] = xi[1] = 0.0; for (int i=0; i<np; ++i) { const double* pxi = points[i]->Xi(); xi[0] += pxi[0]; xi[1] += pxi[1]; } xi[0] /= np; xi[1] /= np; //std::cout << "Nodal xi : " << xi[0] << " / " << xi[1] << endl << endl; fflush(stdout); #endif // create a point -1 as center point and add it to the polygon AddPointtoPolygon(-1,xi); points.clear(); } // if (np>3) np = SizePointPolygon(); std::vector<Teuchos::RCP<MOERTEL::Point> > points; PointView(points); // create a MOERTEL::Node for every point int dof[3]; dof[0] = dof[1] = dof[2] = -1; // find real world coords for all points // find real world normal for all points // note that the polygon is in slave segment parameter space and is // completely contained in the slave segment. we can therefore use // slave segment values to interpolate polgon point values for (int i=0; i<np; ++i) { double x[3]; x[0] = x[1] = x[2] = 0.0; double n[3]; n[0] = n[1] = n[2] = 0.0; double val[20]; sseg_.EvaluateFunction(0,points[i]->Xi(),val,sseg_.Nnode(),NULL); MOERTEL::Node** snodes = sseg_.Nodes(); for (int j=0; j<sseg_.Nnode(); ++j) for (int k=0; k<3; ++k) { x[k] += val[j]*snodes[j]->X()[k]; n[k] += val[j]*snodes[j]->N()[k]; } const double length = MOERTEL::length(n,3); for (int j=0; j<3; ++j) n[j] /= length; // create a node with this coords and normal; MOERTEL::Node* node = new MOERTEL::Node(points[i]->Id(),x,3,dof,false,OutLevel()); node->SetN(n); // set node in point points[i]->SetNode(node); #if 0 std::cout << *points[i]; #endif } // find projection values for all points in polygon on mseg { double mxi[2]; double gap; MOERTEL::Projector projector(inter_.IsOneDimensional(),OutLevel()); for (int i=0; i<np; ++i) { Teuchos::RCP<MOERTEL::Node> node = points[i]->Node(); projector.ProjectNodetoSegment_NodalNormal(*node,mseg_,mxi,gap); // create a projected node and set it in node MOERTEL::ProjectedNode* pnode = new MOERTEL::ProjectedNode(*node,mxi,&mseg_); node->SetProjectedNode(pnode); node->SetGap(gap); #if 0 std::cout << "-------------------------------------------------------\n"; if (mseg_.Nnode()==3) { if (mxi[0]<=1. && mxi[1]<=abs(1.-mxi[0]) && mxi[0]>=0. && mxi[1]>=0.) std::cout << "OVERLAP: point " << points[i]->Id() << " is in mseg, mxi " << mxi[0] << " / " << mxi[1] << endl; else std::cout << "OVERLAP: point " << points[i]->Id() << " is NOT in mseg, mxi " << mxi[0] << " / " << mxi[1] << endl; } else if (mseg_.Nnode()==4) { if (mxi[0]<=1.001 && mxi[0]>=-1.001 && mxi[1]<=1.001 && mxi[1]>=-1.001) std::cout << "OVERLAP: point " << points[i]->Id() << " is in mseg, mxi " << mxi[0] << " / " << mxi[1] << endl; else std::cout << "OVERLAP: point " << points[i]->Id() << " is NOT in mseg, mxi " << mxi[0] << " / " << mxi[1] << endl; } else { std::cout << "***ERR*** MOERTEL::Overlap::Triangulization:\n" << "***ERR*** # nodes " << mseg_.Nnode() << " of master segment is unknown\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; exit(EXIT_FAILURE); } std::cout << "-------------------------------------------------------\n"; #endif } } // if we plan to interpolate function values at the gaussian points we need the // function values at the points if (exactvalues_==false) { // every point has 3 values of the 3 shape functions of the elements: // max 4 values from function 0 from sseg // max 4 values from function 1 from sseg // max 4 values from function 0 from mseg for (int i=0; i<np; ++i) { double val[20]; int nmval = mseg_.Nnode(); int nsval = sseg_.Nnode(); // evaluate function 0 from sseg sseg_.EvaluateFunction(0,points[i]->Xi(),val,nsval,NULL); points[i]->StoreFunctionValues(0,val,nsval); // evaluate function 1 from sseg sseg_.EvaluateFunction(1,points[i]->Xi(),val,nsval,NULL); points[i]->StoreFunctionValues(1,val,nsval); // evaluate function 0 from mseg mseg_.EvaluateFunction(0,points[i]->Node()->GetProjectedNode()->Xi(),val,nmval,NULL); points[i]->StoreFunctionValues(2,val,nmval); } } // create the triangle elements from polygon with centerpoint // In case of np==3, there is no centerpoint if (np>3) { // the polygon is in clockwise order, center point is points[0] and has // id = -1 if (points[0]->Id() != -1) { std::cout << "***ERR*** MOERTEL::Overlap::Triangulization:\n" << "***ERR*** points[0]->Id() is not -1\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; exit(EXIT_FAILURE); } int nodeid[3]; MOERTEL::Segment_BiLinearTri* tmp; MOERTEL::Function_LinearTri* func = new Function_LinearTri(OutLevel()); for (int i=2; i<np; ++i) { // there are np-1 triangles // triangle ids go from 0 to np-2 // a triangle is defined by nodes 0, i, i-1 // *this class takes ownership of triangle nodeid[0] = points[0]->Id(); nodeid[1] = points[i]->Id(); nodeid[2] = points[i-1]->Id(); tmp = new MOERTEL::Segment_BiLinearTri(i-2,3,nodeid,OutLevel()); // set a linear shape function to this triangle tmp->SetFunction(0,func); // add triangle to the *this class AddSegment(tmp->Id(),tmp); } // add the last triangle defined by nodes 0, 1, np-1 separately // *this class takes ownership of triangle nodeid[0] = points[0]->Id(); nodeid[1] = points[1]->Id(); nodeid[2] = points[np-1]->Id(); tmp = new MOERTEL::Segment_BiLinearTri(np-2,3,nodeid,OutLevel()); // set a linear shape function to this triangle tmp->SetFunction(0,func); // add triangle to the *this class AddSegment(tmp->Id(),tmp); if (func) delete func; func = NULL; } else if (np==3) // single triangle without centerpoint { int nodeid[3]; MOERTEL::Segment_BiLinearTri* tmp; MOERTEL::Function_LinearTri* func = new Function_LinearTri(OutLevel()); nodeid[0] = points[0]->Id(); nodeid[1] = points[2]->Id(); nodeid[2] = points[1]->Id(); // *this class takes ownership of triangle tmp = new MOERTEL::Segment_BiLinearTri(0,3,nodeid,OutLevel()); // set a linear shape function to this triangle tmp->SetFunction(0,func); // add triangle the *this class AddSegment(tmp->Id(),tmp); if (func) delete func; func = NULL; } else { std::cout << "***ERR*** MOERTEL::Overlap::Triangulization:\n" << "***ERR*** # point in polygon < 3 ... very strange!!!\n" << "***ERR*** file/line: " << __FILE__ << "/" << __LINE__ << "\n"; exit(EXIT_FAILURE); } // create ptr topology between triangle and nodes in points std::vector<MOERTEL::Node*> nodes(np); for (int i=0; i<np; ++i) nodes[i] = points[i]->Node().get(); // loop segments and set ptr to nodes in them std::map<int,Teuchos::RCP<MOERTEL::Segment> >::iterator curr; for (curr=s_.begin(); curr != s_.end(); ++curr) curr->second->GetPtrstoNodes(nodes); nodes.clear(); points.clear(); return true; }
//--------------------------------------------------------- bool CMultiBand_Variation::Get_Variation(int x, int y) { if( !m_Mask.is_NoData(x, y) ) { int iBand, iCell, ix, iy; double iDistance, iWeight, Weights, Distance; CSG_Vector Centroid(m_pBands->Get_Count()); //------------------------------------------------- for(iCell=0, Weights=0.0; iCell<m_Cells.Get_Count(); iCell++) { if( m_Cells.Get_Values(iCell, ix = x, iy = y, iDistance, iWeight, true) && m_Mask.is_InGrid(ix, iy) ) { for(iBand=0; iBand<m_pBands->Get_Count(); iBand++) { Centroid[iBand] += iWeight * m_pBands->asGrid(iBand)->asDouble(ix, iy); } Weights += iWeight; } } //------------------------------------------------- if( Weights > 0.0 ) { CSG_Simple_Statistics s; Centroid *= 1.0 / Weights; for(iCell=0; iCell<m_Cells.Get_Count(); iCell++) { if( m_Cells.Get_Values(iCell, ix = x, iy = y, iDistance, iWeight, true) && m_Mask.is_InGrid(ix, iy) ) { for(iBand=0, Distance=0.0; iBand<m_pBands->Get_Count(); iBand++) { Distance += SG_Get_Square(Centroid[iBand] - m_pBands->asGrid(iBand)->asDouble(ix, iy)); } s.Add_Value(sqrt(Distance), iWeight); if( ix == x && iy == y ) { if( m_pDiff ) m_pDiff->Set_Value(x, y, sqrt(Distance)); } } } if( m_pMean ) m_pMean ->Set_Value(x, y, s.Get_Mean()); if( m_pStdDev ) m_pStdDev->Set_Value(x, y, s.Get_StdDev()); return( true ); } } //----------------------------------------------------- if( m_pMean ) m_pMean ->Set_NoData(x, y); if( m_pStdDev ) m_pStdDev ->Set_NoData(x, y); if( m_pDiff ) m_pDiff ->Set_NoData(x, y); return( false ); }
void CTexturedLineRData::Update(const SOverlayTexturedLine& line) { if (m_VB) { g_VBMan.Release(m_VB); m_VB = NULL; } if (m_VBIndices) { g_VBMan.Release(m_VBIndices); m_VBIndices = NULL; } if (!line.m_SimContext) { debug_warn(L"[TexturedLineRData] No SimContext set for textured overlay line, cannot render (no terrain data)"); return; } const CTerrain& terrain = line.m_SimContext->GetTerrain(); CmpPtr<ICmpWaterManager> cmpWaterManager(*line.m_SimContext, SYSTEM_ENTITY); float v = 0.f; std::vector<SVertex> vertices; std::vector<u16> indices; size_t n = line.m_Coords.size() / 2; // number of line points bool closed = line.m_Closed; ENSURE(n >= 2); // minimum needed to avoid errors (also minimum value to make sense, can't draw a line between 1 point) // In each iteration, p1 is the position of vertex i, p0 is i-1, p2 is i+1. // To avoid slightly expensive terrain computations we cycle these around and // recompute p2 at the end of each iteration. CVector3D p0; CVector3D p1(line.m_Coords[0], 0, line.m_Coords[1]); CVector3D p2(line.m_Coords[(1 % n)*2], 0, line.m_Coords[(1 % n)*2+1]); if (closed) // grab the ending point so as to close the loop p0 = CVector3D(line.m_Coords[(n-1)*2], 0, line.m_Coords[(n-1)*2+1]); else // we don't want to loop around and use the direction towards the other end of the line, so create an artificial p0 that // extends the p2 -> p1 direction, and use that point instead p0 = p1 + (p1 - p2); bool p1floating = false; bool p2floating = false; // Compute terrain heights, clamped to the water height (and remember whether // each point was floating on water, for normal computation later) // TODO: if we ever support more than one water level per map, recompute this per point float w = cmpWaterManager->GetExactWaterLevel(p0.X, p0.Z); p0.Y = terrain.GetExactGroundLevel(p0.X, p0.Z); if (p0.Y < w) p0.Y = w; p1.Y = terrain.GetExactGroundLevel(p1.X, p1.Z); if (p1.Y < w) { p1.Y = w; p1floating = true; } p2.Y = terrain.GetExactGroundLevel(p2.X, p2.Z); if (p2.Y < w) { p2.Y = w; p2floating = true; } for (size_t i = 0; i < n; ++i) { // For vertex i, compute bisector of lines (i-1)..(i) and (i)..(i+1) // perpendicular to terrain normal // Normal is vertical if on water, else computed from terrain CVector3D norm; if (p1floating) norm = CVector3D(0, 1, 0); else norm = terrain.CalcExactNormal(p1.X, p1.Z); CVector3D b = ((p1 - p0).Normalized() + (p2 - p1).Normalized()).Cross(norm); // Adjust bisector length to match the line thickness, along the line's width float l = b.Dot((p2 - p1).Normalized().Cross(norm)); if (fabs(l) > 0.000001f) // avoid unlikely divide-by-zero b *= line.m_Thickness / l; // Push vertices and indices for each quad in GL_TRIANGLES order. The two triangles of each quad are indexed using // the winding orders (BR, BL, TR) and (TR, BL, TR) (where BR is bottom-right of this iteration's quad, TR top-right etc). SVertex vertex1(p1 + b + norm*OverlayRenderer::OVERLAY_VOFFSET, 0.f, v); SVertex vertex2(p1 - b + norm*OverlayRenderer::OVERLAY_VOFFSET, 1.f, v); vertices.push_back(vertex1); vertices.push_back(vertex2); u16 index1 = vertices.size() - 2; // index of vertex1 in this iteration (TR of this quad) u16 index2 = vertices.size() - 1; // index of the vertex2 in this iteration (TL of this quad) if (i == 0) { // initial two vertices to continue building triangles from (n must be >= 2 for this to work) indices.push_back(index1); indices.push_back(index2); } else { u16 index1Prev = vertices.size() - 4; // index of the vertex1 in the previous iteration (BR of this quad) u16 index2Prev = vertices.size() - 3; // index of the vertex2 in the previous iteration (BL of this quad) ENSURE(index1Prev < vertices.size()); ENSURE(index2Prev < vertices.size()); // Add two corner points from last iteration and join with one of our own corners to create triangle 1 // (don't need to do this if i == 1 because i == 0 are the first two ones, they don't need to be copied) if (i > 1) { indices.push_back(index1Prev); indices.push_back(index2Prev); } indices.push_back(index1); // complete triangle 1 // create triangle 2, specifying the adjacent side's vertices in the opposite order from triangle 1 indices.push_back(index1); indices.push_back(index2Prev); indices.push_back(index2); } // alternate V coordinate for debugging v = 1 - v; // cycle the p's and compute the new p2 p0 = p1; p1 = p2; p1floating = p2floating; // if in closed mode, wrap around the coordinate array for p2 -- otherwise, extend linearly if (!closed && i == n-2) // next iteration is the last point of the line, so create an artificial p2 that extends the p0 -> p1 direction p2 = p1 + (p1 - p0); else p2 = CVector3D(line.m_Coords[((i+2) % n)*2], 0, line.m_Coords[((i+2) % n)*2+1]); p2.Y = terrain.GetExactGroundLevel(p2.X, p2.Z); if (p2.Y < w) { p2.Y = w; p2floating = true; } else p2floating = false; } if (closed) { // close the path indices.push_back(vertices.size()-2); indices.push_back(vertices.size()-1); indices.push_back(0); indices.push_back(0); indices.push_back(vertices.size()-1); indices.push_back(1); } else { // Create start and end caps. On either end, this is done by taking the centroid between the last and second-to-last pair of // vertices that was generated along the path (i.e. the vertex1's and vertex2's from above), taking a directional vector // between them, and drawing the line cap in the plane given by the two butt-end corner points plus said vector. std::vector<u16> capIndices; std::vector<SVertex> capVertices; // create end cap CreateLineCap( line, // the order of these vertices is important here, swapping them produces caps at the wrong side vertices[vertices.size()-2].m_Position, // top-right vertex of last quad vertices[vertices.size()-1].m_Position, // top-left vertex of last quad // directional vector between centroids of last vertex pair and second-to-last vertex pair (Centroid(vertices[vertices.size()-2], vertices[vertices.size()-1]) - Centroid(vertices[vertices.size()-4], vertices[vertices.size()-3])).Normalized(), line.m_EndCapType, capVertices, capIndices ); for (unsigned i = 0; i < capIndices.size(); i++) capIndices[i] += vertices.size(); vertices.insert(vertices.end(), capVertices.begin(), capVertices.end()); indices.insert(indices.end(), capIndices.begin(), capIndices.end()); capIndices.clear(); capVertices.clear(); // create start cap CreateLineCap( line, // the order of these vertices is important here, swapping them produces caps at the wrong side vertices[1].m_Position, vertices[0].m_Position, // directional vector between centroids of first vertex pair and second vertex pair (Centroid(vertices[1], vertices[0]) - Centroid(vertices[3], vertices[2])).Normalized(), line.m_StartCapType, capVertices, capIndices ); for (unsigned i = 0; i < capIndices.size(); i++) capIndices[i] += vertices.size(); vertices.insert(vertices.end(), capVertices.begin(), capVertices.end()); indices.insert(indices.end(), capIndices.begin(), capIndices.end()); } ENSURE(indices.size() % 3 == 0); // GL_TRIANGLES indices, so must be multiple of 3 m_VB = g_VBMan.Allocate(sizeof(SVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); if (m_VB) // allocation might fail (e.g. due to too many vertices) { m_VB->m_Owner->UpdateChunkVertices(m_VB, &vertices[0]); // copy data into VBO for (size_t k = 0; k < indices.size(); ++k) indices[k] += m_VB->m_Index; m_VBIndices = g_VBMan.Allocate(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); if (m_VBIndices) m_VBIndices->m_Owner->UpdateChunkVertices(m_VBIndices, &indices[0]); } }
void RotateToZero(PointVector& points) { PointPtr c = Centroid(points); double theta = atan2(c->Y - points[0]->Y, c->X - points[0]->X); RotateBy(points, -theta); }
const R3Sphere R3Box:: BSphere (void) const { // Return bounding sphere return R3Sphere(Centroid(), DiagonalRadius()); }