void ParticleEmitter3D::PrepareEmitterParameters(Particle * particle, float32 velocity, int32 emitIndex) { Vector3 tempPosition = Vector3(); Matrix4 * worldTransformPtr = GetWorldTransformPtr(); Matrix3 rotationMatrix; rotationMatrix.Identity(); if(worldTransformPtr) { tempPosition = worldTransformPtr->GetTranslationVector(); rotationMatrix = Matrix3(*worldTransformPtr);; } //Vector3 tempPosition = particlesFollow ? Vector3() : position; if (emitterType == EMITTER_POINT) { particle->position = tempPosition; } else if (emitterType == EMITTER_RECT) { float32 rand05_x = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_y = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_z = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] Vector3 lineDirection(0, 0, 0); if(size) lineDirection = Vector3(size->GetValue(time).x * rand05_x, size->GetValue(time).y * rand05_y, size->GetValue(time).z * rand05_z); //particle->position = tempPosition + lineDirection; particle->position = tempPosition + TransformPerserveLength(lineDirection, rotationMatrix); } else if ((emitterType == EMITTER_ONCIRCLE_VOLUME) || (emitterType == EMITTER_ONCIRCLE_EDGES)) { CalculateParticlePositionForCircle(particle, tempPosition, rotationMatrix); } if (emitterType == EMITTER_SHOCKWAVE) { // For "Shockwave" emitters the calculation is different. PrepareEmitterParametersShockwave(particle, velocity, emitIndex, tempPosition, rotationMatrix); } else { PrepareEmitterParametersGeneric(particle, velocity, emitIndex, tempPosition, rotationMatrix); } if(worldTransformPtr) { Matrix4 newTransform = *worldTransformPtr; newTransform._30 = newTransform._31 = newTransform._32 = 0; float32 speedLength = particle->speed.Length(); particle->speed = particle->speed*newTransform; float32 speedLengthAfter = particle->speed.Length(); if (speedLengthAfter) particle->speed*=speedLength/speedLengthAfter; } }
void ParticleEmitter::PrepareEmitterParameters(Particle * particle, float32 velocity, int32 emitIndex) { // Yuri Coder, 2013/01/30. ParticleEmitter class can be now only 2D. Vector3 tempPosition = particlesFollow ? Vector3() : position; if (emitterType == EMITTER_POINT) { particle->position = tempPosition; } else if (emitterType == EMITTER_RECT) { // TODO: add emitter angle support float32 rand05_x = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_y = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_z = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] Vector3 lineDirection(0, 0, 0); if(size) lineDirection = Vector3(size->GetValue(time).x * rand05_x, size->GetValue(time).y * rand05_y, size->GetValue(time).z * rand05_z); particle->position = tempPosition + lineDirection; } else if ((emitterType == EMITTER_ONCIRCLE) || (emitterType == EMITTER_SHOCKWAVE)) { // here just set particle position // Yuri Coder, 2013/04/18. Shockwave particle isn't implemented for 2D mode - // currently draw them in the same way as "onCircle" ones. particle->position = tempPosition; } Vector3 vel; //vel.x = (float32)((rand() & 255) - 128); //vel.y = (float32)((rand() & 255) - 128); //vel.Normalize(); float32 rand05 = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 particleAngle = 0; if(emissionAngle) particleAngle = DegToRad(emissionAngle->GetValue(time) + angle); float32 range = 0.0f; if(emissionRange) range = DegToRad(emissionRange->GetValue(time)); if (emitPointsCount == -1) { // if emitAtPoints property is not set just emit randomly in range particleAngle += range * rand05; } else { particleAngle += range * (float32)emitIndex / (float32)emitPointsCount; } vel.x = cosf(particleAngle); vel.y = sinf(particleAngle); vel.z = 0; // reuse particle velocity we've calculated // Yuri Coder, 2013/04/18. Shockwave particle isn't implemented for 2D mode - // currently draw them in the same way as "onCircle" ones. if ((emitterType == EMITTER_ONCIRCLE) || (emitterType == EMITTER_SHOCKWAVE)) { if(radius) particle->position += vel * radius->GetValue(time); } particle->direction.x = vel.x; particle->direction.y = vel.y; particle->speed = velocity; particle->angle = particleAngle; }
void ParticleEmitter3D::PrepareEmitterParameters(Particle * particle, float32 velocity, int32 emitIndex) { Vector3 tempPosition = Vector3(); Matrix4 * worldTransformPtr = GetWorldTransformPtr(); if(worldTransformPtr) { tempPosition = worldTransformPtr->GetTranslationVector(); } //Vector3 tempPosition = particlesFollow ? Vector3() : position; if (emitterType == EMITTER_POINT) { particle->position = tempPosition; } else if (emitterType == EMITTER_LINE) { // TODO: add emitter angle support float32 rand05 = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] Vector3 lineDirection(0, 0, 0); if(size) lineDirection = size->GetValue(time)*rand05; particle->position = tempPosition + lineDirection; } else if (emitterType == EMITTER_RECT) { // TODO: add emitter angle support float32 rand05_x = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_y = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] float32 rand05_z = (float32)Random::Instance()->RandFloat() - 0.5f; // [-0.5f, 0.5f] Vector3 lineDirection(0, 0, 0); if(size) lineDirection = Vector3(size->GetValue(time).x * rand05_x, size->GetValue(time).y * rand05_y, size->GetValue(time).z * rand05_z); particle->position = tempPosition + lineDirection; } else if (emitterType == EMITTER_ONCIRCLE) { // here just set particle position particle->position = tempPosition; } Vector3 vel = Vector3(1.0f, 0.0f, 0.0f); if(emissionVector) { vel = emissionVector->GetValue(0); vel = vel*rotationMatrix; } Vector3 rotVect(0, 0, 1); float32 phi = PI*2*(float32)Random::Instance()->RandFloat(); if(vel.x != 0) { rotVect.y = sinf(phi); rotVect.z = cosf(phi); rotVect.x = - rotVect.y*vel.y/vel.x - rotVect.z*vel.z/vel.x; } else if(vel.y != 0) { rotVect.x = cosf(phi); rotVect.z = sinf(phi); rotVect.y = - rotVect.z*vel.z/vel.y; } else if(vel.z != 0) { rotVect.x = cosf(phi); rotVect.y = sinf(phi); rotVect.z = 0; } rotVect.Normalize(); float32 range = 0; if(emissionRange) range = DegToRad(emissionRange->GetValue(time) + angle); float32 rand05 = (float32)Random::Instance()->RandFloat() - 0.5f; Vector3 q_v(rotVect*sinf(range*rand05/2)); float32 q_w = cosf(range*rand05/2); Vector3 q1_v(q_v); float32 q1_w = -q_w; q1_v /= (q_v.SquareLength() + q_w*q_w); q1_w /= (q_v.SquareLength() + q_w*q_w); Vector3 v_v(vel); Vector3 qv_v = q_v.CrossProduct(v_v) + q_w*v_v; float32 qv_w = - q_v.DotProduct(v_v); Vector3 qvq1_v = qv_v.CrossProduct(q1_v) + qv_w*q1_v + q1_w*qv_v; Vector3 speed = qvq1_v * velocity; particle->speed = speed.Length(); particle->direction = speed/particle->speed; if (particle->direction.x <= EPSILON && particle->direction.x >= -EPSILON) particle->direction.x = 0.f; if (particle->direction.y <= EPSILON && particle->direction.y >= -EPSILON) particle->direction.y = 0.f; if (particle->direction.z <= EPSILON && particle->direction.z >= -EPSILON) particle->direction.z = 0.f; if (emitterType == EMITTER_ONCIRCLE) { qvq1_v.Normalize(); if(radius) particle->position += qvq1_v * radius->GetValue(time); } particle->angle = atanf(particle->direction.z/particle->direction.x); if(worldTransformPtr) { Matrix4 newTransform = *worldTransformPtr; newTransform._30 = newTransform._31 = newTransform._32 = 0; particle->direction = particle->direction*newTransform; } }
bool ContourModel::update(vector<vector<Point> > contours,vector<Point2d>& originalPoints, int image_w_half) { //step 1: find the larger contours to filter out some noise (area > thresh) vector<vector<Point> > largeContours; int areaThreshold = 130; for(int i = 0;i < (int)contours.size();i++) { vector<Point> currCont = contours.at(i); double area = contourArea(contours.at(i)); if(area > areaThreshold) { largeContours.push_back(currCont); } } //step 2: for each larger contour: find the center of mass and the lane direction to group them vector<Point2d> mass_centers; vector<Point2d> line_directions; for(int i = 0;i < (int)largeContours.size();i++) { //calculate the line direction for each contour Vec4f lineParams; fitLine(largeContours.at(i), lineParams, CV_DIST_L2, 0, 0.01, 0.01); Point2d lineDirection(lineParams[0],lineParams[1]); line_directions.push_back(lineDirection); //calculate the mass center for each contour vector<Moments> contourMoments; Moments currMoments = moments(largeContours.at(i)); double x_cent = currMoments.m10 / currMoments.m00; double y_cent = currMoments.m01 / currMoments.m00; Point2d mass_cent(x_cent,y_cent); mass_centers.push_back(mass_cent); } //assert these vectors have same length: if(largeContours.size() != mass_centers.size())cout << "ERROR in ContourModel: massCenters.size != largeContours.size()" << endl; if(largeContours.size() != line_directions.size())cout << "ERROR in ContourModel: massCenters.size != largeContours.size()" << endl; //step 3: create the "mergeList": store for each contour weather it wants to merge with another one vector<vector<int> > mergelist; //merge contours based on center of mass and line direction for(int i = 0;i < (int)largeContours.size();i++) { vector<int> mergeWishes; Point2d currCenter = mass_centers.at(i); Point2d currDirection = line_directions.at(i); for(int j = i+1;j < (int)largeContours.size();j++) { Point2d compCenter = mass_centers.at(j); Point2d compDirection = line_directions.at(j); bool wantMerge = mergeContours(currCenter, currDirection, compCenter, compDirection); if(wantMerge)mergeWishes.push_back(j); } mergelist.push_back(mergeWishes); } //step 4: use the mergeList to create the final_mergelist which looks as follows: //[ [0,2,5] [3] [1] [4,6]] telling which contours should be merged together vector<vector<int> > final_mergelist; for(int i = 0;i < (int)largeContours.size();i++) { vector<int> temp; temp.push_back(i); final_mergelist.push_back(temp); } for(int i = 0;i < (int)largeContours.size();i++) { vector<int>* containerToPushTo = NULL; //step 1: find the container the contour i is in - note that this will always succeed so containerToPushTo wont stay NULL for(int j = 0;j < (int)final_mergelist.size();j++) { vector<int>* currContainer; currContainer = &final_mergelist.at(j); for(int k = 0;k < (int)final_mergelist.at(j).size();k++) { if(final_mergelist.at(j).at(k) == i) { containerToPushTo = currContainer; } } } //step2: for each element to push: make sure it appears in the container for(int j = 0;j < (int)mergelist.at(i).size();j++) { int elemToMerge = mergelist.at(i).at(j); //if elemToMerge already appears in containerToPushTo => do nothing bool alreadyInContainer = false; for(int k = 0;k < (int)containerToPushTo->size();k++) { if(containerToPushTo->at(k) == elemToMerge) alreadyInContainer = true; } //not inside: push the element and delete it from the old vector it was in if(!alreadyInContainer) { //delete it from the old container!! for(int k = 0;k < (int)final_mergelist.size();k++) { for(int l = 0;l < (int)final_mergelist.at(k).size();l++) { //DEBUG IFS - ERASE LATER if(k < 0 || k >= (int)final_mergelist.size())cout << "OVERFLOW IN 159::ContourModel" << endl; if(l < 0 || l >= (int)final_mergelist.at(k).size())cout << "OVERFLOW IN 160::ContourModel" << endl; if(final_mergelist.at(k).at(l) == elemToMerge) { //DEBUG IF- ERASE LATER if(l < 0 || l >= (int)final_mergelist.at(k).size()) cout << "ERROR ContourModel 162" << endl; final_mergelist.at(k).erase(final_mergelist.at(k).begin()+l); } } } //add it in the new container containerToPushTo->push_back(elemToMerge); } } } //step 5: merge the contours together vector< vector<vector<Point> > > mergedContours; for(int i = 0;i < (int)final_mergelist.size();i++) { vector<vector<Point> > currGrouping; for(int j = 0;j < (int)final_mergelist.at(i).size();j++) { vector<Point> currContour = largeContours.at(final_mergelist.at(i).at(j)); currGrouping.push_back(currContour); } if(currGrouping.size() > 0)mergedContours.push_back(currGrouping); } //TRY TO FIND THE MIDDLE LANE vector<vector<Point> > singleContours; vector<vector<vector<Point> > > multipleContours; for(int i = 0;i < (int)mergedContours.size();i++) { vector<vector<Point> > currContGroup = mergedContours.at(i); if(currContGroup.size() == 1) singleContours.push_back(currContGroup.at(0)); else if(currContGroup.size() > 1) multipleContours.push_back(currContGroup); } //in this situation there is actually a chance to apply the middle lane extraction, otherwise the old procedure is applied if(multipleContours.size() == 1 && singleContours.size() <= 2 && singleContours.size() > 0) { //sort single contours by area std::sort(singleContours.begin(),singleContours.end(),acompareCont); vector<Point> largestSingleContour = singleContours.at(singleContours.size()-1); double areaLargestSingle = contourArea(largestSingleContour); vector<vector<Point> > middleContour = multipleContours.at(0); double areaMiddle = 0; bool validMid = true; for(int i = 0;i < (int)middleContour.size();i++) { double areaCurr = contourArea(middleContour.at(i)); if(areaCurr > areaLargestSingle/2.0){ validMid = false; } areaMiddle += contourArea(middleContour.at(i)); } //if both contours have a certain size if(areaLargestSingle > 120 && areaMiddle > 120) { //MIDDLE LANE AND OTHER LANE FOUND => RETURN THE ESTIMATE //first argument will be the middle lane //second argument will be the other larger lane vector<vector<Point2d> > nicelyGroupedPoints; //1) --- MIDDLE LANE --- vector<Point2d> temp_result; for(int i = 0;i < (int)middleContour.size();i++) { vector<Point> currCont = middleContour.at(i); Rect bound = boundingRect(currCont); //visit every point in the bounding rect for(int y = bound.y;y < bound.y+bound.height;y++) { for(int x = bound.x;x < bound.x+bound.width;x++) { if(pointPolygonTest(currCont, Point(x,y), false) >= 0) { temp_result.push_back(Point2d(x-image_w_half,y)); } } } } nicelyGroupedPoints.push_back(temp_result); //2) --- OTHER LANE --- vector<Point2d> temp_result2; Rect bound = boundingRect(largestSingleContour); //visit every point in the bounding rect for(int y = bound.y;y < bound.y+bound.height;y++) { for(int x = bound.x;x < bound.x+bound.width;x++) { if(pointPolygonTest(largestSingleContour, Point(x,y), false) >= 0) { temp_result2.push_back(Point2d(x-image_w_half,y)); } } } if(validMid) { nicelyGroupedPoints.push_back(temp_result2); points = nicelyGroupedPoints; return true; //middle lane estimate provided } } } //MIDDLE LANE WAS NOT FOUND //step 6: get the final result: the grouped points matching the contours //need to perform a inside contour check within the bounding rectangle of the contour for //each point in the bounding rectangle vector<vector<Point2d> > nicelyGroupedPoints; for(int i = 0;i < (int)mergedContours.size();i++) { vector<Point2d> temp_result; for(int j = 0;j < (int)mergedContours.at(i).size();j++) { vector<Point> currContour = mergedContours.at(i).at(j); Rect bound = boundingRect(currContour); //visit every point in the bounding rect for(int y = bound.y;y < bound.y+bound.height;y++) { for(int x = bound.x;x < bound.x+bound.width;x++) { if(pointPolygonTest(currContour, Point(x,y), false) >= 0) { temp_result.push_back(Point2d(x-image_w_half,y)); } } } } if(temp_result.size() > 0) { nicelyGroupedPoints.push_back(temp_result); } } /* //step 6 (alternative): get the final result: the grouped points matching the contours //need to perform a inside contour check for the input points if in boundary rectangle of the contour vector<vector<Point2d> > nicelyGroupedPoints; for(int i = 0;i < mergedContours.size();i++) { vector<Point2d> temp_result; for(int j = 0;j < mergedContours.at(i).size();j++) { vector<Point> currContour = mergedContours.at(i).at(j); Rect bound = boundingRect(currContour); for(int k = 0;k < originalPoints.size();k++) { //check if within the contour: if(pointPolygonTest(currContour, originalPoints.at(k), false) >= 0) { temp_result.push_back(Point2d(originalPoints.at(k).x-image_w_half, originalPoints.at(k).y)); } } } if(temp_result.size() > 0) { nicelyGroupedPoints.push_back(temp_result); } } */ points = nicelyGroupedPoints; return false; //everything as usual, no further information }