// Print what is wrong with the grid, appending it to the existing string void GridDefinition::PrintError(float originalXrange, float originalYrange, StringRef& r) const { if (spacing < MinSpacing) { r.cat("Spacing too small"); } else if (numX == 0) { r.cat("X range too small"); } else if (numY == 0) { r.cat("Y range too small"); } else if ( numX > MaxXGridPoints || numX > MaxGridProbePoints || numY > MaxGridProbePoints // check X and Y individually in case X*Y overflows || NumPoints() > MaxGridProbePoints ) { const float totalRange = originalXrange + originalYrange; const float area = originalXrange * originalYrange; const float minSpacing = (totalRange + sqrtf(fsquare(totalRange) + 4.0 * (MaxGridProbePoints - 1) * area))/(2.0 * (MaxGridProbePoints - 1)); const float minXspacing = originalXrange/(MaxXGridPoints - 1); r.catf("Too many grid points; suggest increase spacing to %.1fmm", max<float>(minSpacing, minXspacing)); } else { // The only thing left is a bad radius r.cat("Bad radius"); } }
// Compute Forces - Very slow, but simple. O(n^2) void FluidSystem::SPH_ComputeForceSlow () { char *dat1, *dat1_end; char *dat2, *dat2_end; Fluid *p, *q; Vector3DF force, fcurr; register double pterm, vterm, dterm; double c, r, d, sum, dsq; double dx, dy, dz; double mR, mR2, visc; d = m_Param[SPH_SIMSCALE]; mR = m_Param[SPH_SMOOTHRADIUS]; mR2 = (mR*mR); visc = m_Param[SPH_VISC]; vterm = m_LapKern * visc; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) { p = (Fluid*) dat1; sum = 0.0; force.Set ( 0, 0, 0 ); dat2_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat2 = mBuf[0].data; dat2 < dat2_end; dat2 += mBuf[0].stride ) { q = (Fluid*) dat2; if ( p == q ) continue; dx = ( p->pos.x - q->pos.x )*d; // dist in cm dy = ( p->pos.y - q->pos.y )*d; dz = ( p->pos.z - q->pos.z )*d; dsq = (dx*dx + dy*dy + dz*dz); if ( mR2 > dsq ) { r = sqrt ( dsq ); c = (mR - r); pterm = -0.5f * c * m_SpikyKern * ( p->pressure + q->pressure) / r; dterm = c * p->density * q->density; force.x += ( pterm * dx + vterm * (q->vel_eval.x - p->vel_eval.x) ) * dterm; force.y += ( pterm * dy + vterm * (q->vel_eval.y - p->vel_eval.y) ) * dterm; force.z += ( pterm * dz + vterm * (q->vel_eval.z - p->vel_eval.z) ) * dterm; } } p->sph_force = force; } }
void PointSet::Grid_InsertParticles () { char *dat1, *dat1_end; Point *p; int gs; int gx, gy, gz; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) ((Point*) dat1)->next = -1; //initialize for (int n=0; n < m_GridTotal; n++) { m_Grid[n] = -1; m_GridCnt[n] = 0; m_GridControlCnt[n] = 0; } dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; int n = 0; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) { p = (Point*) dat1; gx = (int)( (p->pos.x - m_GridMin.x) * m_GridDelta.x); // Determine grid cell gy = (int)( (p->pos.y - m_GridMin.y) * m_GridDelta.y); gz = (int)( (p->pos.z - m_GridMin.z) * m_GridDelta.z); //grid index gs gs = (int)( (gz*m_GridRes.y + gy)*m_GridRes.x + gx); if ( gs >= 0 && gs < m_GridTotal ) { p->next = m_Grid[gs];// pointer to the previous particle in the list of the recent particle m_Grid[gs] = n; // stores most recent particle index of that particular cell //that particular particle maintains a list of all the previous particles in the cell //if(p->type == 0) //{ ////m_GridCnt[gs]++; //stores no of particles in one grid cell //} // //if(p->type == 1) //{ //m_GridControlCnt[gs]++; //stores no of particles in one grid cell //} } n++; } }
int PointSet::AddPointReuse () { xref ndx; if ( NumPoints() < mBuf[0].max-1 ) AddElem ( 0, ndx ); else RandomElem ( 0, ndx ); return ndx; }
void PointSet::Advance () { char* dat; Particle* p; Vector3DF vnext, accel, norm; vnext = m_Vec[EMIT_DANG]; vnext *= m_DT; m_Vec[EMIT_ANG] += vnext; dat = mBuf[0].data; for ( int c = 0; c < NumPoints(); c++ ) { p = (Particle*) dat; accel.Set (0, 0, 0); // Plane gravity if ( m_Param[PLANE_GRAV] > 0) accel += m_Vec[PLANE_GRAV_DIR]; // Point gravity if ( m_Param[POINT_GRAV] > 0 ) { norm.x = ( p->pos.x - m_Vec[POINT_GRAV_POS].x ); norm.y = ( p->pos.y - m_Vec[POINT_GRAV_POS].y ); norm.z = ( p->pos.z - m_Vec[POINT_GRAV_POS].z ); norm.Normalize (); norm *= m_Param[POINT_GRAV]; accel -= norm; } if(p->type == 0){ // Leapfrog Integration ---------------------------- vnext = accel; vnext *= m_DT; vnext += p->vel; // v(t+1/2) = v(t-1/2) + a(t) dt p->vel_eval = p->vel; p->vel_eval += vnext; p->vel_eval *= 0.5; // v(t+1) = [v(t-1/2) + v(t+1/2)] * 0.5 used to compute forces later p->vel = vnext; vnext *= m_DT; p->pos += vnext; // p(t+1) = p(t) + v(t+1/2) dt } // Euler integration ------------------------------- // accel += m_Gravity; // accel *= m_DT; // mParticles[c].vel += accel; // v(t+1) = v(t) + a(t) dt // mParticles[c].vel_eval += accel; // mParticles[c].vel_eval *= m_DT/d; // mParticles[c].pos += mParticles[c].vel_eval; // mParticles[c].vel_eval = mParticles[c].vel; dat += mBuf[0].stride; } m_Time += m_DT; }
// Compute Pressures - Very slow yet simple. O(n^2) void FluidSystem::SPH_ComputePressureSlow () { char *dat1, *dat1_end; char *dat2, *dat2_end; Fluid *p, *q; int cnt = 0; double dx, dy, dz, sum, dsq, c; double d, d2, mR, mR2; d = m_Param[SPH_SIMSCALE]; d2 = d*d; mR = m_Param[SPH_SMOOTHRADIUS]; mR2 = mR*mR; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) { p = (Fluid*) dat1; sum = 0.0; cnt = 0; dat2_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat2 = mBuf[0].data; dat2 < dat2_end; dat2 += mBuf[0].stride ) { q = (Fluid*) dat2; if ( p==q ) continue; dx = ( p->pos.x - q->pos.x)*d; // dist in cm dy = ( p->pos.y - q->pos.y)*d; dz = ( p->pos.z - q->pos.z)*d; dsq = (dx*dx + dy*dy + dz*dz); if ( mR2 > dsq ) { c = m_R2 - dsq; sum += c * c * c; cnt++; //if ( p == m_CurrP ) q->tag = true; } } p->density = sum * m_Param[SPH_PMASS] * m_Poly6Kern ; p->pressure = ( p->density - m_Param[SPH_RESTDENSITY] ) * m_Param[SPH_INTSTIFF]; p->density = 1.0f / p->density; } }
// Compute Forces - Using spatial grid. Faster. void FluidSystem::SPH_ComputeForceGrid () { char *dat1, *dat1_end; Fluid *p; Fluid *pcurr; int pndx; Vector3DF force, fcurr; register double pterm, vterm, dterm; double c, d, dsq, r; double dx, dy, dz; double mR, mR2, visc; float radius = m_Param[SPH_SMOOTHRADIUS] / m_Param[SPH_SIMSCALE]; d = m_Param[SPH_SIMSCALE]; mR = m_Param[SPH_SMOOTHRADIUS]; mR2 = (mR*mR); visc = m_Param[SPH_VISC]; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) { p = (Fluid*) dat1; force.Set ( 0, 0, 0 ); Grid_FindCells ( p->pos, radius ); for (int cell=0; cell < 8; cell++) { if ( m_GridCell[cell] != -1 ) { pndx = m_Grid [ m_GridCell[cell] ]; while ( pndx != -1 ) { pcurr = (Fluid*) (mBuf[0].data + pndx*mBuf[0].stride); if ( pcurr == p ) {pndx = pcurr->next; continue; } dx = ( p->pos.x - pcurr->pos.x)*d; // dist in cm dy = ( p->pos.y - pcurr->pos.y)*d; dz = ( p->pos.z - pcurr->pos.z)*d; dsq = (dx*dx + dy*dy + dz*dz); if ( mR2 > dsq ) { r = sqrt ( dsq ); c = (mR - r); pterm = -0.5f * c * m_SpikyKern * ( p->pressure + pcurr->pressure) / r; dterm = c * p->density * pcurr->density; vterm = m_LapKern * visc; force.x += ( pterm * dx + vterm * (pcurr->vel_eval.x - p->vel_eval.x) ) * dterm; force.y += ( pterm * dy + vterm * (pcurr->vel_eval.y - p->vel_eval.y) ) * dterm; force.z += ( pterm * dz + vterm * (pcurr->vel_eval.z - p->vel_eval.z) ) * dterm; } pndx = pcurr->next; } } } p->sph_force = force; } }
// Compute Pressures - Using spatial grid, and also create neighbor table void FluidSystem::SPH_ComputePressureGrid () { char *dat1, *dat1_end; Fluid* p; Fluid* pcurr; int pndx; int i, cnt = 0; float dx, dy, dz, sum, dsq, c; float d, d2, mR, mR2; float radius = m_Param[SPH_SMOOTHRADIUS] / m_Param[SPH_SIMSCALE]; d = m_Param[SPH_SIMSCALE]; d2 = d*d; mR = m_Param[SPH_SMOOTHRADIUS]; mR2 = mR*mR; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; i = 0; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride, i++ ) { p = (Fluid*) dat1; sum = 0.0; m_NC[i] = 0; Grid_FindCells ( p->pos, radius ); for (int cell=0; cell < 8; cell++) { if ( m_GridCell[cell] != -1 ) { pndx = m_Grid [ m_GridCell[cell] ]; while ( pndx != -1 ) { pcurr = (Fluid*) (mBuf[0].data + pndx*mBuf[0].stride); if ( pcurr == p ) {pndx = pcurr->next; continue; } dx = ( p->pos.x - pcurr->pos.x)*d; // dist in cm dy = ( p->pos.y - pcurr->pos.y)*d; dz = ( p->pos.z - pcurr->pos.z)*d; dsq = (dx*dx + dy*dy + dz*dz); if ( mR2 > dsq ) { c = m_R2 - dsq; sum += c * c * c; if ( m_NC[i] < MAX_NEIGHBOR ) { m_Neighbor[i][ m_NC[i] ] = pndx; m_NDist[i][ m_NC[i] ] = sqrt(dsq); m_NC[i]++; } } pndx = pcurr->next; } } m_GridCell[cell] = -1; } p->density = sum * m_Param[SPH_PMASS] * m_Poly6Kern ; p->pressure = ( p->density - m_Param[SPH_RESTDENSITY] ) * m_Param[SPH_INTSTIFF]; p->density = 1.0f / p->density; } }
//---------------------------------------------------------------------------- BOOL DragDropLink::paint(CDC* pDC){ //---------------------------------------------------------------------------- PROC_TRACE; if (!isVisible()) return TRUE; if (NumPoints() > 0) { inherited::paint(pDC); } return TRUE; }
Point Polygon::FarthestPointAtAngle(real angle) const { // TODO(mraggi): Replace with Binary search implementation int n = NumPoints(); for (int i = 0; i < n; ++i) { Point p1 = m_vPoints[i]; Point p2 = m_vPoints[(i + 1)%n]; real a1 = p1.Angle(); real a2 = p2.Angle(); if (isAngleBetweenAngles(angle, a1, a2)) { Point hola; Ray ray(Ray(Point(0, 0), angle)); ray.Intersects(Segment(p1, p2), hola); return hola + Position(); } } if (NumPoints() > 2) std::cerr << "ERROR IN Polygon::FarthestPointAtAngle" << std::endl; return {0, 0}; }
bool Polygon::Intersects(const Point& other) const { const Polygon& B = *this; int n = NumPoints(); if (n <= 2) return false; for (int i = 0; i < n; ++i) { Point X = B[i]; Point Y = B[(i + 1)%n]; if (other.IsToTheLeftOfLine(X, Y) || X == Y) return false; } return true; }
Point Polygon::ClosestPoint(const Point& point) const { if (Intersects(point)) return point; Point closestSoFar = GetPoint(0); for (int i = 0; i < NumPoints(); ++i) { Segment seg(GetPoint(i), GetPoint(i + 1)); Point closestNow = seg.ClosestPoint(point); if (point.IsCloserToFirstThanSecond(closestNow, closestSoFar)) closestSoFar = closestNow; } return closestSoFar; }
int FluidSystem::AddPointReuse () { xref ndx; Fluid* f; if ( NumPoints() <= mBuf[0].max-2 ) f = (Fluid*) AddElem ( 0, ndx ); else f = (Fluid*) RandomElem ( 0, ndx ); f->sph_force.Set(0,0,0); f->vel.Set(0,0,0); f->vel_eval.Set(0,0,0); f->next = 0x0; f->pressure = 0; f->density = 0; return ndx; }
// Compute Forces - Using spatial grid with saved neighbor table. Fastest. void FluidSystem::SPH_ComputeForceGridNC () { char *dat1, *dat1_end; Fluid *p; Fluid *pcurr; Vector3DF force, fcurr; register float pterm, vterm, dterm; int i; float c, d; float dx, dy, dz; float mR, mR2, visc; d = m_Param[SPH_SIMSCALE]; mR = m_Param[SPH_SMOOTHRADIUS]; mR2 = (mR*mR); visc = m_Param[SPH_VISC]; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; i = 0; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride, i++ ) { p = (Fluid*) dat1; force.Set ( 0, 0, 0 ); for (int j=0; j < m_NC[i]; j++ ) { pcurr = (Fluid*) (mBuf[0].data + m_Neighbor[i][j]*mBuf[0].stride); dx = ( p->pos.x - pcurr->pos.x)*d; // dist in cm dy = ( p->pos.y - pcurr->pos.y)*d; dz = ( p->pos.z - pcurr->pos.z)*d; c = ( mR - m_NDist[i][j] ); pterm = -0.5f * c * m_SpikyKern * ( p->pressure + pcurr->pressure) / m_NDist[i][j]; dterm = c * p->density * pcurr->density; vterm = m_LapKern * visc; force.x += ( pterm * dx + vterm * (pcurr->vel_eval.x - p->vel_eval.x) ) * dterm; force.y += ( pterm * dy + vterm * (pcurr->vel_eval.y - p->vel_eval.y) ) * dterm; force.z += ( pterm * dz + vterm * (pcurr->vel_eval.z - p->vel_eval.z) ) * dterm; } p->sph_force = force; } }
//---------------------------------------------------------------------------- void DragDropLink::GainedSelection(DragDropSelection* pSelection){ //---------------------------------------------------------------------------- PROC_TRACE; assert(pSelection!=NULL); // the link has gained selection, it is time to set up resize handles if (!IsResizable()) { pSelection->CreateBoundingHandle (this); return; } CPoint point; for (int i=1; i < NumPoints()-1; i++){ point = GetPoint(i); pSelection->CreateResizeHandle (this, point.x, point.y, i + HandlesLast, TRUE); } return; }
// Append the grid parameters to the end of a string void GridDefinition::PrintParameters(StringRef& s) const { s.catf("X%.1f:%.1f, Y%.1f:%.1f, radius %.1f, spacing %.1f, %d points", xMin, xMax, yMin, yMax, radius, spacing, NumPoints()); }
//---------------------------------------------------------------------------- int DragDropLink::GetLastPickPoint(){ //---------------------------------------------------------------------------- PROC_TRACE; return NumPoints()-1; }
Point Polygon::GetPoint(int index) const { return Position() + m_vPoints[index%NumPoints()]; }
void GridDefinition::CheckValidity() { isValid = NumPoints() != 0 && NumPoints() <= MaxGridProbePoints && (radius < 0.0 || radius >= 1.0) && NumXpoints() <= MaxXGridPoints; }
void SetPoint(unsigned int i, const float3& p) { points[std::min(i, NumPoints() - 1)] = p; }
void FluidSystem::SPH_CreateExample ( int n, int nmax ) { Vector3DF pos; Vector3DF min, max; Reset ( nmax ); switch ( n ) { case 0: // Wave pool //-- TEST CASE: 2x2x2 grid, 32 particles. NOTE: Set PRADIUS to 0.0004 to reduce wall influence // grid 0: 3*3*2 = 18 particles // grid 1,2: 3*1*2 = 6 particles // grid 3: 1*1*2 = 2 particles // grid 4,5,6: 0 = 0 particles /*m_Vec [ SPH_VOLMIN ].Set ( -2.5, -2.5, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 2.5, 2.5, 5.0 ); m_Vec [ SPH_INITMIN ].Set ( -2.5, -2.5, 0 ); m_Vec [ SPH_INITMAX ].Set ( 2.5, 2.5, 1.6 );*/ m_Vec [ SPH_VOLMIN ].Set ( -30, -30, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 30, 30, 40 ); //m_Vec [ SPH_INITMIN ].Set ( -5, -5, 10 ); //m_Vec [ SPH_INITMAX ].Set ( 5, 5, 20 ); m_Vec [ SPH_INITMIN ].Set ( -20, -26, 10 ); m_Vec [ SPH_INITMAX ].Set ( 20, 26, 40 ); m_Param [ FORCE_XMIN_SIN ] = 12.0; m_Param [ BOUND_ZMIN_SLOPE ] = 0.05; break; case 1: // Dam break m_Vec [ SPH_VOLMIN ].Set ( -30, -14, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 30, 14, 60 ); m_Vec [ SPH_INITMIN ].Set ( 0, -13, 0 ); m_Vec [ SPH_INITMAX ].Set ( 29, 13, 30 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 2: // Dual-Wave pool m_Vec [ SPH_VOLMIN ].Set ( -60, -5, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 60, 5, 50 ); m_Vec [ SPH_INITMIN ].Set ( -46, -5, 0 ); m_Vec [ SPH_INITMAX ].Set ( 46, 5, 15 ); m_Param [ FORCE_XMIN_SIN ] = 8.0; m_Param [ FORCE_XMAX_SIN ] = 8.0; m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 3: // Swirl Stream m_Vec [ SPH_VOLMIN ].Set ( -30, -30, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 30, 30, 50 ); m_Vec [ SPH_INITMIN ].Set ( -30, -30, 0 ); m_Vec [ SPH_INITMAX ].Set ( 30, 30, 40 ); m_Vec [ EMIT_POS ].Set ( -20, -20, 22 ); m_Vec [ EMIT_RATE ].Set ( 1, 4, 0 ); m_Vec [ EMIT_ANG ].Set ( 0, 120, 1.5 ); m_Vec [ EMIT_DANG ].Set ( 0, 0, 0 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 4: // Shockwave m_Vec [ SPH_VOLMIN ].Set ( -60, -15, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 60, 15, 50 ); m_Vec [ SPH_INITMIN ].Set ( -59, -14, 0 ); m_Vec [ SPH_INITMAX ].Set ( 59, 14, 30 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); m_Toggle [ WALL_BARRIER ] = true; m_Toggle [ WRAP_X ] = true; break; case 5: // Zero gravity m_Vec [ SPH_VOLMIN ].Set ( -40, -40, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 40, 40, 50 ); m_Vec [ SPH_INITMIN ].Set ( -20, -20, 20 ); m_Vec [ SPH_INITMAX ].Set ( 20, 20, 40 ); m_Vec [ EMIT_POS ].Set ( -20, 0, 40 ); m_Vec [ EMIT_RATE ].Set ( 2, 1, 0 ); m_Vec [ EMIT_ANG ].Set ( 0, 120, 0.25 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0, 0, 0 ); m_Param [ SPH_INTSTIFF ] = 0.20; break; case 6: // Point gravity m_Vec [ SPH_VOLMIN ].Set ( -40, -40, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 40, 40, 50 ); m_Vec [ SPH_INITMIN ].Set ( -20, -20, 20 ); m_Vec [ SPH_INITMAX ].Set ( 20, 20, 40 ); m_Param [ SPH_INTSTIFF ] = 0.50; m_Vec [ EMIT_POS ].Set ( -20, 20, 25 ); m_Vec [ EMIT_RATE ].Set ( 1, 4, 0 ); m_Vec [ EMIT_ANG ].Set ( -20, 100, 2.0 ); m_Vec [ POINT_GRAV_POS ].Set ( 0, 0, 25 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0, 0, 0 ); m_Param [ POINT_GRAV ] = 3.5; break; case 7: // Levy break m_Vec [ SPH_VOLMIN ].Set ( -40, -40, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 40, 40, 50 ); m_Vec [ SPH_INITMIN ].Set ( 10, -40, 0 ); m_Vec [ SPH_INITMAX ].Set ( 40, 40, 50 ); m_Vec [ EMIT_POS ].Set ( 34, 27, 16.6 ); m_Vec [ EMIT_RATE ].Set ( 2, 9, 0 ); m_Vec [ EMIT_ANG ].Set ( 118, 200, 1.0 ); m_Toggle [ LEVY_BARRIER ] = true; m_Param [ BOUND_ZMIN_SLOPE ] = 0.1; m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 8: // Drain m_Vec [ SPH_VOLMIN ].Set ( -20, -20, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 20, 20, 50 ); m_Vec [ SPH_INITMIN ].Set ( -15, -20, 20 ); m_Vec [ SPH_INITMAX ].Set ( 20, 20, 50 ); m_Vec [ EMIT_POS ].Set ( -16, -16, 30 ); m_Vec [ EMIT_RATE ].Set ( 1, 4, 0 ); m_Vec [ EMIT_ANG ].Set ( -20, 140, 1.8 ); m_Toggle [ DRAIN_BARRIER ] = true; m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 9: // Tumbler m_Vec [ SPH_VOLMIN ].Set ( -30, -30, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 30, 30, 50 ); m_Vec [ SPH_INITMIN ].Set ( 24, -29, 20 ); m_Vec [ SPH_INITMAX ].Set ( 29, 29, 40 ); m_Param [ SPH_VISC ] = 0.1; m_Param [ SPH_INTSTIFF ] = 0.50; m_Param [ SPH_EXTSTIFF ] = 8000; //m_Param [ SPH_SMOOTHRADIUS ] = 0.01; m_Param [ BOUND_ZMIN_SLOPE ] = 0.4; m_Param [ FORCE_XMIN_SIN ] = 12.00; m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; case 10: // Large sim m_Vec [ SPH_VOLMIN ].Set ( -35, -35, 0 ); m_Vec [ SPH_VOLMAX ].Set ( 35, 35, 60 ); m_Vec [ SPH_INITMIN ].Set ( -5, -35, 0 ); m_Vec [ SPH_INITMAX ].Set ( 30, 0, 60 ); m_Vec [ PLANE_GRAV_DIR ].Set ( 0.0, 0, -9.8 ); break; } SPH_ComputeKernels (); m_Param [ SPH_SIMSIZE ] = m_Param [ SPH_SIMSCALE ] * (m_Vec[SPH_VOLMAX].z - m_Vec[SPH_VOLMIN].z); m_Param [ SPH_PDIST ] = pow ( m_Param[SPH_PMASS] / m_Param[SPH_RESTDENSITY], 1/3.0 ); float ss = m_Param [ SPH_PDIST ]*0.87 / m_Param[ SPH_SIMSCALE ]; printf ( "Spacing: %f\n", ss); AddVolume ( m_Vec[SPH_INITMIN], m_Vec[SPH_INITMAX], ss ); // Create the particles float cell_size = m_Param[SPH_SMOOTHRADIUS]*2.0; // Grid cell size (2r) Grid_Setup ( m_Vec[SPH_VOLMIN], m_Vec[SPH_VOLMAX], m_Param[SPH_SIMSCALE], cell_size, 1.0 ); // Setup grid Grid_InsertParticles (); // Insert particles Vector3DF vmin, vmax; vmin = m_Vec[SPH_VOLMIN]; vmin -= Vector3DF(2,2,2); vmax = m_Vec[SPH_VOLMAX]; vmax += Vector3DF(2,2,-2); #ifdef BUILD_CUDA FluidClearCUDA (); Sleep ( 500 ); FluidSetupCUDA ( NumPoints(), sizeof(Fluid), *(float3*)& m_GridMin, *(float3*)& m_GridMax, *(float3*)& m_GridRes, *(float3*)& m_GridSize, (int) m_Vec[EMIT_RATE].x ); Sleep ( 500 ); FluidParamCUDA ( m_Param[SPH_SIMSCALE], m_Param[SPH_SMOOTHRADIUS], m_Param[SPH_PMASS], m_Param[SPH_RESTDENSITY], m_Param[SPH_INTSTIFF], m_Param[SPH_VISC] ); #endif }
void FluidSystem::Advance () { char *dat1, *dat1_end; Fluid* p; Vector3DF norm, z; Vector3DF dir, accel; Vector3DF vnext; Vector3DF min, max; double adj; float SL, SL2, ss, radius; float stiff, damp, speed, diff; SL = m_Param[SPH_LIMIT]; SL2 = SL*SL; stiff = m_Param[SPH_EXTSTIFF]; damp = m_Param[SPH_EXTDAMP]; radius = m_Param[SPH_PRADIUS]; min = m_Vec[SPH_VOLMIN]; max = m_Vec[SPH_VOLMAX]; ss = m_Param[SPH_SIMSCALE]; dat1_end = mBuf[0].data + NumPoints()*mBuf[0].stride; for ( dat1 = mBuf[0].data; dat1 < dat1_end; dat1 += mBuf[0].stride ) { p = (Fluid*) dat1; // Compute Acceleration accel = p->sph_force; accel *= m_Param[SPH_PMASS]; // Velocity limiting speed = accel.x*accel.x + accel.y*accel.y + accel.z*accel.z; if ( speed > SL2 ) { accel *= SL / sqrt(speed); } // Boundary Conditions // Z-axis walls diff = 2 * radius - ( p->pos.z - min.z - (p->pos.x - m_Vec[SPH_VOLMIN].x) * m_Param[BOUND_ZMIN_SLOPE] )*ss; if (diff > EPSILON ) { norm.Set ( -m_Param[BOUND_ZMIN_SLOPE], 0, 1.0 - m_Param[BOUND_ZMIN_SLOPE] ); adj = stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } diff = 2 * radius - ( max.z - p->pos.z )*ss; if (diff > EPSILON) { norm.Set ( 0, 0, -1 ); adj = stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } // X-axis walls if ( !m_Toggle[WRAP_X] ) { diff = 2 * radius - ( p->pos.x - min.x + (sin(m_Time*10.0)-1+(p->pos.y*0.025)*0.25) * m_Param[FORCE_XMIN_SIN] )*ss; //diff = 2 * radius - ( p->pos.x - min.x + (sin(m_Time*10.0)-1) * m_Param[FORCE_XMIN_SIN] )*ss; if (diff > EPSILON ) { norm.Set ( 1.0, 0, 0 ); adj = (m_Param[ FORCE_XMIN_SIN ] + 1) * stiff * diff - damp * norm.Dot ( p->vel_eval ) ; accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } diff = 2 * radius - ( max.x - p->pos.x + (sin(m_Time*10.0)-1) * m_Param[FORCE_XMAX_SIN] )*ss; if (diff > EPSILON) { norm.Set ( -1, 0, 0 ); adj = (m_Param[ FORCE_XMAX_SIN ]+1) * stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } } // Y-axis walls diff = 2 * radius - ( p->pos.y - min.y )*ss; if (diff > EPSILON) { norm.Set ( 0, 1, 0 ); adj = stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } diff = 2 * radius - ( max.y - p->pos.y )*ss; if (diff > EPSILON) { norm.Set ( 0, -1, 0 ); adj = stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } // Wall barrier if ( m_Toggle[WALL_BARRIER] ) { diff = 2 * radius - ( p->pos.x - 0 )*ss; if (diff < 2*radius && diff > EPSILON && fabs(p->pos.y) < 3 && p->pos.z < 10) { norm.Set ( 1.0, 0, 0 ); adj = 2*stiff * diff - damp * norm.Dot ( p->vel_eval ) ; accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } } // Levy barrier if ( m_Toggle[LEVY_BARRIER] ) { diff = 2 * radius - ( p->pos.x - 0 )*ss; if (diff < 2*radius && diff > EPSILON && fabs(p->pos.y) > 5 && p->pos.z < 10) { norm.Set ( 1.0, 0, 0 ); adj = 2*stiff * diff - damp * norm.Dot ( p->vel_eval ) ; accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } } // Drain barrier if ( m_Toggle[DRAIN_BARRIER] ) { diff = 2 * radius - ( p->pos.z - min.z-15 )*ss; if (diff < 2*radius && diff > EPSILON && (fabs(p->pos.x)>3 || fabs(p->pos.y)>3) ) { norm.Set ( 0, 0, 1); adj = stiff * diff - damp * norm.Dot ( p->vel_eval ); accel.x += adj * norm.x; accel.y += adj * norm.y; accel.z += adj * norm.z; } } // Plane gravity if ( m_Param[PLANE_GRAV] > 0) accel += m_Vec[PLANE_GRAV_DIR]; // Point gravity if ( m_Param[POINT_GRAV] > 0 ) { norm.x = ( p->pos.x - m_Vec[POINT_GRAV_POS].x ); norm.y = ( p->pos.y - m_Vec[POINT_GRAV_POS].y ); norm.z = ( p->pos.z - m_Vec[POINT_GRAV_POS].z ); norm.Normalize (); norm *= m_Param[POINT_GRAV]; accel -= norm; } // Leapfrog Integration ---------------------------- vnext = accel; vnext *= m_DT; vnext += p->vel; // v(t+1/2) = v(t-1/2) + a(t) dt p->vel_eval = p->vel; p->vel_eval += vnext; p->vel_eval *= 0.5; // v(t+1) = [v(t-1/2) + v(t+1/2)] * 0.5 used to compute forces later p->vel = vnext; vnext *= m_DT/ss; p->pos += vnext; // p(t+1) = p(t) + v(t+1/2) dt if ( m_Param[CLR_MODE]==1.0 ) { adj = fabs(vnext.x)+fabs(vnext.y)+fabs(vnext.z) / 7000.0; adj = (adj > 1.0) ? 1.0 : adj; p->clr = COLORA( 0, adj, adj, 1 ); } if ( m_Param[CLR_MODE]==2.0 ) { float v = 0.5 + ( p->pressure / 1500.0); if ( v < 0.1 ) v = 0.1; if ( v > 1.0 ) v = 1.0; p->clr = COLORA ( v, 1-v, 0, 1 ); } // Euler integration ------------------------------- /* accel += m_Gravity; accel *= m_DT; p->vel += accel; // v(t+1) = v(t) + a(t) dt p->vel_eval += accel; p->vel_eval *= m_DT/d; p->pos += p->vel_eval; p->vel_eval = p->vel; */ if ( m_Toggle[WRAP_X] ) { diff = p->pos.x - (m_Vec[SPH_VOLMIN].x + 2); // -- Simulates object in center of flow if ( diff <= 0 ) { p->pos.x = (m_Vec[SPH_VOLMAX].x - 2) + diff*2; p->pos.z = 10; } } } m_Time += m_DT; }
void FluidSystem::Run () { bool bTiming = true; mint::Time start, stop; float ss = m_Param [ SPH_PDIST ] / m_Param[ SPH_SIMSCALE ]; // simulation scale (not Schutzstaffel) if ( m_Vec[EMIT_RATE].x > 0 && (++m_Frame) % (int) m_Vec[EMIT_RATE].x == 0 ) { //m_Frame = 0; Emit ( ss ); } #ifdef NOGRID // Slow method - O(n^2) SPH_ComputePressureSlow (); SPH_ComputeForceSlow (); #else if ( m_Toggle[USE_CUDA] ) { #ifdef BUILD_CUDA // -- GPU -- start.SetSystemTime ( ACC_NSEC ); TransferToCUDA ( mBuf[0].data, (int*) &m_Grid[0], NumPoints() ); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "TO: %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); Grid_InsertParticlesCUDA (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "INSERT (CUDA): %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); SPH_ComputePressureCUDA (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "PRESS (CUDA): %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); SPH_ComputeForceCUDA (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "FORCE (CUDA): %s\n", stop.GetReadableTime().c_str() ); } //** CUDA integrator is incomplete.. // Once integrator is done, we can remove TransferTo/From steps /*start.SetSystemTime ( ACC_NSEC ); SPH_AdvanceCUDA( m_DT, m_DT/m_Param[SPH_SIMSCALE] ); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "ADV (CUDA): %s\n", stop.GetReadableTime().c_str() ); }*/ start.SetSystemTime ( ACC_NSEC ); TransferFromCUDA ( mBuf[0].data, (int*) &m_Grid[0], NumPoints() ); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "FROM: %s\n", stop.GetReadableTime().c_str() ); } // .. Do advance on CPU Advance(); #endif } else { // -- CPU only -- start.SetSystemTime ( ACC_NSEC ); Grid_InsertParticles (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "INSERT: %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); SPH_ComputePressureGrid (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "PRESS: %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); SPH_ComputeForceGridNC (); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "FORCE: %s\n", stop.GetReadableTime().c_str() ); } start.SetSystemTime ( ACC_NSEC ); Advance(); if ( bTiming) { stop.SetSystemTime ( ACC_NSEC ); stop = stop - start; printf ( "ADV: %s\n", stop.GetReadableTime().c_str() ); } } #endif }
const float3& GetPoint(unsigned int i) const { return points[std::min(i, NumPoints() - 1)]; }
void TriObject::Deform(Deformer *defProc,int useSel) { int nv = NumPoints(); int i; if ( useSel ) { BitArray sel = mesh.VertexTempSel(); float *vssel = mesh.getVSelectionWeights (); #if TRI_MULTI_PROCESSING WaitForSingleObject(defMutex, INFINITE); defStuff.triobj = this; defStuff.defProc = defProc; defStuff.ct = nv / 2; defStuff.useSel = 1; defStuff.sel = sel; defStuff.vssel = vssel; SetEvent(defStartEvent); Sleep(0); if (vssel) { for (i=nv/2; i<nv; i++) { if(sel[i]) { SetPoint(i,defProc->Map(i,GetPoint(i))); continue; } if (vssel[i]==0) continue; Point3 & A = GetPoint(i); Point3 dir = defProc->Map(i,A) - A; SetPoint(i,A+vssel[i]*dir); } } else { for (i=nv/2; i<nv; i++) if(sel[i]) SetPoint(i,defProc->Map(i,GetPoint(i))); } WaitForSingleObject(defEndEvent, INFINITE); ReleaseMutex(defMutex); #else if (vssel) { for (i=0; i<nv; i++) { if(sel[i]) { SetPoint(i,defProc->Map(i,GetPoint(i))); continue; } if (vssel[i]==0) continue; Point3 & A = GetPoint(i); Point3 dir = defProc->Map(i,A) - A; SetPoint(i,A+vssel[i]*dir); } } else { for (i=0; i<nv; i++) if (sel[i]) SetPoint(i,defProc->Map(i,GetPoint(i))); } #endif } else { #if TRI_MULTI_PROCESSING WaitForSingleObject(defMutex, INFINITE); defStuff.triobj = this; defStuff.defProc = defProc; defStuff.ct = nv / 2; defStuff.useSel = 0; SetEvent(defStartEvent); Sleep(0); for (i=nv/2; i<nv; i++) SetPoint(i,defProc->Map(i,GetPoint(i))); WaitForSingleObject(defEndEvent, INFINITE); ReleaseMutex(defMutex); #else for (i=0; i<nv; i++) SetPoint(i,defProc->Map(i,GetPoint(i))); #endif } PointsWereChanged(); }