/**
 * @brief Compute the coefficients of the number of planes specified for a given cloud. 
 * 
 * @param cloud Point cloud in which the computation is based.
 */
void MultiplePlaneSegmentation::computeCoefficients(const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud) {

	// Cloud containing the points without the planes.
	pcl::PointCloud<pcl::PointXYZRGBA>::Ptr remainingCloud = pcl::PointCloud<pcl::PointXYZRGBA>::Ptr(new pcl::PointCloud<pcl::PointXYZRGBA>(*cloud));

	// Create the segmentation object.
	pcl::SACSegmentation<pcl::PointXYZRGBA> seg;

	// Set segmentation parameters.
	seg.setModelType(pcl::SACMODEL_PARALLEL_PLANE);
	seg.setOptimizeCoefficients(true);
	seg.setAxis(orientation);
	seg.setEpsAngle(angleThreshold); 
	seg.setMethodType(pcl::SAC_RANSAC);
	seg.setMaxIterations(5000);
	seg.setDistanceThreshold(planeDistance);

	// Create the filtering object.
	pcl::ExtractIndices<pcl::PointXYZRGBA> extract;

	// At each step, one plane is removed from remainingCloud.
	for(int i = 0; i < nPlanes; i++){

		pcl::ModelCoefficients coefficients;
		pcl::PointIndices::Ptr inliers(new pcl::PointIndices());

		// Segment the largest planar component from the remaining cloud.
		seg.setInputCloud(remainingCloud);
		seg.segment(*inliers, coefficients);

		// Remove non valid points.
		removeNans(cloud,  inliers);

		// Make sure the normal is looking to the camera.
		float origin[] = {0,0,0};
		correctNormal(origin, cloud->points[inliers->indices[0]], coefficients);

		// With 0 inliers, nothing needs to be done.
		if (inliers->indices.size() == 0) break;

		// Extract the plane inliers from the remainingCloud.
		extract.setInputCloud(remainingCloud);
		extract.setIndices(inliers);
		extract.setNegative(true);
		extract.filter(*remainingCloud);

		// Update plane coefficients.
		planes[i].setCoefficients(coefficients);
	}
}
bool Foam::parcel::move(spray& sDB)
{
    const polyMesh& mesh = cloud().pMesh();
    const polyBoundaryMesh& pbMesh = mesh.boundaryMesh();

    const liquidMixture& fuels = sDB.fuels();

    scalar deltaT = sDB.runTime().deltaT().value();
    label Nf = fuels.components().size();
    label Ns = sDB.composition().Y().size();

    // Calculate the interpolated gas properties at the position of the parcel
    vector Up = sDB.UInterpolator().interpolate(position(), cell())
        + Uturb();
    scalar rhog = sDB.rhoInterpolator().interpolate(position(), cell());
    scalar pg = sDB.pInterpolator().interpolate(position(), cell());
    scalar Tg = sDB.TInterpolator().interpolate(position(), cell());

    scalarField Yfg(Nf, 0.0);

    scalar cpMixture = 0.0;
    for(label i=0; i<Ns; i++)
    {
        const volScalarField& Yi = sDB.composition().Y()[i];
        if (sDB.isLiquidFuel()[i])
        {
            label j = sDB.gasToLiquidIndex()[i];
            scalar Yicelli = Yi[cell()];
            Yfg[j] = Yicelli;
        }
        cpMixture += Yi[cell()]*sDB.gasProperties()[i].Cp(Tg);
    }

    // Correct the gaseous temperature for evaporated fuel

    scalar cellV = sDB.mesh().V()[cell()];
    scalar cellMass = rhog*cellV;
    Tg += sDB.shs()[cell()]/(cpMixture*cellMass);

    // Changed cut-off temperature for evaporation.  HJ, 27/Apr/2011
    Tg = max(273, Tg);

    scalar tauMomentum = GREAT;
    scalar tauHeatTransfer = GREAT;
    scalarField tauEvaporation(Nf, GREAT);
    scalarField tauBoiling(Nf, GREAT);

    bool keepParcel = true;

    setRelaxationTimes
    (
        cell(),
        tauMomentum,
        tauEvaporation,
        tauHeatTransfer,
        tauBoiling,
        sDB,
        rhog,
        Up,
        Tg,
        pg,
        Yfg,
        m()*fuels.Y(X()),
        deltaT
    );


    // set the end-time for the track
    scalar tEnd = (1.0 - stepFraction())*deltaT;

    // Set the maximum time step for this parcel

    // FPK changes: avoid temperature-out-of-range errors
    // in spray tracking.  HJ, 13/Oct/2007
    // tauEvaporation no longer multiplied by 1e20,
    // to account for the evaporation timescale
    // FPK, 13/Oct/2007
    scalar dtMax = min
    (
        tEnd,
        min
        (
            tauMomentum,
            min
            (
                mag(min(tauEvaporation)),
                min
                (
                    mag(tauHeatTransfer),
                    mag(min(tauBoiling))
                )
            )
        )
    )/sDB.subCycles();

    // prevent the number of subcycles from being too many
    // (10 000 seems high enough)
    dtMax = max(dtMax, 1.0e-4*tEnd);

    bool switchProcessor = false;
    vector planeNormal = vector::zero;
    if (sDB.twoD())
    {
        planeNormal = n() ^ sDB.axisOfSymmetry();
        planeNormal /= mag(planeNormal);
    }

    // move the parcel until there is no 'timeLeft'
    while (keepParcel && tEnd > SMALL && !switchProcessor)
    {
        // set the lagrangian time-step
        scalar dt = min(dtMax, tEnd);

        // remember which cell the parcel is in
        // since this will change if a face is hit
        label celli = cell();
        scalar p = sDB.p()[celli];

        // track parcel to face, or end of trajectory
        if (keepParcel)
        {
            // Track and adjust the time step if the trajectory
            // is not completed
            dt *= trackToFace(position() + dt*U_, sDB);

            // Decrement the end-time acording to how much time the track took
            tEnd -= dt;

            // Set the current time-step fraction.
            stepFraction() = 1.0 - tEnd/deltaT;

            if (onBoundary()) // hit face
            {
#               include "boundaryTreatment.H"
            }
        }

        if (keepParcel && sDB.twoD())
        {
            scalar z = position() & sDB.axisOfSymmetry();
            vector r = position() - z*sDB.axisOfSymmetry();

            if (mag(r) > SMALL)
            {
                correctNormal(sDB.axisOfSymmetry());
            }
        }

        // **** calculate the lagrangian source terms ****
        // First we get the 'old' properties.
        // and then 'update' them to get the 'new'
        // properties.
        // The difference is then added to the source terms.

        scalar oRho = fuels.rho(p, T(), X());
        scalarField oMass(Nf, 0.0);
        scalar oHg = 0.0;
        scalar oTotMass = m();
        scalarField oYf(fuels.Y(X()));

        forAll(oMass, i)
        {
            oMass[i] = m()*oYf[i];
            label j = sDB.liquidToGasIndex()[i];
            oHg += oYf[i]*sDB.gasProperties()[j].Hs(T());
        }

        vector oMom = m()*U();
        scalar oHv = fuels.hl(p, T(), X());
        scalar oH = oHg - oHv;
        scalar oPE = (p - fuels.pv(p, T(), X()))/oRho;

        // update the parcel properties (U, T, D)
        updateParcelProperties
        (
            dt,
            sDB,
            celli,
            face()
        );

        scalar nRho = fuels.rho(p, T(), X());
        scalar nHg = 0.0;
        scalarField nMass(Nf, 0.0);
        scalarField nYf(fuels.Y(X()));

        forAll(nMass, i)
        {
            nMass[i] = m()*nYf[i];
            label j = sDB.liquidToGasIndex()[i];
            nHg += nYf[i]*sDB.gasProperties()[j].Hs(T());
        }