void ParticleController::doubleDensityRelaxation( float neighborhood, float restDensity, float stiffnessParameter, float stiffnessParameterNear ) { float neighborhoodSqrd = neighborhood * neighborhood; for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ p1->mDensity = 0.0f; p1->mNearDensity = 0.0f; for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float q = rijSqrd / neighborhoodSqrd; p1->mDensity += ( 1-q ) * ( 1-q ); p1->mNearDensity += ( 1-q ) * ( 1-q ) * ( 1-q ); } p1->mPressure = stiffnessParameter * ( p1->mDensity - restDensity ); p1->mNearPressure = stiffnessParameterNear * p1->mNearDensity; Vec2f dpos = Vec2f::zero(); for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float q = rijSqrd / neighborhoodSqrd; Vec2f DPos = rij.normalized() * ( p1->mPressure * ( 1-q ) + p1->mNearPressure * ( 1-q ) * ( 1-q ) ); p2->mPos += DPos/2; dpos -= DPos/2; } p1->mPos += dpos; } }
//--------------------------------------------------------------------------------------------------- void FactionState::ProcessAction(AIAction action, const ActionBuffer& commandBuffer) { ShipState* ship; uint32_t shipId; switch (action) { case kForce: shipId = commandBuffer.ReadUInt(); ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr; if (ship != nullptr && &ship->faction() == this) { Vec2f force = commandBuffer.ReadVec2f(); float totalForceSquared = force.lengthSquared(); if (totalForceSquared > AICommand::kMaxForce*AICommand::kMaxForce) force = force.normalized() * AICommand::kMaxForce; ship->set_force(force); } break; case kFire: shipId = commandBuffer.ReadUInt(); ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr; if (ship != nullptr && &ship->faction() == this) battle_.Fire(*ship); break; } }
void ParticleEmitter::repulseParticles() { for( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ list<Particle>::iterator p2 = p1; for( ++p2; p2 != mParticles.end(); ++p2 ) { Vec2f dir = p1->mLoc - p2->mLoc; float thresh = ( p1->mRadius + p2->mRadius ) * 5.0f; if( dir.x > -thresh && dir.x < thresh && dir.y > -thresh && dir.y < thresh ){ float distSqrd = dir.lengthSquared() * dir.length(); if( distSqrd > 0.0f ){ float F = 1.0f/distSqrd; dir.normalize(); // acceleration = force / mass p1->mAcc += ( F * dir ) / p1->mMass; p2->mAcc -= ( F * dir ) / p2->mMass; // TMP p1->mAcc *= 0.005; p2->mAcc *= 0.005; } } } } }
void WaterSimApp::mouseMove( MouseEvent event ) { Vec2f delta = Vec2f( getWindowWidth(), getWindowHeight() ) / 2.0f - event.getPos(); if( delta.lengthSquared() > 5 ) { mGravityVector = delta.normalized() * 9.8f; mGravityVector.y = -mGravityVector.y; } }
//-------------------------------------------------------------- void DrawerBase::drawVectors(float x, float y, float renderWidth, float renderHeight) const { if(enabled == false) return; ofPushStyle(); if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD); else ofDisableAlphaBlending(); int fw = _fluidSolver->getWidth(); int fh = _fluidSolver->getHeight(); // int xStep = renderWidth / 10; // every 10 pixels // int yStep = renderHeight / 10; // every 10 pixels ofPushMatrix(); ofTranslate(x, y, 0); ofScale(renderWidth/(fw-2), renderHeight/(fh-2), 1.0); float maxVel = 5.0f/20000; Vec2f vel; float vt = velDrawThreshold * _fluidSolver->getInvWidth() * _fluidSolver->getInvHeight(); vt *= vt; for (int j=0; j<fh-2; j+=vectorSkipCount+1 ){ for (int i=0; i<fw-2; i+=vectorSkipCount+1 ){ vel = _fluidSolver->getVelocityAtCell(i+1, j+1); float d2 = vel.lengthSquared(); if(d2>vt) { if(d2 > maxVel * maxVel) { float mult = maxVel * maxVel/ d2; // float mult = (d2 - maxVel * maxVel) / d2; vel.x *= mult; vel.y *= mult; } vel *= velDrawMult * 50000; float b = mapRange(d2, vt, maxVel, 0.0f, brightness); b = brightness*255; // ofBeginShape(); // ofSetColor(0, 0, 0); // ofVertex(i, j); ofSetColor(b, b, b); ofDrawLine(i, j, i + vel.x, j + vel.y); // ofVertex(i + vel.x, j + vel.y); // ofEndShape(); } } } ofPopMatrix(); ofPopStyle(); }
void ParticleController::applyViscosity( float neighborhood, float viscositySigma, float viscosityBeta ) { float neighborhoodSqrd = neighborhood * neighborhood; for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float u = ( p1->mVel - p2->mVel ).dot( rij.normalized() ); float q = rijSqrd / neighborhoodSqrd; if ( u > 0 ){ Vec2f I = ( 1 - q ) * ( ( viscositySigma * u ) + ( viscosityBeta * u * u ) ) * rij.normalized(); p1->mVel -= I/2; p2->mVel += I/2; } } } }
void Arcball::mapToSphere(const Vector2D& point, Vector3D& newVec) const{ Vec2f tempVec = Vec2f(point.x, point.y); //scale to [-1..1] tempVec.x = (tempVec.x * ADJ_WIDTH) - 1.0f; tempVec.y = 1.0f - (tempVec.y * ADJ_HEIGHT); float length = tempVec.lengthSquared(); //outside of the sphere? if (length > 1.0f){ float norm = sqrt(length); newVec.x = tempVec.x*norm; newVec.y = tempVec.y*norm; newVec.z = 0.0f; } else{ newVec.x = tempVec.x; newVec.y = tempVec.y; newVec.z = sqrt(1.0f-length); } }
void Controller::checkForBalloonPop( const Vec2f &mousePos ) { for( vector<Balloon>::reverse_iterator it = mBalloons.rbegin(); it != mBalloons.rend(); ++it ){ Vec2f dir = mousePos - it->mScreenPos; float distSqrd = dir.lengthSquared(); if( distSqrd < 1000.0f ){ Vec3f pos = it->mPos; float lifespan = 12.0f; float speed = 20.0f; mShockwaves.push_back( Shockwave( it->mPos, Vec3f::yAxis(), lifespan, speed ) ); int numConfettis = 250; addConfettis( numConfettis, pos, 0.5f ); // PLAY A BALLOON POP AUDIO FILE HERE it->mIsDead = true; break; } } }
double PathFitter::computeMaxError(vector<Vec2f> const &d, int first, int last, vector<Vec2f> *bezCurve, vector<double> const &u, int *splitPoint) { int i; double maxDist; // Maximum error double dist; // Current error Vec2f P; // Point on curve Vec2f v; // Vector from point to curve *splitPoint = (last - first + 1)/2; maxDist = 0.0; for (i = first + 1; i < last; i++) { P = bezierII(3, *bezCurve, u[i-first]); v = P - d[i]; dist = v.lengthSquared(); if (dist >= maxDist) { maxDist = dist; *splitPoint = i; } } return (maxDist); }
void Fluid2DCamAppApp::update() { if( mCapture && mCapture.checkNewFrame() ) { if( ! mTexCam ) { mTexCam = gl::Texture( mCapture.getSurface() ); } // Flip the image if( ! mFlipped ) { Surface8u srcImg = mCapture.getSurface(); mFlipped = Surface8u( srcImg.getWidth(), srcImg.getHeight(), srcImg.hasAlpha(), srcImg.getChannelOrder() ); } Surface8u srcImg = mCapture.getSurface(); mFlipped = Surface8u( srcImg.getWidth(), srcImg.getHeight(), srcImg.hasAlpha(), srcImg.getChannelOrder() ); for( int y = 0; y < mCapture.getHeight(); ++y ) { const Color8u* src = (const Color8u*)(srcImg.getData() + (y + 1)*srcImg.getRowBytes() - srcImg.getPixelInc()); Color8u* dst = (Color8u*)(mFlipped.getData() + y*mFlipped.getRowBytes()); for( int x = 0; x < mCapture.getWidth(); ++x ) { *dst = *src; ++dst; --src; } } // Create scaled image if( ! mCurScaled ) { mCurScaled = Surface8u( mFlipped.getWidth()/kFlowScale, mFlipped.getHeight()/kFlowScale, mFlipped.hasAlpha(), mFlipped.getChannelOrder() ); } ip::resize( mFlipped, &mCurScaled ); // Optical flow if( mCurScaled && mPrvScaled ) { mPrvCvData = mCurCvData; mCurCvData = cv::Mat( toOcv( Channel( mCurScaled ) ) ); if( mPrvCvData.data && mCurCvData.data ) { int pyrLvels = 3; int winSize = 3; int iters = 5; int poly_n = 7; double poly_sigma = 1.5; cv::calcOpticalFlowFarneback( mPrvCvData, mCurCvData, mFlow, 0.5, pyrLvels, 2*winSize + 1, iters, poly_n, poly_sigma, cv::OPTFLOW_FARNEBACK_GAUSSIAN ); if( mFlow.data ) { if( mFlowVectors.empty() ) { mFlowVectors.resize( mCurScaled.getWidth()*mCurScaled.getHeight() ); } //memset( &mFlowVectors[0], 0, mCurScaled.getWidth()*mCurScaled.getHeight()*sizeof( Vec2f ) ); mNumActiveFlowVectors = 0; for( int j = 0; j < mCurScaled.getHeight(); ++j ) { for( int i = 0; i < mCurScaled.getWidth(); ++i ) { const float* fptr = reinterpret_cast<float*>(mFlow.data + j*mFlow.step + i*sizeof(float)*2); // Vec2f v = Vec2f( fptr[0], fptr[1] ); if( v.lengthSquared() >= mVelThreshold ) { if( mNumActiveFlowVectors >= (int)mFlowVectors.size() ) { mFlowVectors.push_back( std::make_pair( Vec2i( i, j ), v ) ); } else { mFlowVectors[mNumActiveFlowVectors] = std::make_pair( Vec2i( i, j ), v ); } ++mNumActiveFlowVectors; } } } } } } // Update texture mTexCam.update( mFlipped ); // Save previous frame if( ! mPrvScaled ) { mPrvScaled = Surface8u( mCurScaled.getWidth(), mCurScaled.getHeight(), mCurScaled.hasAlpha(), mCurScaled.getChannelOrder() ); } memcpy( mPrvScaled.getData(), mCurScaled.getData(), mCurScaled.getHeight()*mCurScaled.getRowBytes() ); } // Update fluid float dx = (mFluid2DResX - 2)/(float)(640/kFlowScale); float dy = (mFluid2DResY - 2)/(float)(480/kFlowScale); for( int i = 0; i < mNumActiveFlowVectors; ++i ) { Vec2f P = mFlowVectors[i].first; const Vec2f& v = mFlowVectors[i].second; mFluid2D.splatDensity( P.x*dx + 1, P.y*dy + 1, mDenScale*v.lengthSquared() ); mFluid2D.splatVelocity( P.x*dx + 1, P.y*dy + 1, v*mVelScale ); } mFluid2D.step(); // Update velocity const Vec2f* srcVel0 = mFluid2D.dbgVel0().data(); const Vec2f* srcVel1 = mFluid2D.dbgVel1().data(); Colorf* dstVel0 = (Colorf*)mSurfVel0.getData(); Colorf* dstVel1 = (Colorf*)mSurfVel1.getData(); for( int j = 0; j < mFluid2DResY; ++j ) { for( int i = 0; i < mFluid2DResX; ++i ) { *dstVel0 = Colorf( srcVel0->x, srcVel0->y, 0.0f ); *dstVel1 = Colorf( srcVel1->x, srcVel1->y, 0.0f ); ++srcVel0; ++srcVel1; ++dstVel0; ++dstVel1; } } // Update Density mChanDen0 = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgDen0().data() ); mChanDen1 = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgDen1().data() ); mTexDen0.update( mChanDen0 ); mTexDen1.update( mChanDen1 ); // Update velocity textures mTexVel0.update( mSurfVel0 ); mTexVel1.update( mSurfVel1 ); // Update Divergence mChanDiv = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgDivergence().data() ); mTexDiv.update( mChanDiv ); // Update Divergence mChanPrs = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgPressure().data() ); mTexPrs.update( mChanPrs ); // Update Curl, Curl Length mChanCurl = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgCurl().data() ); mTexCurl.update( mChanCurl ); mChanCurlLen = Channel32f( mFluid2DResX, mFluid2DResY, mFluid2DResX*sizeof(float), 1, mFluid2D.dbgCurlLength().data() ); mTexCurlLen.update( mChanCurlLen ); }
/* * RETURNS numeric_limits<float>::max() IF CLOSEST POINT IS FARTHER THAN threshold DISTANCE * * REFERENCE: "Minimum Distance between a Point and a Line" BY Paul Bourke * http://paulbourke.net/geometry/pointlineplane */ float getShortestDistance(const Vec2f &point, const vector<Vec2f> &polygon, bool close, float threshold) { float min = threshold * threshold; // BECAUSE IT IS MORE EFFICIENT TO WORK WITH MAGNIFIED DISTANCES int end = polygon.size(); bool found = false; for (int i = 0; i < end; i++) { int i0, i1; if (i == end - 1) { if (close) { i0 = i; i1 = 0; } else { break; } } else { i0 = i; i1 = i + 1; } Vec2f p0 = polygon[i0]; Vec2f p1 = polygon[i1]; if (p0 != p1) { Vec2f delta = p1 - p0; float u = delta.dot(point - p0) / delta.lengthSquared(); if (u >= 0 && u <= 1) { Vec2f p = p0 + u * delta; float mag = (p - point).lengthSquared(); if (mag < min) { min = mag; found = true; } } else { float mag0 = (p0 - point).lengthSquared(); float mag1 = (p1 - point).lengthSquared(); if ((mag0 < min) && (mag0 < mag1)) { min = mag0; found = true; } else if ((mag1 < min) && (mag1 < mag0)) { min = mag1; found = true; } } } } return found ? ci::math<float>::sqrt(min) : numeric_limits<float>::max(); }
void PeerCircle::update() { // attraction to torrent position Vec2f dir = mAttractorPos - mPos; float distSqrd = dir.lengthSquared(); float strength = 5.f; if ( distSqrd > 0.f ) { float minDistSqrd = 1000.f; if ( distSqrd < minDistSqrd ) { strength = lmap< float >( 1.f, minDistSqrd, 0.f, strength, distSqrd ); strength = math< float >::clamp( strength, 0.f, 5.f ); } float force = strength * mMass / distSqrd; Vec2f deltaForce = dir * force; moveBy( deltaForce * mInvMass, false ); } // repel other peers const std::vector< PeerRef > &peers = mTorrentRef->getPeers(); for ( PeerRef peer : peers ) { if ( peer->getId() == mId ) continue; auto other = std::static_pointer_cast< PeerCircle >( peer ); Vec2d dir = mPos - other->getPos(); float distSqrd = dir.lengthSquared(); if ( distSqrd > .0f ) { float force = .1f * mMass * other->getMass() / distSqrd; Vec2f deltaForce = dir * force; moveBy( deltaForce * mInvMass, false ); other->moveBy( - deltaForce * other->getInvMass(), false ); } } // do verlet Vec2f curPos = mPos; Vec2f vel = mPos - mOldPos; mPos += vel * mDrag; mOldPos = curPos; /* // TODO: attract actual torrent position Vec2d dir = Vec2d( 500, 500 ) - mPos; double distSqrd = dir.lengthSquared(); if ( distSqrd > 0. ) { double f = math< double >::sqrt( distSqrd ) * .00001; mAcc += dir.normalized() * f; } mVel += mAcc; mPos += mVel; mVel *= mDecay; mAcc.set( 0., 0. ); //mRadius = lerp< double, double >( mRadius, mRadiusOrig, .01 ); */ }
void ParticleController::checkForNeighbors( float neighborhood ) { int ctr1 = 0; int ctr2 = 0; float neighborhoodSqrd = neighborhood * neighborhood; int scnt = 0; Spring *s1; Particle *it; for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){ if ( ctr1 < mParticles.size() - 1 ){ for ( list<Particle>::iterator p2 = mParticles.begin(); p2 != mParticles.end(); ++p2 ){ //std::cout << "s: " << scnt << "\n"; //std::cout << "1: " << ctr1 << "\n"; //std::cout << "2: " << ctr2 << "\n"; if ( ctr1 != ctr2 ){ Vec2f rij = p1->mPos - p2->mPos; float rijSqrd = rij.lengthSquared(); float q = rijSqrd / neighborhoodSqrd; it = &*p2; //s1 = mSprings.at( scnt ); //std::cout << "before: " << s1.mIsActive << "\n"; /* std::cout << "p1: "; std::cout << p1->mPos; std::cout << " p2: "; std::cout << p2->mPos << "\n"; std::cout << "sA: "; std::cout << s1.pA->mPos; std::cout << " sb: "; std::cout << s1.pB->mPos << "\n\n"; */ Particle *part1 = &*p1; Particle *part2 = &*p2; if ( q < 1.0f ){ p1->addNeighbor( it ); if ( ctr2 > ctr1 ){ p1->addForwardNeighbor( it ); //std::cout << scnt << "\n"; s1 = new Spring( part1, part2, neighborhood ); //std::cout << scnt << ": " << s1->particleA->mPos << ": " << s1->particleB->mPos << "\n"; addSpring( s1 ); //s1.makeActive(); //s1.mIsActive = true; } } else { //std::cout << "FALSE"; if ( ctr2 > ctr1 ){ //std::cout << scnt << "\n"; //s1 = new Spring( part1, part2, neighborhood ); //destroySpring( s1 ); //s1.kill(); //s1.mIsActive = false; } } //std::cout << "after: " << s1.mIsActive << "\n"; if ( ctr2 > ctr1 ){ scnt++; // springs are forward counting } } ctr2++; } } ctr1++; ctr2 = 0; //scnt++; } }