void ExampleExperimentFields::DrawScalarField() { viewer->clear(); //Load scalar field ScalarField2 field; if (!field.load(ScalarfieldFilename)) { output << "Error loading field file " << ScalarfieldFilename << "\n"; return; } //Get the minimum/maximum value in that field float32 min = std::numeric_limits<float32>::max(); float32 max = -std::numeric_limits<float32>::max(); for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i< field.dims()[0]; i++) { const float32 val = field.nodeScalar(i,j); min = val < min ? val : min; max = val > max ? val : max; } } //Draw a point for each grid vertex. for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i<field.dims()[0]; i++) { const float32 val = field.nodeScalar(i, j); const float32 c = (val - min) / (max - min); Point2D p; p.position = field.nodePosition(i, j); p.size = 5; //Use a grayscale depending on the actual value p.color[0] = c; p.color[1] = c; p.color[2] = c; viewer->addPoint(p); } } viewer->refresh(); }
void IterativeLevelSetSolver2::extrapolate( const FaceCenteredGrid2& input, const ScalarField2& sdf, double maxDistance, FaceCenteredGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); const Vector2D gridSpacing = input.gridSpacing(); auto u = input.uConstAccessor(); auto uPos = input.uPosition(); Array2<double> sdfAtU(u.size()); input.parallelForEachUIndex([&](size_t i, size_t j) { sdfAtU(i, j) = sdf.sample(uPos(i, j)); }); extrapolate( u, sdfAtU, gridSpacing, maxDistance, output->uAccessor()); auto v = input.vConstAccessor(); auto vPos = input.vPosition(); Array2<double> sdfAtV(v.size()); input.parallelForEachVIndex([&](size_t i, size_t j) { sdfAtV(i, j) = sdf.sample(vPos(i, j)); }); extrapolate( v, sdfAtV, gridSpacing, maxDistance, output->vAccessor()); }
void IterativeLevelSetSolver2::extrapolate( const CollocatedVectorGrid2& input, const ScalarField2& sdf, double maxDistance, CollocatedVectorGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); Array2<double> sdfGrid(input.dataSize()); auto pos = input.dataPosition(); sdfGrid.parallelForEachIndex([&](size_t i, size_t j) { sdfGrid(i, j) = sdf.sample(pos(i, j)); }); const Vector2D gridSpacing = input.gridSpacing(); Array2<double> u(input.dataSize()); Array2<double> u0(input.dataSize()); Array2<double> v(input.dataSize()); Array2<double> v0(input.dataSize()); input.parallelForEachDataPointIndex([&](size_t i, size_t j) { u(i, j) = input(i, j).x; v(i, j) = input(i, j).y; }); extrapolate( u, sdfGrid.constAccessor(), gridSpacing, maxDistance, u0); extrapolate( v, sdfGrid.constAccessor(), gridSpacing, maxDistance, v0); output->parallelForEachDataPointIndex([&](size_t i, size_t j) { (*output)(i, j).x = u(i, j); (*output)(i, j).y = v(i, j); }); }
void IterativeLevelSetSolver2::extrapolate( const ScalarGrid2& input, const ScalarField2& sdf, double maxDistance, ScalarGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); Array2<double> sdfGrid(input.dataSize()); auto pos = input.dataPosition(); sdfGrid.parallelForEachIndex([&](size_t i, size_t j) { sdfGrid(i, j) = sdf.sample(pos(i, j)); }); extrapolate( input.constDataAccessor(), sdfGrid.constAccessor(), input.gridSpacing(), maxDistance, output->dataAccessor()); }
void Experiment3_1::DrawRegularMesh() { viewer->clear(); //Load scalar field ScalarField2 field; if (!field.load(scalar_filename)) { output << "Error loading field file " << scalar_filename << "\n"; return; } //Get the minimum/maximum value in that field float32 min = std::numeric_limits<float32>::max(); float32 max = -std::numeric_limits<float32>::max(); for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i< field.dims()[0]; i++) { const float32 val = field.nodeScalar(i,j); min = val < min ? val : min; max = val > max ? val : max; } } //Plot the grid //Traverse one dimension first and then the other dimension for(size_t j=0; j<field.dims()[1]; j++) { viewer->addLine(field.nodePosition(0,j), field.nodePosition(field.dims()[0]-1,j), makeVector4f(0.5,0.5,0.5,grid_alpha), 1); } for(size_t i=0; i<field.dims()[0]; i++) { viewer->addLine(field.nodePosition(i,0), field.nodePosition(i,field.dims()[1]-1), makeVector4f(0.5,0.5,0.5,grid_alpha), 1); } //Optionally overlay data on the grid if (grid_w_data == true ) { //Draw a point for each grid vertex. for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i<field.dims()[0]; i++) { const float32 val = field.nodeScalar(i, j); const float32 c = (val - min) / (max - min); Point2D p; p.position = field.nodePosition(i, j); p.size = 5; //Use a grayscale depending on the actual value p.color[0] = c; p.color[1] = c; p.color[2] = c; viewer->addPoint(p); } } } viewer->refresh(); }
void Experiment3_1::DrawIsoContour_Asymp() { viewer->clear(); //Load scalar field ScalarField2 field; if (!field.load(scalar_filename)) { output << "Error loading field file " << scalar_filename << "\n"; return; } //Get the minimum/maximum value in that field float32 min = std::numeric_limits<float32>::max(); float32 max = -std::numeric_limits<float32>::max(); for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i< field.dims()[0]; i++) { const float32 val = field.nodeScalar(i,j); min = val < min ? val : min; max = val > max ? val : max; } } //Plot the grid //Traverse one dimension first and then the other dimension for(size_t j=0; j<field.dims()[1]; j++) { viewer->addLine(field.nodePosition(0,j), field.nodePosition(field.dims()[0]-1,j), makeVector4f(0.5,0.5,0.5,grid_alpha), 1); } for(size_t i=0; i<field.dims()[0]; i++) { viewer->addLine(field.nodePosition(i,0), field.nodePosition(i,field.dims()[1]-1), makeVector4f(0.5,0.5,0.5,grid_alpha), 1); } //Optionally overlay data on the grid if (grid_w_data == true ) { //Draw a point for each grid vertex. for(size_t j=0; j<field.dims()[1]; j++) { for(size_t i=0; i<field.dims()[0]; i++) { const float32 val = field.nodeScalar(i, j); const float32 c = (val - min) / (max - min); Point2D p; p.position = field.nodePosition(i, j); p.size = 5; //Use a grayscale depending on the actual value p.color[0] = c; p.color[1] = c; p.color[2] = c; viewer->addPoint(p); } } } viewer->refresh(); //Plot the Iso Contour //Traverse the cells for(size_t i=0; i<field.dims()[0]-1; i++) { for(size_t j=0; j<field.dims()[1]-1; j++) { //Compute Max and Min values in each cell float32 fval[4]; fval[0]= field.nodeScalar(i,j); fval[1]= field.nodeScalar(i,j+1); fval[2]= field.nodeScalar(i+1,j+1); fval[3]= field.nodeScalar(i+1,j); vector <Vector2f> Pos; Pos.resize(4); Pos[0]=field.nodePosition(i,j); Pos[1]=field.nodePosition(i,j+1); Pos[2]=field.nodePosition(i+1,j+1); Pos[3]=field.nodePosition(i+1,j); //output << "** "<< Pos[0][0] << " " << Pos[0][1] <<"\n"; //output << field.nodePosition(i,j)[0] << " "<< field.nodePosition(i,j)[1] << "\n" ; float32 maxf, minf; maxf=fmax(fval[0],fval[1]); maxf=fmax(maxf,fval[2]); maxf=fmax(maxf,fval[3]); minf=fmin(fval[0],fval[1]); minf=fmin(minf,fval[2]); minf=fmin(minf,fval[3]); //Check if the iso contour passes the grid if((iso_c < minf) || (iso_c > maxf)) continue; else //We plot the iso contour { float32 EdgeChar[3][4]; //Now figure out the signs for the four nodes bool sign[4]= {0,0,0,0}; for(int k=0; k<4; k++) { if(fval[k]>=iso_c) sign[k] = 1; } //Traverse the nodes clockwise and see if the edge carries a crossing point for(int k=0; k<4; k++) { if( sign[k] ^ sign[(k+1)%4] ) { EdgeChar[2][k] = 1; float32 x,y; x = ( (Pos[(k+1)%4][0] - Pos[k][0])*iso_c + Pos[k][0] * fval[(k+1)%4] - Pos[(k+1)%4][0] * fval[k] ) / ( fval[(k+1)%4] - fval[k] ) ; y = ( (Pos[(k+1)%4][1] - Pos[k][1])*iso_c + Pos[k][1] * fval[(k+1)%4] - Pos[(k+1)%4][1] * fval[k] ) / ( fval[(k+1)%4] - fval[k] ) ; EdgeChar[0][k] = x; EdgeChar[1][k] = y; } else EdgeChar[2][k] = 0; } //Count the number of edges that have a valid crossing point. It should be either 2 or 4 int EdgeCount=0; for(int k=0; k<4; k++) { if(EdgeChar[2][k]==1) EdgeCount++; } if(EdgeCount == 2) { //Simply plot the contour vector <Vector2f> LineEnd; LineEnd.clear(); LineEnd.resize(2); int index=0; for(int k=0; k<4; k++) { if(EdgeChar[2][k]==1) { LineEnd[index]= makeVector2f(EdgeChar[0][k], EdgeChar[1][k]) ; index++; } } viewer->addLine(LineEnd[0], LineEnd[1], makeVector4f(0.5,0.5,0.5,iso_alpha), 2); viewer->refresh(); } else //Cell has the contour intersecting at 4 points { //There is an ambiguity to be resolved float32 fmid= (fval[3]*fval[1] - fval[2]*fval[0]) / ( fval[3]+fval[1] -fval[2] - fval[0] ) ; vector <Vector2f> LineEnd; LineEnd.clear(); LineEnd.resize(4); for(int k=0; k<4; k++) { LineEnd[k]= makeVector2f(EdgeChar[0][k], EdgeChar[1][k]) ; } if(fval[1] < iso_c) { if(iso_c > fmid) //Connect 3 to 0 and 1 to 2 { viewer->addLine(LineEnd[3], LineEnd[0], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->addLine(LineEnd[1], LineEnd[2], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->refresh(); } else //Connect 0 to 1 and 2 to 3 { viewer->addLine(LineEnd[0], LineEnd[1], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->addLine(LineEnd[2], LineEnd[3], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->refresh(); } } else { if(iso_c > fmid) //Connect 0 to 1 and 2 to 3 { viewer->addLine(LineEnd[0], LineEnd[1], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->addLine(LineEnd[2], LineEnd[3], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->refresh(); } else //Connect 3 to 0 and 1 to 2 { viewer->addLine(LineEnd[3], LineEnd[0], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->addLine(LineEnd[1], LineEnd[2], makeVector4f(1,0.5,0.5,iso_alpha), 2); viewer->refresh(); } } } } } } }
void ExampleExperimentFields::DrawTexture() { viewer->clear(); //Load the texture using Qt QImage image(ImageFilename.c_str()); //Get its (original) dimensions. Used as bounds later. const float fWidth = (float)image.width(); const float fHeight = (float)image.height(); //Resize to power-of-two and mirror. image = image.mirrored().scaled(NextPOT(image.width()), NextPOT(image.height())); //Get its new integer dimensions. const int iWidth = image.width(); const int iHeight = image.height(); if (bColoredTexture) { //Create three color channels for the texture //Each of them is represented using a scalar field ScalarField2 Red; Red.init(makeVector2f(-fWidth, -fHeight), makeVector2f(fWidth, fHeight), makeVector2ui(iWidth, iHeight)); ScalarField2 Green; Green.init(makeVector2f(-fWidth, -fHeight), makeVector2f(fWidth, fHeight), makeVector2ui(iWidth, iHeight)); ScalarField2 Blue; Blue.init(makeVector2f(-fWidth, -fHeight), makeVector2f(fWidth, fHeight), makeVector2ui(iWidth, iHeight)); //Fill the scalar fields for(size_t j=0; j<Red.dims()[1]; j++) { for(size_t i=0; i<Red.dims()[0]; i++) { Red.setNodeScalar(i, j, (float)(qRed(image.pixel(i, j))) / 255.0 ); Green.setNodeScalar(i, j, (float)(qGreen(image.pixel(i, j))) / 255.0 ); Blue.setNodeScalar(i, j, (float)(qBlue(image.pixel(i, j))) / 255.0 ); } } //Set the texture in the viewer viewer->setTextureRGB(Red.getData(), Green.getData(), Blue.getData()); } else { //Create one gray color channel represented as a scalar field ScalarField2 Gray; Gray.init(makeVector2f(-fWidth, -fHeight), makeVector2f(fWidth, fHeight), makeVector2ui(iWidth, iHeight)); //Set the values at the vertices for(size_t j=0; j<Gray.dims()[1]; j++) { for(size_t i=0; i<Gray.dims()[0]; i++) { Gray.setNodeScalar(i, j, (float)(qGray(image.pixel(i, j))) / 255.0 ); } } //Set the texture in the viewer viewer->setTextureGray(Gray.getData()); } viewer->refresh(); }
void GridFractionalSinglePhasePressureSolver2::buildWeights( const FaceCenteredGrid2& input, const ScalarField2& boundarySdf, const VectorField2& boundaryVelocity, const ScalarField2& fluidSdf) { auto size = input.resolution(); // Build levels size_t maxLevels = 1; if (_mgSystemSolver != nullptr) { maxLevels = _mgSystemSolver->params().maxNumberOfLevels; } FdmMgUtils2::resizeArrayWithFinest(size, maxLevels, &_fluidSdf); _uWeights.resize(_fluidSdf.size()); _vWeights.resize(_fluidSdf.size()); for (size_t l = 0; l < _fluidSdf.size(); ++l) { _uWeights[l].resize(_fluidSdf[l].size() + Size2(1, 0)); _vWeights[l].resize(_fluidSdf[l].size() + Size2(0, 1)); } // Build top-level grids auto cellPos = input.cellCenterPosition(); auto uPos = input.uPosition(); auto vPos = input.vPosition(); _boundaryVel = boundaryVelocity.sampler(); Vector2D h = input.gridSpacing(); _fluidSdf[0].parallelForEachIndex([&](size_t i, size_t j) { _fluidSdf[0](i, j) = static_cast<float>(fluidSdf.sample(cellPos(i, j))); }); _uWeights[0].parallelForEachIndex([&](size_t i, size_t j) { Vector2D pt = uPos(i, j); double phi0 = boundarySdf.sample(pt - Vector2D(0.5 * h.x, 0.0)); double phi1 = boundarySdf.sample(pt + Vector2D(0.5 * h.x, 0.0)); double frac = fractionInsideSdf(phi0, phi1); double weight = clamp(1.0 - frac, 0.0, 1.0); // Clamp non-zero weight to kMinWeight. Having nearly-zero element // in the matrix can be an issue. if (weight < kMinWeight && weight > 0.0) { weight = kMinWeight; } _uWeights[0](i, j) = static_cast<float>(weight); }); _vWeights[0].parallelForEachIndex([&](size_t i, size_t j) { Vector2D pt = vPos(i, j); double phi0 = boundarySdf.sample(pt - Vector2D(0.0, 0.5 * h.y)); double phi1 = boundarySdf.sample(pt + Vector2D(0.0, 0.5 * h.y)); double frac = fractionInsideSdf(phi0, phi1); double weight = clamp(1.0 - frac, 0.0, 1.0); // Clamp non-zero weight to kMinWeight. Having nearly-zero element // in the matrix can be an issue. if (weight < kMinWeight && weight > 0.0) { weight = kMinWeight; } _vWeights[0](i, j) = static_cast<float>(weight); }); // Build sub-levels for (size_t l = 1; l < _fluidSdf.size(); ++l) { const auto& finerFluidSdf = _fluidSdf[l - 1]; auto& coarserFluidSdf = _fluidSdf[l]; const auto& finerUWeight = _uWeights[l - 1]; auto& coarserUWeight = _uWeights[l]; const auto& finerVWeight = _vWeights[l - 1]; auto& coarserVWeight = _vWeights[l]; // Fluid SDF restrict(finerFluidSdf, &coarserFluidSdf); restrict(finerUWeight, &coarserUWeight); restrict(finerVWeight, &coarserVWeight); } }