void BSplineCurveEvaluator::evaluateCurve(const std::vector<Point>& ptvCtrlPts, std::vector<Point>& ptvEvaluatedCurvePts, const float& fAniLength, const bool& bWrap) const { ptvEvaluatedCurvePts.clear(); std::vector<double> samplePoints(_numSamples + 1,_numSamples); ufGenSample uf; std::transform(samplePoints.begin(),samplePoints.end(),samplePoints.begin(),uf); // if wrapping is off, make the first and last segments of // the curve horizontal. Mat4d basisMat(1.0f/6.0f,-1.0f/2.0f,1.0f/2.0f,-1.0f/6.0f,2.0f/3.0f,0.0f,-1.0f,1.0f/2.0f,1.0f/6.0f,1.0f/2.0f,1.0f/2.0f,-1.0f/2.0f,0.0f,0.0f,0.0f,1.0f/6.0f); std::vector<Point> knotVector; if(~bWrap){ knotVector.push_back(ptvCtrlPts[0]); knotVector.push_back(ptvCtrlPts[0]);} for(std::vector<Point>::const_iterator itC = ptvCtrlPts.begin(); itC!=ptvCtrlPts.end();++itC) knotVector.push_back(*itC); if(bWrap){ knotVector.push_back(*(ptvCtrlPts.end() - 1)); knotVector.push_back(Point(fAniLength + ptvCtrlPts[0].x, ptvCtrlPts[0].y)); knotVector.push_back(Point(fAniLength + ptvCtrlPts[0].x, ptvCtrlPts[0].y));} if(~bWrap){ knotVector.push_back(*(ptvCtrlPts.end() - 1)); knotVector.push_back(*(ptvCtrlPts.end() - 1));} for(std::vector<Point>::iterator it = knotVector.begin();it!=(knotVector.end()-3);++it){ Point P0 = *it; Point P1 = *(1 + it); Point P2 = *(2 + it); Point P3 = *(3 + it); for(std::vector<double>::iterator it = samplePoints.begin();it!=samplePoints.end();++it){ Vec4d sampleMultVec(1,*it,(*it) * (*it), (*it) * (*it) * (*it)); Vec4d result = basisMat * sampleMultVec; Point evalPt = (result[0]*P0) + (result[1]*P1) + (result[2]*P2) + (result[3]*P3); if(bWrap){ if(evalPt.x>fAniLength){ evalPt.x-=fAniLength; if(evalPt.x>ptvCtrlPts[0].x) continue;}} ptvEvaluatedCurvePts.push_back(evalPt); } } if(!bWrap){ ptvEvaluatedCurvePts.push_back(Point(0.0f,ptvCtrlPts[0].y)); ptvEvaluatedCurvePts.push_back(Point(fAniLength,(*(ptvCtrlPts.end() -1)).y)); } }
void Foam::timeVaryingMappedFixedValuePointPatchField<Type>::checkTable() { // Initialise if (startSampleTime_ == -1 && endSampleTime_ == -1) { const polyMesh& pMesh = this->patch().boundaryMesh().mesh()(); // Read the initial point position pointField meshPts; if (pMesh.pointsInstance() == pMesh.facesInstance()) { meshPts = pointField(pMesh.points(), this->patch().meshPoints()); } else { // Load points from facesInstance if (debug) { Info<< "Reloading points0 from " << pMesh.facesInstance() << endl; } pointIOField points0 ( IOobject ( "points", pMesh.facesInstance(), polyMesh::meshSubDir, pMesh, IOobject::MUST_READ, IOobject::NO_WRITE, false ) ); meshPts = pointField(points0, this->patch().meshPoints()); } pointIOField samplePoints ( IOobject ( "points", this->db().time().constant(), "boundaryData"/this->patch().name(), this->db(), IOobject::MUST_READ, IOobject::AUTO_WRITE, false ) ); // tbd: run-time selection bool nearestOnly = ( !mapMethod_.empty() && mapMethod_ != "planarInterpolation" ); // Allocate the interpolator mapperPtr_.reset ( new pointToPointPlanarInterpolation ( samplePoints, meshPts, perturb_, nearestOnly ) ); // Read the times for which data is available const fileName samplePointsFile = samplePoints.filePath(); const fileName samplePointsDir = samplePointsFile.path(); sampleTimes_ = Time::findTimes(samplePointsDir); if (debug) { Info<< "timeVaryingMappedFixedValuePointPatchField : In directory " << samplePointsDir << " found times " << pointToPointPlanarInterpolation::timeNames(sampleTimes_) << endl; } } // Find current time in sampleTimes label lo = -1; label hi = -1; bool foundTime = mapperPtr_().findTime ( sampleTimes_, startSampleTime_, this->db().time().value(), lo, hi ); if (!foundTime) { FatalErrorIn ( "timeVaryingMappedFixedValuePointPatchField<Type>::checkTable" ) << "Cannot find starting sampling values for current time " << this->db().time().value() << nl << "Have sampling values for times " << pointToPointPlanarInterpolation::timeNames(sampleTimes_) << nl << "In directory " << this->db().time().constant()/"boundaryData"/this->patch().name() << "\n on patch " << this->patch().name() << " of field " << fieldTableName_ << exit(FatalError); } // Update sampled data fields. if (lo != startSampleTime_) { startSampleTime_ = lo; if (startSampleTime_ == endSampleTime_) { // No need to reread since are end values if (debug) { Pout<< "checkTable : Setting startValues to (already read) " << "boundaryData" /this->patch().name() /sampleTimes_[startSampleTime_].name() << endl; } startSampledValues_ = endSampledValues_; startAverage_ = endAverage_; } else { if (debug) { Pout<< "checkTable : Reading startValues from " << "boundaryData" /this->patch().name() /sampleTimes_[lo].name() << endl; } // Reread values and interpolate AverageIOField<Type> vals ( IOobject ( fieldTableName_, this->db().time().constant(), "boundaryData" /this->patch().name() /sampleTimes_[startSampleTime_].name(), this->db(), IOobject::MUST_READ, IOobject::AUTO_WRITE, false ) ); if (vals.size() != mapperPtr_().sourceSize()) { FatalErrorIn ( "timeVaryingMappedFixedValuePointPatchField<Type>::" "checkTable()" ) << "Number of values (" << vals.size() << ") differs from the number of points (" << mapperPtr_().sourceSize() << ") in file " << vals.objectPath() << exit(FatalError); } startAverage_ = vals.average(); startSampledValues_ = mapperPtr_().interpolate(vals); } } if (hi != endSampleTime_) { endSampleTime_ = hi; if (endSampleTime_ == -1) { // endTime no longer valid. Might as well clear endValues. if (debug) { Pout<< "checkTable : Clearing endValues" << endl; } endSampledValues_.clear(); } else { if (debug) { Pout<< "checkTable : Reading endValues from " << "boundaryData" /this->patch().name() /sampleTimes_[endSampleTime_].name() << endl; } // Reread values and interpolate AverageIOField<Type> vals ( IOobject ( fieldTableName_, this->db().time().constant(), "boundaryData" /this->patch().name() /sampleTimes_[endSampleTime_].name(), this->db(), IOobject::MUST_READ, IOobject::AUTO_WRITE, false ) ); if (vals.size() != mapperPtr_().sourceSize()) { FatalErrorIn ( "timeVaryingMappedFixedValuePointPatchField<Type>::" "checkTable()" ) << "Number of values (" << vals.size() << ") differs from the number of points (" << mapperPtr_().sourceSize() << ") in file " << vals.objectPath() << exit(FatalError); } endAverage_ = vals.average(); endSampledValues_ = mapperPtr_().interpolate(vals); } } }
void BSplineSurfaceFitterWindow::CreateScene() { // Begin with a flat 64x64 height field. int const numSamples = 64; float const extent = 8.0f; VertexFormat hfformat; hfformat.Bind(VA_POSITION, DF_R32G32B32_FLOAT, 0); hfformat.Bind(VA_TEXCOORD, DF_R32G32_FLOAT, 0); MeshFactory mf; mf.SetVertexFormat(hfformat); mHeightField = mf.CreateRectangle(numSamples, numSamples, extent, extent); int numVertices = numSamples * numSamples; VertexPT* hfvertices = mHeightField->GetVertexBuffer()->Get<VertexPT>(); // Set the heights based on a precomputed height field. Also create a // texture image to go with the height field. std::string path = mEnvironment.GetPath("BTHeightField.png"); std::shared_ptr<Texture2> texture(WICFileIO::Load(path, false)); std::shared_ptr<Texture2Effect> txeffect = std::make_shared<Texture2Effect>(mProgramFactory, texture, SamplerState::MIN_L_MAG_L_MIP_P, SamplerState::CLAMP, SamplerState::CLAMP); mHeightField->SetEffect(txeffect); std::mt19937 mte; std::uniform_real_distribution<float> symmr(-0.05f, 0.05f); std::uniform_real_distribution<float> intvr(32.0f, 64.0f); unsigned char* data = (unsigned char*)texture->Get<unsigned char>(); std::vector<Vector3<float>> samplePoints(numVertices); for (int i = 0; i < numVertices; ++i) { unsigned char value = *data; float height = 3.0f*((float)value) / 255.0f + symmr(mte); *data++ = (unsigned char)intvr(mte); *data++ = 3 * (128 - value / 2) / 4; *data++ = 0; data++; hfvertices[i].position[2] = height; samplePoints[i] = hfvertices[i].position; } // Compute a B-Spline surface with NxN control points, where N < 64. // This surface will be sampled to 64x64 and displayed together with the // original height field for comparison. int const numControls = 32; int const degree = 3; BSplineSurfaceFit<float> fitter(degree, numControls, numSamples, degree, numControls, numSamples, &samplePoints[0]); VertexFormat ffformat; ffformat.Bind(VA_POSITION, DF_R32G32B32_FLOAT, 0); ffformat.Bind(VA_COLOR, DF_R32G32B32A32_FLOAT, 0); mf.SetVertexFormat(ffformat); mFittedField = mf.CreateRectangle(numSamples, numSamples, extent, extent); VertexPC* ffvertices = mFittedField->GetVertexBuffer()->Get<VertexPC>(); Vector4<float> translucent{ 1.0f, 1.0f, 1.0f, 0.5f }; for (int i = 0; i < numVertices; ++i) { float u = 0.5f*(ffvertices[i].position[0] / extent + 1.0f); float v = 0.5f*(ffvertices[i].position[1] / extent + 1.0f); ffvertices[i].position = fitter.GetPosition(u, v); ffvertices[i].color = translucent; } std::shared_ptr<VertexColorEffect> vceffect = std::make_shared<VertexColorEffect>(mProgramFactory); mFittedField->SetEffect(vceffect); mCameraRig.Subscribe(mHeightField->worldTransform, txeffect->GetPVWMatrixConstant()); mCameraRig.Subscribe(mFittedField->worldTransform, vceffect->GetPVWMatrixConstant()); mTrackball.Attach(mHeightField); mTrackball.Attach(mFittedField); mTrackball.Update(); }
void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints() { // Read the sample points pointIOField samplePoints ( IOobject ( "points", this->db().time().constant(), "boundaryData"/this->patch().name(), this->db(), IOobject::MUST_READ, IOobject::AUTO_WRITE, false ) ); const fileName samplePointsFile = samplePoints.filePath(); if (debug) { Info<< "timeVaryingMappedFixedValueFvPatchField :" << " Read " << samplePoints.size() << " sample points from " << samplePointsFile << endl; } // Determine coordinate system from samplePoints if (samplePoints.size() < 3) { FatalErrorIn ( "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()" ) << "Only " << samplePoints.size() << " points read from file " << samplePoints.objectPath() << nl << "Need at least three non-colinear samplePoints" << " to be able to interpolate." << "\n on patch " << this->patch().name() << " of field " << this->dimensionedInternalField().name() << " in file " << this->dimensionedInternalField().objectPath() << exit(FatalError); } const point& p0 = samplePoints[0]; // Find point separate from p0 vector e1; label index1 = -1; for (label i = 1; i < samplePoints.size(); i++) { e1 = samplePoints[i] - p0; scalar magE1 = mag(e1); if (magE1 > SMALL) { e1 /= magE1; index1 = i; break; } } // Find point that makes angle with n1 label index2 = -1; vector e2; vector n; for (label i = index1+1; i < samplePoints.size(); i++) { e2 = samplePoints[i] - p0; scalar magE2 = mag(e2); if (magE2 > SMALL) { e2 /= magE2; n = e1^e2; scalar magN = mag(n); if (magN > SMALL) { index2 = i; n /= magN; break; } } } if (index2 == -1) { FatalErrorIn ( "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()" ) << "Cannot find points that make valid normal." << nl << "Need at least three sample points which are not in a line." << "\n on patch " << this->patch().name() << " of field " << this->dimensionedInternalField().name() << " in file " << this->dimensionedInternalField().objectPath() << exit(FatalError); } if (debug) { Info<< "timeVaryingMappedFixedValueFvPatchField :" << " Used points " << p0 << ' ' << samplePoints[index1] << ' ' << samplePoints[index2] << " to define coordinate system with normal " << n << endl; } referenceCS_.reset ( new cartesianCS ( "reference", p0, // origin n, // normal e1 // 0-axis ) ); tmp<vectorField> tlocalVertices ( referenceCS().localPosition(samplePoints) ); const vectorField& localVertices = tlocalVertices(); // Determine triangulation List<vector2D> localVertices2D(localVertices.size()); forAll(localVertices, i) { localVertices2D[i][0] = localVertices[i][0]; localVertices2D[i][1] = localVertices[i][1]; }
void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints() { // Read the sample points pointIOField samplePoints ( IOobject ( "points", this->db().time().constant(), "boundaryData"/this->patch().name(), this->db(), IOobject::MUST_READ, IOobject::AUTO_WRITE, false ) ); const fileName samplePointsFile = samplePoints.filePath(); if (debug) { Info<< "timeVaryingMappedFixedValueFvPatchField :" << " Read " << samplePoints.size() << " sample points from " << samplePointsFile << endl; } // Determine coordinate system from samplePoints if (samplePoints.size() < 3) { FatalErrorIn ( "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()" ) << "Only " << samplePoints.size() << " points read from file " << samplePoints.objectPath() << nl << "Need at least three non-colinear samplePoints" << " to be able to interpolate." << "\n on patch " << this->patch().name() << " of points " << samplePoints.name() << " in file " << samplePoints.objectPath() << exit(FatalError); } const point& p0 = samplePoints[0]; // Find furthest away point vector e1; label index1 = -1; scalar maxDist = -GREAT; for (label i = 1; i < samplePoints.size(); i++) { const vector d = samplePoints[i] - p0; scalar magD = mag(d); if (magD > maxDist) { e1 = d/magD; index1 = i; maxDist = magD; } } // Find point that is furthest away from line p0-p1 const point& p1 = samplePoints[index1]; label index2 = -1; maxDist = -GREAT; for (label i = 1; i < samplePoints.size(); i++) { if (i != index1) { const point& p2 = samplePoints[i]; vector e2(p2 - p0); e2 -= (e2&e1)*e1; scalar magE2 = mag(e2); if (magE2 > maxDist) { index2 = i; maxDist = magE2; } } } if (index2 == -1) { FatalErrorIn ( "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()" ) << "Cannot find points that make valid normal." << nl << "Have so far points " << p0 << " and " << p1 << "Need at least three sample points which are not in a line." << "\n on patch " << this->patch().name() << " of points " << samplePoints.name() << " in file " << samplePoints.objectPath() << exit(FatalError); } vector n = e1^(samplePoints[index2]-p0); n /= mag(n); if (debug) { Info<< "timeVaryingMappedFixedValueFvPatchField :" << " Used points " << p0 << ' ' << samplePoints[index1] << ' ' << samplePoints[index2] << " to define coordinate system with normal " << n << endl; } referenceCS_.reset ( new coordinateSystem ( "reference", p0, // origin n, // normal e1 // 0-axis ) ); tmp<vectorField> tlocalVertices ( referenceCS().localPosition(samplePoints) ); vectorField& localVertices = tlocalVertices(); const boundBox bb(localVertices, true); const point bbMid(bb.midpoint()); if (debug) { Info<< "timeVaryingMappedFixedValueFvPatchField :" << " Perturbing points with " << perturb_ << " fraction of a random position inside " << bb << " to break any ties on regular meshes." << nl << endl; } Random rndGen(123456); forAll(localVertices, i) { localVertices[i] += perturb_ *(rndGen.position(bb.min(), bb.max())-bbMid); }