<commit_before>/*===- ShieldedCoulombForce.cpp - libSimulation -===============================
*
*                                  DEMON
*
* This file is distributed under the BSD Open Source License. See LICENSE.TXT
* for details.
*
*===-----------------------------------------------------------------------===*/

#include "ShieldedCoulombForce.h"
#include <cmath>

const double ShieldedCoulombForce::coulomb = 1.0/(4.0*M_PI*8.85E-12);

ShieldedCoulombForce::ShieldedCoulombForce(Cloud * const myCloud, const double shieldingConstant)
: Force(myCloud), shielding(shieldingConstant) {}

void ShieldedCoulombForce::force1(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx1_pd(currentParticle);
		const __m128d vy1 = cloud->gety1_pd(currentParticle);
		const __m128d vq1 = cloud->getq1_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);

		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq1_pd(i), vx1 - cloud->getx1_pd(i), vy1 - cloud->gety1_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq1r_pd(i), vx1 - cloud->getx1r_pd(i), vy1 - cloud->gety1r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force2(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx2_pd(currentParticle);
		const __m128d vy1 = cloud->gety2_pd(currentParticle);
		const __m128d vq1 = cloud->getq2_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq2_pd(i), vx1 - cloud->getx2_pd(i), vy1 - cloud->gety2_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq2r_pd(i), vx1 - cloud->getx2r_pd(i), vy1 - cloud->gety2r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force3(const double currentTime)
{
    for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx3_pd(currentParticle);
		const __m128d vy1 = cloud->gety3_pd(currentParticle);
		const __m128d vq1 = cloud->getq3_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq3_pd(i), vx1 - cloud->getx3_pd(i), vy1 - cloud->gety3_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq3r_pd(i), vx1 - cloud->getx3r_pd(i), vy1 - cloud->gety3r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force4(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx4_pd(currentParticle);
		const __m128d vy1 = cloud->gety4_pd(currentParticle);
		const __m128d vq1 = cloud->getq4_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq4_pd(i), vx1 - cloud->getx4_pd(i), vy1 - cloud->gety4_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq4r_pd(i), vx1 - cloud->getx4r_pd(i), vy1 - cloud->gety4r_pd(i));
		}
	}
}

inline void ShieldedCoulombForce::force(const cloud_index currentParticle, const cloud_index iParticle,
                                        const double currentCharge, const double iCharge,
                                        const double displacementX, const double displacementY)
{
	// Calculate displacement between particles.
	const double displacement = sqrt(displacementX*displacementX + displacementY*displacementY);
	const double valExp = displacement*shielding;

	if (valExp < 10.0) // restrict to 10*(ion debye length)
	{
		// calculate phi
		const double coeffient = coulomb/(displacement*exp(valExp));
		cloud->phi[currentParticle] += coeffient*iCharge;
		cloud->phi[iParticle] += coeffient*currentCharge;

		// calculate force
		const double forceC = currentCharge*iCharge*coeffient*(1.0 + valExp)/(displacement*displacement);
		cloud->forceX[currentParticle] += forceC*displacementX;
		cloud->forceY[currentParticle] += forceC*displacementY;

		// equal and opposite force:
		cloud->forceX[iParticle] -= forceC*displacementX;
		cloud->forceY[iParticle] -= forceC*displacementY;
	}
}

inline void ShieldedCoulombForce::force(const cloud_index currentParticle, const cloud_index iParticle,
                                        const __m128d currentCharge, const __m128d iCharge,
                                        const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	__m128d expv = _mm_set_pd(boolH ? exp(-valExpH) : 0.0, // _mm_set_pd is backwards
							  boolL ? exp(-valExpL) : 0.0);

	// calculate phi
	const __m128d coeffient = _mm_set1_pd(coulomb)/displacement*expv;
	double *pPh = cloud->phi + currentParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*iCharge);
	pPh = cloud->phi + iParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*currentCharge);

	// calculate force
	const __m128d forceC = currentCharge*iCharge*coeffient*(_mm_set1_pd(1.0) + valExp)/(displacement*displacement);

	const __m128d forcevX = forceC*displacementX;
	const __m128d forcevY = forceC*displacementY;

	double *pFx = cloud->forceX + currentParticle;
	double *pFy = cloud->forceY + currentParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	// equal and opposite force:
	pFx = cloud->forceX + iParticle;
	pFy = cloud->forceY + iParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) - forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) - forcevY);
}

inline void ShieldedCoulombForce::forcer(const cloud_index currentParticle, const cloud_index iParticle,
                                         const __m128d currentCharge, const __m128d iCharge,
                                         const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	__m128d expv = _mm_set_pd(boolH ? exp(-valExpH) : 0.0, // _mm_set_pd is backwards
							  boolL ? exp(-valExpL) : 0.0);

	// calculate phi
	const __m128d coeffient = _mm_set1_pd(coulomb)/displacement*expv;
	double *pPh = cloud->phi + currentParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*iCharge);
	pPh = cloud->phi + iParticle;
	_mm_storer_pd(pPh, _mm_loadr_pd(pPh) + coeffient*currentCharge);

	// calculate force
	const __m128d forceC = currentCharge*iCharge*coeffient*(_mm_set1_pd(1.0) + valExp)/(displacement*displacement);

	const __m128d forcevX = forceC*displacementX;
	const __m128d forcevY = forceC*displacementY;

	double *pFx = cloud->forceX + currentParticle;
	double *pFy = cloud->forceY + currentParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	// equal and opposite force:
	pFx = cloud->forceX + iParticle;
	pFy = cloud->forceY + iParticle;
	_mm_storer_pd(pFx, _mm_loadr_pd(pFx) - forcevX);
	_mm_storer_pd(pFy, _mm_loadr_pd(pFy) - forcevY);
}

void ShieldedCoulombForce::writeForce(fitsfile * const file, int * const error) const
{
	// move to primary HDU:
	if (!*error)
		// file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	// add flag indicating that the drag force is used:
	if (!*error)
	{
		long forceFlags = 0;
		fits_read_key_lng(file, const_cast<char *> ("FORCES"), &forceFlags, NULL, error);

		// add ShieldedCoulombForce bit:
		forceFlags |= ShieldedCoulombForceFlag; // compound bitwise OR

		if (*error == KEY_NO_EXIST || *error == VALUE_UNDEFINED)
			*error = 0; // clear above error.

		// add or update keyword.
		if (!*error)
			fits_update_key(file, TLONG, const_cast<char *> ("FORCES"), &forceFlags, const_cast<char *> ("Force configuration."), error);
	}

	if (!*error)
		// file, key name, value, precision (scientific format), comment
		fits_write_key_dbl(file, const_cast<char *> ("shieldingConstant"), shielding, 6, const_cast<char *> ("[m^-1] (ShieldedCoulombForce)"), error);
}

void ShieldedCoulombForce::readForce(fitsfile * const file, int * const error)
{
	// move to primary HDU:
	if (!*error)
		// file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	if (!*error)
		// file, key name, value, don't read comment, error
		fits_read_key_dbl(file, const_cast<char *> ("shieldingConstant"), &shielding, NULL, error);
}
<commit_msg>Change permittivity of free space to match value in NRL plasma formulary.<commit_after>/*===- ShieldedCoulombForce.cpp - libSimulation -===============================
*
*                                  DEMON
*
* This file is distributed under the BSD Open Source License. See LICENSE.TXT
* for details.
*
*===-----------------------------------------------------------------------===*/

#include "ShieldedCoulombForce.h"
#include <cmath>

const double ShieldedCoulombForce::coulomb = 1.0/(4.0*M_PI*8.8542E-12);

ShieldedCoulombForce::ShieldedCoulombForce(Cloud * const myCloud, const double shieldingConstant)
: Force(myCloud), shielding(shieldingConstant) {}

void ShieldedCoulombForce::force1(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx1_pd(currentParticle);
		const __m128d vy1 = cloud->gety1_pd(currentParticle);
		const __m128d vq1 = cloud->getq1_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);

		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq1_pd(i), vx1 - cloud->getx1_pd(i), vy1 - cloud->gety1_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq1r_pd(i), vx1 - cloud->getx1r_pd(i), vy1 - cloud->gety1r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force2(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx2_pd(currentParticle);
		const __m128d vy1 = cloud->gety2_pd(currentParticle);
		const __m128d vq1 = cloud->getq2_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq2_pd(i), vx1 - cloud->getx2_pd(i), vy1 - cloud->gety2_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq2r_pd(i), vx1 - cloud->getx2r_pd(i), vy1 - cloud->gety2r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force3(const double currentTime)
{
    for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx3_pd(currentParticle);
		const __m128d vy1 = cloud->gety3_pd(currentParticle);
		const __m128d vq1 = cloud->getq3_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq3_pd(i), vx1 - cloud->getx3_pd(i), vy1 - cloud->gety3_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq3r_pd(i), vx1 - cloud->getx3r_pd(i), vy1 - cloud->gety3r_pd(i));
		}
	}
}

void ShieldedCoulombForce::force4(const double currentTime)
{
	for (cloud_index currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = cloud->getx4_pd(currentParticle);
		const __m128d vy1 = cloud->gety4_pd(currentParticle);
		const __m128d vq1 = cloud->getq4_pd(currentParticle);
		double x1, x2, y1, y2, q1, q2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);
		_mm_storel_pd(&q1, vq1);
		_mm_storeh_pd(&q2, vq1);

		force(currentParticle, currentParticle + 1, q1, q2, x1 - x2, y1 - y2);
		for (cloud_index i = currentParticle + 2; i < numParticles; i += 2)
		{
			force(currentParticle, i, vq1, cloud->getq4_pd(i), vx1 - cloud->getx4_pd(i), vy1 - cloud->gety4_pd(i));
			forcer(currentParticle, i, vq1, cloud->getq4r_pd(i), vx1 - cloud->getx4r_pd(i), vy1 - cloud->gety4r_pd(i));
		}
	}
}

inline void ShieldedCoulombForce::force(const cloud_index currentParticle, const cloud_index iParticle,
                                        const double currentCharge, const double iCharge,
                                        const double displacementX, const double displacementY)
{
	// Calculate displacement between particles.
	const double displacement = sqrt(displacementX*displacementX + displacementY*displacementY);
	const double valExp = displacement*shielding;

	if (valExp < 10.0) // restrict to 10*(ion debye length)
	{
		// calculate phi
		const double coeffient = coulomb/(displacement*exp(valExp));
		cloud->phi[currentParticle] += coeffient*iCharge;
		cloud->phi[iParticle] += coeffient*currentCharge;

		// calculate force
		const double forceC = currentCharge*iCharge*coeffient*(1.0 + valExp)/(displacement*displacement);
		cloud->forceX[currentParticle] += forceC*displacementX;
		cloud->forceY[currentParticle] += forceC*displacementY;

		// equal and opposite force:
		cloud->forceX[iParticle] -= forceC*displacementX;
		cloud->forceY[iParticle] -= forceC*displacementY;
	}
}

inline void ShieldedCoulombForce::force(const cloud_index currentParticle, const cloud_index iParticle,
                                        const __m128d currentCharge, const __m128d iCharge,
                                        const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	__m128d expv = _mm_set_pd(boolH ? exp(-valExpH) : 0.0, // _mm_set_pd is backwards
							  boolL ? exp(-valExpL) : 0.0);

	// calculate phi
	const __m128d coeffient = _mm_set1_pd(coulomb)/displacement*expv;
	double *pPh = cloud->phi + currentParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*iCharge);
	pPh = cloud->phi + iParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*currentCharge);

	// calculate force
	const __m128d forceC = currentCharge*iCharge*coeffient*(_mm_set1_pd(1.0) + valExp)/(displacement*displacement);

	const __m128d forcevX = forceC*displacementX;
	const __m128d forcevY = forceC*displacementY;

	double *pFx = cloud->forceX + currentParticle;
	double *pFy = cloud->forceY + currentParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	// equal and opposite force:
	pFx = cloud->forceX + iParticle;
	pFy = cloud->forceY + iParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) - forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) - forcevY);
}

inline void ShieldedCoulombForce::forcer(const cloud_index currentParticle, const cloud_index iParticle,
                                         const __m128d currentCharge, const __m128d iCharge,
                                         const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	__m128d expv = _mm_set_pd(boolH ? exp(-valExpH) : 0.0, // _mm_set_pd is backwards
							  boolL ? exp(-valExpL) : 0.0);

	// calculate phi
	const __m128d coeffient = _mm_set1_pd(coulomb)/displacement*expv;
	double *pPh = cloud->phi + currentParticle;
	_mm_store_pd(pPh, _mm_load_pd(pPh) + coeffient*iCharge);
	pPh = cloud->phi + iParticle;
	_mm_storer_pd(pPh, _mm_loadr_pd(pPh) + coeffient*currentCharge);

	// calculate force
	const __m128d forceC = currentCharge*iCharge*coeffient*(_mm_set1_pd(1.0) + valExp)/(displacement*displacement);

	const __m128d forcevX = forceC*displacementX;
	const __m128d forcevY = forceC*displacementY;

	double *pFx = cloud->forceX + currentParticle;
	double *pFy = cloud->forceY + currentParticle;
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	// equal and opposite force:
	pFx = cloud->forceX + iParticle;
	pFy = cloud->forceY + iParticle;
	_mm_storer_pd(pFx, _mm_loadr_pd(pFx) - forcevX);
	_mm_storer_pd(pFy, _mm_loadr_pd(pFy) - forcevY);
}

void ShieldedCoulombForce::writeForce(fitsfile * const file, int * const error) const
{
	// move to primary HDU:
	if (!*error)
		// file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	// add flag indicating that the drag force is used:
	if (!*error)
	{
		long forceFlags = 0;
		fits_read_key_lng(file, const_cast<char *> ("FORCES"), &forceFlags, NULL, error);

		// add ShieldedCoulombForce bit:
		forceFlags |= ShieldedCoulombForceFlag; // compound bitwise OR

		if (*error == KEY_NO_EXIST || *error == VALUE_UNDEFINED)
			*error = 0; // clear above error.

		// add or update keyword.
		if (!*error)
			fits_update_key(file, TLONG, const_cast<char *> ("FORCES"), &forceFlags, const_cast<char *> ("Force configuration."), error);
	}

	if (!*error)
		// file, key name, value, precision (scientific format), comment
		fits_write_key_dbl(file, const_cast<char *> ("shieldingConstant"), shielding, 6, const_cast<char *> ("[m^-1] (ShieldedCoulombForce)"), error);
}

void ShieldedCoulombForce::readForce(fitsfile * const file, int * const error)
{
	// move to primary HDU:
	if (!*error)
		// file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	if (!*error)
		// file, key name, value, don't read comment, error
		fits_read_key_dbl(file, const_cast<char *> ("shieldingConstant"), &shielding, NULL, error);
}
<|endoftext|>


<commit_before>//
//  CPullingSwing.cpp
//  SwingGame
//
//  Created by Tim Brier on 24/02/2015.
//  Copyright (c) 2015 tbrier. All rights reserved.
//

// =============================================================================
// Include files
// -----------------------------------------------------------------------------
#include "CPullingSwing.hpp"
#include "CPlayer.hpp"

// =============================================================================
// Static members
// -----------------------------------------------------------------------------
float CPullingSwing::smPullSpeedIncrement = 350.0f;
float CPullingSwing::smPullSpeedMax = 500.0f;
float CPullingSwing::smDetachLength = CSwing::smMinLength;

// =============================================================================
// CPullingSwing constructor/destructor
// -----------------------------------------------------------------------------
CPullingSwing::CPullingSwing(CPlayer *theBob, CLevel *theParentLevel)
:   CSwing(theBob, theParentLevel)
{
    // Make it blue
    mColour = CColour::Blue;
}

CPullingSwing::~CPullingSwing()
{

}

// =============================================================================
// CPullingSwing::Update
// -----------------------------------------------------------------------------
void CPullingSwing::Update(CTime elapsedTime)
{
    if (mAttached)
    {
        // Update the length since the player will be closer now
        mLength = GetDistanceToBob();

        // Detach the player if they are close enough
        if (mLength <= smDetachLength)
        {
            Detach();
        }
        else
        {
            // Accelerate the player towards the origin
            CVector2f v = mBob->GetVelocity();
            CVector2f bobToOrigin = mOrigin - mBob->GetPosition();
            bobToOrigin.Normalise();
            float timedInc = smPullSpeedIncrement * elapsedTime.asSeconds();
            CVector2f newV = v + (bobToOrigin * timedInc);

            // Clamp the new velocity
            if (newV.GetMagnitude() > smPullSpeedMax)
            {
                newV = bobToOrigin * smPullSpeedMax;
            }

            mBob->SetVelocity(newV);
        }
    }
}

// =============================================================================
// CPullingSwing::AttenuateGravity
// -----------------------------------------------------------------------------
CVector2f CPullingSwing::AttenuateGravity(CVector2f gravity)
{
    // Have no gravity when on this swing
    if (mAttached)
    {
        gravity = CVector2f(0.0f, 0.0f);
    }

    return gravity;
}

// =============================================================================
// CPullingSwing::RespondToAttach
// -----------------------------------------------------------------------------
void CPullingSwing::RespondToAttach()
{
    // Throw away all player velocity, we'll give them a vel towards the origin
    // in update
    mBob->SetVelocity(CVector2f(0.0f, 0.0f));
}<commit_msg>Make sure the players velocity is always towards the origin when on the pulling swing, even after they have collided with something<commit_after>//
//  CPullingSwing.cpp
//  SwingGame
//
//  Created by Tim Brier on 24/02/2015.
//  Copyright (c) 2015 tbrier. All rights reserved.
//

// =============================================================================
// Include files
// -----------------------------------------------------------------------------
#include "CPullingSwing.hpp"
#include "CPlayer.hpp"

// =============================================================================
// Static members
// -----------------------------------------------------------------------------
float CPullingSwing::smPullSpeedIncrement = 350.0f;
float CPullingSwing::smPullSpeedMax = 500.0f;
float CPullingSwing::smDetachLength = CSwing::smMinLength;

// =============================================================================
// CPullingSwing constructor/destructor
// -----------------------------------------------------------------------------
CPullingSwing::CPullingSwing(CPlayer *theBob, CLevel *theParentLevel)
:   CSwing(theBob, theParentLevel)
{
    // Make it blue
    mColour = CColour::Blue;
}

CPullingSwing::~CPullingSwing()
{

}

// =============================================================================
// CPullingSwing::Update
// -----------------------------------------------------------------------------
void CPullingSwing::Update(CTime elapsedTime)
{
    if (mAttached)
    {
        // Update the length since the player will be closer now
        mLength = GetDistanceToBob();

        // Detach the player if they are close enough
        if (mLength <= smDetachLength)
        {
            Detach();
        }
        else
        {
            // Make sure the players velocity is towards the origin
            CVector2f v = mBob->GetVelocity();
            CVector2f bobToOrigin = mOrigin - mBob->GetPosition();
            bobToOrigin.Normalise();
            v = v.GetComponentInDirection(bobToOrigin);

            // Accelerate the player towards the origin
            float timedInc = smPullSpeedIncrement * elapsedTime.asSeconds();
            CVector2f newV = v + (bobToOrigin * timedInc);

            // Clamp the new velocity
            if (newV.GetMagnitude() > smPullSpeedMax)
            {
                newV = bobToOrigin * smPullSpeedMax;
            }

            mBob->SetVelocity(newV);
        }
    }
}

// =============================================================================
// CPullingSwing::AttenuateGravity
// -----------------------------------------------------------------------------
CVector2f CPullingSwing::AttenuateGravity(CVector2f gravity)
{
    // Have no gravity when on this swing
    if (mAttached)
    {
        gravity = CVector2f(0.0f, 0.0f);
    }

    return gravity;
}

// =============================================================================
// CPullingSwing::RespondToAttach
// -----------------------------------------------------------------------------
void CPullingSwing::RespondToAttach()
{
    // Throw away all player velocity, we'll give them a vel towards the origin
    // in update
    mBob->SetVelocity(CVector2f(0.0f, 0.0f));
}<|endoftext|>


<commit_before>//Source: The LLVM Compiler Infrastructure - lib/addsf3.c
//Modified to truncate result of addition

#include <limits.h>
#include <boost/cstdint.hpp>
#ifdef _WIN32
#include <Windows.h>
#endif
#include "FpMulTruncate.h"

typedef uint32 rep_t;
typedef int32 srep_t;
typedef float fp_t;
#define REP_C UINT32_C
#define significandBits 23

#define typeWidth       (sizeof(rep_t)*CHAR_BIT)
#define exponentBits    (typeWidth - significandBits - 1)
#define maxExponent     ((1 << exponentBits) - 1)
#define exponentBias    (maxExponent >> 1)

#define implicitBit     (REP_C(1) << significandBits)
#define significandMask (implicitBit - 1U)
#define signBit         (REP_C(1) << (significandBits + exponentBits))
#define absMask         (signBit - 1U)
#define exponentMask    (absMask ^ significandMask)
#define oneRep          ((rep_t)exponentBias << significandBits)
#define infRep          exponentMask
#define quietBit        (implicitBit >> 1)
#define qnanRep         (exponentMask | quietBit)

static inline int rep_clz(rep_t a) {
#ifdef _WIN32
   DWORD r = 0;
   _BitScanForward(&r, a);
   return 32 - r;
#else
	return __builtin_clz(a);
#endif
}

uint32 FpAddTruncate(uint32 a, uint32 b)
{
    const rep_t aAbs = a & absMask;
    const rep_t bAbs = b & absMask;

    // Detect if a or b is zero, infinity, or NaN.
    if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {

        // NaN + anything = qNaN
        if (aAbs > infRep) return (a | quietBit);
        // anything + NaN = qNaN
        if (bAbs > infRep) return (b | quietBit);

        if (aAbs == infRep) {
            // +/-infinity + -/+infinity = qNaN
            if ((a ^ b) == signBit) return qnanRep;
            // +/-infinity + anything remaining = +/- infinity
            else return a;
        }

        // anything remaining + +/-infinity = +/-infinity
        if (bAbs == infRep) return b;

        // zero + anything = anything
        if (!aAbs) {
            // but we need to get the sign right for zero + zero
            if (!bAbs) return (a & b);
            else return b;
        }

        // anything + zero = anything
        if (!bAbs) return a;
    }

    // Swap a and b if necessary so that a has the larger absolute value.
    if (bAbs > aAbs) {
        const uint32 temp = a;
        a = b;
        b = temp;
    }

    // Extract the exponent and significand from the (possibly swapped) a and b.
    int aExponent = a >> significandBits & maxExponent;
    int bExponent = b >> significandBits & maxExponent;
    rep_t aSignificand = a & significandMask;
    rep_t bSignificand = b & significandMask;

    // Normalize any denormals, and adjust the exponent accordingly.
    //if (aExponent == 0) aExponent = normalize(&aSignificand);
    //if (bExponent == 0) bExponent = normalize(&bSignificand);

    // The sign of the result is the sign of the larger operand, a.  If they
    // have opposite signs, we are performing a subtraction; otherwise addition.
    const rep_t resultSign = a & signBit;
    const bool subtraction = (a ^ b) & signBit;

    // Shift the significands to give us round, guard and sticky, and or in the
    // implicit significand bit.  (If we fell through from the denormal path it
    // was already set by normalize( ), but setting it twice won't hurt
    // anything.)
    aSignificand = (aSignificand | implicitBit) << 3;
    bSignificand = (bSignificand | implicitBit) << 3;

    // Shift the significand of b by the difference in exponents, with a sticky
    // bottom bit to get rounding correct.
    const unsigned int align = aExponent - bExponent;
    if (align) {
        if (align < typeWidth) {
            //const bool sticky = bSignificand << (typeWidth - align);
            bSignificand = bSignificand >> align;
        } else {
            bSignificand = 0; // sticky; b is known to be non-zero.
        }
    }

    if (subtraction) {
        aSignificand -= bSignificand;

        // If a == -b, return +zero.
        if (aSignificand == 0) return 0;

        // If partial cancellation occured, we need to left-shift the result
        // and adjust the exponent:
        if (aSignificand < implicitBit << 3) {
            const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
            aSignificand <<= shift;
            aExponent -= shift;
        }
    }

    else /* addition */ {
        aSignificand += bSignificand;

        // If the addition carried up, we need to right-shift the result and
        // adjust the exponent:
        if (aSignificand & implicitBit << 4) {
            const bool sticky = aSignificand & 1;
            aSignificand = aSignificand >> 1 | sticky;
            aExponent += 1;
        }
    }

    // If we have overflowed the type, return +/- infinity:
    if (aExponent >= maxExponent) return infRep | resultSign;

    if (aExponent <= 0) {
        // Result is denormal before rounding; the exponent is zero and we
        // need to shift the significand.
        const int shift = 1 - aExponent;
        const bool sticky = aSignificand << (typeWidth - shift);
        aSignificand = aSignificand >> shift | sticky;
        aExponent = 0;
    }

    // Low three bits are round, guard, and sticky.
    const int roundGuardSticky = aSignificand & 0x7;

    // Shift the significand into place, and mask off the implicit bit.
    rep_t result = aSignificand >> 3 & significandMask;

    // Insert the exponent and sign.
    result |= (rep_t)aExponent << significandBits;
    result |= resultSign;

    return result;
}
<commit_msg>Fixed bug in FpAddTruncate.<commit_after>//Source: The LLVM Compiler Infrastructure - lib/addsf3.c
//Modified to truncate result of addition

#include <limits.h>
#include <boost/cstdint.hpp>
#ifdef _WIN32
#include <Windows.h>
#endif
#include "FpAddTruncate.h"

typedef uint32 rep_t;
typedef int32 srep_t;
typedef float fp_t;
#define REP_C UINT32_C
#define significandBits 23

#define typeWidth       (sizeof(rep_t)*CHAR_BIT)
#define exponentBits    (typeWidth - significandBits - 1)
#define maxExponent     ((1 << exponentBits) - 1)
#define exponentBias    (maxExponent >> 1)

#define implicitBit     (REP_C(1) << significandBits)
#define significandMask (implicitBit - 1U)
#define signBit         (REP_C(1) << (significandBits + exponentBits))
#define absMask         (signBit - 1U)
#define exponentMask    (absMask ^ significandMask)
#define oneRep          ((rep_t)exponentBias << significandBits)
#define infRep          exponentMask
#define quietBit        (implicitBit >> 1)
#define qnanRep         (exponentMask | quietBit)

static inline int rep_clz(rep_t a) {
#ifdef _WIN32
   DWORD r = 0;
   _BitScanReverse(&r, a);
   return (31 - r);
#else
	return __builtin_clz(a);
#endif
}

uint32 FpAddTruncate(uint32 a, uint32 b)
{
    const rep_t aAbs = a & absMask;
    const rep_t bAbs = b & absMask;

    // Detect if a or b is zero, infinity, or NaN.
    if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {

        // NaN + anything = qNaN
        if (aAbs > infRep) return (a | quietBit);
        // anything + NaN = qNaN
        if (bAbs > infRep) return (b | quietBit);

        if (aAbs == infRep) {
            // +/-infinity + -/+infinity = qNaN
            if ((a ^ b) == signBit) return qnanRep;
            // +/-infinity + anything remaining = +/- infinity
            else return a;
        }

        // anything remaining + +/-infinity = +/-infinity
        if (bAbs == infRep) return b;

        // zero + anything = anything
        if (!aAbs) {
            // but we need to get the sign right for zero + zero
            if (!bAbs) return (a & b);
            else return b;
        }

        // anything + zero = anything
        if (!bAbs) return a;
    }

    // Swap a and b if necessary so that a has the larger absolute value.
    if (bAbs > aAbs) {
        const uint32 temp = a;
        a = b;
        b = temp;
    }

    // Extract the exponent and significand from the (possibly swapped) a and b.
    int aExponent = a >> significandBits & maxExponent;
    int bExponent = b >> significandBits & maxExponent;
    rep_t aSignificand = a & significandMask;
    rep_t bSignificand = b & significandMask;

    // Normalize any denormals, and adjust the exponent accordingly.
    //if (aExponent == 0) aExponent = normalize(&aSignificand);
    //if (bExponent == 0) bExponent = normalize(&bSignificand);

    // The sign of the result is the sign of the larger operand, a.  If they
    // have opposite signs, we are performing a subtraction; otherwise addition.
    const rep_t resultSign = a & signBit;
    const bool subtraction = (a ^ b) & signBit;

    // Shift the significands to give us round, guard and sticky, and or in the
    // implicit significand bit.  (If we fell through from the denormal path it
    // was already set by normalize( ), but setting it twice won't hurt
    // anything.)
    aSignificand = (aSignificand | implicitBit) << 3;
    bSignificand = (bSignificand | implicitBit) << 3;

    // Shift the significand of b by the difference in exponents, with a sticky
    // bottom bit to get rounding correct.
    const unsigned int align = aExponent - bExponent;
    if (align) {
        if (align < typeWidth) {
            //const bool sticky = bSignificand << (typeWidth - align);
            bSignificand = bSignificand >> align;
        } else {
            bSignificand = 0; // sticky; b is known to be non-zero.
        }
    }

    if (subtraction) {
        aSignificand -= bSignificand;

        // If a == -b, return +zero.
        if (aSignificand == 0) return 0;

        // If partial cancellation occured, we need to left-shift the result
        // and adjust the exponent:
        if (aSignificand < implicitBit << 3) {
            const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
            aSignificand <<= shift;
            aExponent -= shift;
        }
    }

    else /* addition */ {
        aSignificand += bSignificand;

        // If the addition carried up, we need to right-shift the result and
        // adjust the exponent:
        if (aSignificand & implicitBit << 4) {
            const bool sticky = aSignificand & 1;
            aSignificand = aSignificand >> 1 | sticky;
            aExponent += 1;
        }
    }

    // If we have overflowed the type, return +/- infinity:
    if (aExponent >= maxExponent) return infRep | resultSign;

    if (aExponent <= 0) {
        // Result is denormal before rounding; the exponent is zero and we
        // need to shift the significand.
        const int shift = 1 - aExponent;
        const bool sticky = aSignificand << (typeWidth - shift);
        aSignificand = aSignificand >> shift | sticky;
        aExponent = 0;
    }

    // Low three bits are round, guard, and sticky.
    const int roundGuardSticky = aSignificand & 0x7;

    // Shift the significand into place, and mask off the implicit bit.
    rep_t result = aSignificand >> 3 & significandMask;

    // Insert the exponent and sign.
    result |= (rep_t)aExponent << significandBits;
    result |= resultSign;

    return result;
}
<|endoftext|>


<commit_before>// Copyright (c) Microsoft Corporation
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pch.h"
#include "../HTTP/httpcall.h"
#include "buildver.h"
#include "global.h"
#include "../Mock/lhc_mock.h"

#if !HC_NOWEBSOCKETS
#include "../WebSocket/hcwebsocket.h"
#endif

using namespace xbox::httpclient;

NAMESPACE_XBOX_HTTP_CLIENT_BEGIN

HRESULT http_singleton::singleton_access(
    _In_ singleton_access_mode mode,
    _In_opt_ HCInitArgs* createArgs,
    _Out_ std::shared_ptr<http_singleton>& singleton
) noexcept
{
    static std::mutex s_mutex;
    static std::shared_ptr<http_singleton> s_singleton{ nullptr };
    static uint8_t s_useCount{ 0 };

    std::lock_guard<std::mutex> lock{ s_mutex };
    switch (mode)
    {
    case singleton_access_mode::create:
    {
        // Create the singleton only for the first client calling create
        if (!s_useCount)
        {
            PerformEnv performEnv;
            RETURN_IF_FAILED(Internal_InitializeHttpPlatform(createArgs, performEnv));

            auto rawSingleton = new (http_memory::mem_alloc(sizeof(http_singleton))) http_singleton(
                GetUserHttpPerformHandler(),
#if !HC_NOWEBSOCKETS
                GetUserWebSocketPerformHandlers(),
#endif
                std::move(performEnv)
            );

            s_singleton = std::shared_ptr<http_singleton>(rawSingleton, http_alloc_deleter<http_singleton>());
            s_singleton->m_self = s_singleton;
        }

        ++s_useCount;
        singleton = s_singleton;

        return S_OK;
    }
    case singleton_access_mode::get:
    {
        assert(!createArgs);
        singleton = s_singleton;
        return S_OK;
    }
    case singleton_access_mode::cleanup:
    {
        assert(!createArgs);

        if (!s_singleton)
        {
            assert(s_useCount == 0);
            return E_HC_NOT_INITIALISED;
        }

        --s_useCount;
        singleton = s_singleton;

        if (s_useCount > 0)
        {
            return E_HC_INTERNAL_STILLINUSE;
        }

        s_singleton.reset();
        return S_OK;
    }
    default:
    {
        assert(false);
        return S_OK;
    }
    }
}

std::shared_ptr<http_singleton> http_singleton::get() noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    auto hr = singleton_access(singleton_access_mode::get, nullptr, singleton);

    // get should never fail
    assert(SUCCEEDED(hr));
    UNREFERENCED_PARAMETER(hr);

    return singleton;
}

HRESULT http_singleton::create(
    _In_ HCInitArgs* args
) noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    return singleton_access(singleton_access_mode::create, args, singleton);
}

HRESULT http_singleton::cleanup_async(
    _In_ XAsyncBlock* async
) noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    RETURN_IF_FAILED(singleton_access(singleton_access_mode::cleanup, nullptr, singleton));

    return XAsyncBegin(
        async,
        singleton.get(),
        reinterpret_cast<void*>(cleanup_async),
        __FUNCTION__,
        [](XAsyncOp op, const XAsyncProviderData* data)
    {
        switch (op)
        {
        case XAsyncOp::Begin:
        {
            return XAsyncSchedule(data->async, 0);
        }
        case XAsyncOp::DoWork:
        {
            auto& self{ static_cast<http_singleton*>(data->context)->m_self };

            // Wait for all other references to the singleton to go away
            // Note that the use count check here is only valid because we never create
            // a weak_ptr to the singleton. If we did that could cause the use count
            // to increase even though we are the only strong reference
            if (self.use_count() > 1)
            {
                return XAsyncSchedule(data->async, 10);
            }

            shared_ptr_cache::cleanup(self);

            // self is the only reference at this point, the singleton will be destroyed on this thread.
            self.reset();

            XAsyncComplete(data->async, S_OK, 0);
            return S_OK;
        }
        default:
        {
            return S_OK;
        }
        }
    });
}

http_singleton::http_singleton(
    HttpPerformInfo const& httpPerformInfo,
#if !HC_NOWEBSOCKETS
    WebSocketPerformInfo const& websocketPerformInfo,
#endif
    PerformEnv&& performEnv
) :
    m_httpPerform{ httpPerformInfo },
    m_performEnv{ std::move(performEnv) }
#if !HC_NOWEBSOCKETS
    , m_websocketPerform{ websocketPerformInfo }
#endif
{}

http_singleton::~http_singleton()
{
    for (auto& mockCall : m_mocks)
    {
        HCHttpCallCloseHandle(mockCall);
    }
    m_mocks.clear();
}

std::shared_ptr<http_singleton> get_http_singleton()
{
    return http_singleton::get();
}

void http_singleton::set_retry_state(
    _In_ uint32_t retryAfterCacheId,
    _In_ const http_retry_after_api_state& state)
{
    std::lock_guard<std::recursive_mutex> lock(m_retryAfterCacheLock); // STL is not safe for multithreaded writes
    http_retry_after_api_state oldstate = get_retry_state(retryAfterCacheId);
    if (oldstate.statusCode < 400)
    {
        m_retryAfterCache[retryAfterCacheId] = state;
    }
    else if (oldstate.retryAfterTime <= state.retryAfterTime)
    {
        m_retryAfterCache[retryAfterCacheId] = state;
    }
}

http_retry_after_api_state http_singleton::get_retry_state(_In_ uint32_t retryAfterCacheId)
{
    auto it = m_retryAfterCache.find(retryAfterCacheId); // STL is multithread read safe
    if (it != m_retryAfterCache.end())
    {
        return it->second; // returning a copy of state struct
    }

    return http_retry_after_api_state();
}

void http_singleton::clear_retry_state(_In_ uint32_t retryAfterCacheId)
{
    std::lock_guard<std::recursive_mutex> lock(m_retryAfterCacheLock); // STL is not safe for multithreaded writes
    m_retryAfterCache.erase(retryAfterCacheId);
}

HRESULT http_singleton::set_global_proxy(_In_ const char* proxyUri)
{
#if HC_PLATFORM == HC_PLATFORM_WIN32
    return Internal_SetGlobalProxy(m_performEnv.get(), proxyUri);
#else
    UNREFERENCED_PARAMETER(proxyUri);
    return E_NOTIMPL;
#endif
}

HttpPerformInfo& GetUserHttpPerformHandler() noexcept
{
    static HttpPerformInfo handler(&Internal_HCHttpCallPerformAsync, nullptr);
    return handler;
}

#if !HC_NOWEBSOCKETS
WebSocketPerformInfo& GetUserWebSocketPerformHandlers() noexcept
{
    static WebSocketPerformInfo handlers(
        Internal_HCWebSocketConnectAsync,
        Internal_HCWebSocketSendMessageAsync,
        Internal_HCWebSocketSendBinaryMessageAsync,
        Internal_HCWebSocketDisconnect,
        nullptr
    );
    return handlers;
}
#endif

NAMESPACE_XBOX_HTTP_CLIENT_END
<commit_msg>CleanupAsync needs to return E_PENDING unless its done (#499)<commit_after>// Copyright (c) Microsoft Corporation
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "pch.h"
#include "../HTTP/httpcall.h"
#include "buildver.h"
#include "global.h"
#include "../Mock/lhc_mock.h"

#if !HC_NOWEBSOCKETS
#include "../WebSocket/hcwebsocket.h"
#endif

using namespace xbox::httpclient;

NAMESPACE_XBOX_HTTP_CLIENT_BEGIN

HRESULT http_singleton::singleton_access(
    _In_ singleton_access_mode mode,
    _In_opt_ HCInitArgs* createArgs,
    _Out_ std::shared_ptr<http_singleton>& singleton
) noexcept
{
    static std::mutex s_mutex;
    static std::shared_ptr<http_singleton> s_singleton{ nullptr };
    static uint8_t s_useCount{ 0 };

    std::lock_guard<std::mutex> lock{ s_mutex };
    switch (mode)
    {
    case singleton_access_mode::create:
    {
        // Create the singleton only for the first client calling create
        if (!s_useCount)
        {
            PerformEnv performEnv;
            RETURN_IF_FAILED(Internal_InitializeHttpPlatform(createArgs, performEnv));

            auto rawSingleton = new (http_memory::mem_alloc(sizeof(http_singleton))) http_singleton(
                GetUserHttpPerformHandler(),
#if !HC_NOWEBSOCKETS
                GetUserWebSocketPerformHandlers(),
#endif
                std::move(performEnv)
            );

            s_singleton = std::shared_ptr<http_singleton>(rawSingleton, http_alloc_deleter<http_singleton>());
            s_singleton->m_self = s_singleton;
        }

        ++s_useCount;
        singleton = s_singleton;

        return S_OK;
    }
    case singleton_access_mode::get:
    {
        assert(!createArgs);
        singleton = s_singleton;
        return S_OK;
    }
    case singleton_access_mode::cleanup:
    {
        assert(!createArgs);

        if (!s_singleton)
        {
            assert(s_useCount == 0);
            return E_HC_NOT_INITIALISED;
        }

        --s_useCount;
        singleton = s_singleton;

        if (s_useCount > 0)
        {
            return E_HC_INTERNAL_STILLINUSE;
        }

        s_singleton.reset();
        return S_OK;
    }
    default:
    {
        assert(false);
        return S_OK;
    }
    }
}

std::shared_ptr<http_singleton> http_singleton::get() noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    auto hr = singleton_access(singleton_access_mode::get, nullptr, singleton);

    // get should never fail
    assert(SUCCEEDED(hr));
    UNREFERENCED_PARAMETER(hr);

    return singleton;
}

HRESULT http_singleton::create(
    _In_ HCInitArgs* args
) noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    return singleton_access(singleton_access_mode::create, args, singleton);
}

HRESULT http_singleton::cleanup_async(
    _In_ XAsyncBlock* async
) noexcept
{
    std::shared_ptr<http_singleton> singleton{};
    RETURN_IF_FAILED(singleton_access(singleton_access_mode::cleanup, nullptr, singleton));

    return XAsyncBegin(
        async,
        singleton.get(),
        reinterpret_cast<void*>(cleanup_async),
        __FUNCTION__,
        [](XAsyncOp op, const XAsyncProviderData* data)
    {
        switch (op)
        {
        case XAsyncOp::Begin:
        {
            return XAsyncSchedule(data->async, 0);
        }
        case XAsyncOp::DoWork:
        {
            auto& self{ static_cast<http_singleton*>(data->context)->m_self };

            // Wait for all other references to the singleton to go away
            // Note that the use count check here is only valid because we never create
            // a weak_ptr to the singleton. If we did that could cause the use count
            // to increase even though we are the only strong reference
            if (self.use_count() > 1)
            {
                RETURN_IF_FAILED(XAsyncSchedule(data->async, 10));
                return E_PENDING;
            }

            shared_ptr_cache::cleanup(self);

            // self is the only reference at this point, the singleton will be destroyed on this thread.
            self.reset();

            XAsyncComplete(data->async, S_OK, 0);
            return S_OK;
        }
        default:
        {
            return S_OK;
        }
        }
    });
}

http_singleton::http_singleton(
    HttpPerformInfo const& httpPerformInfo,
#if !HC_NOWEBSOCKETS
    WebSocketPerformInfo const& websocketPerformInfo,
#endif
    PerformEnv&& performEnv
) :
    m_httpPerform{ httpPerformInfo },
    m_performEnv{ std::move(performEnv) }
#if !HC_NOWEBSOCKETS
    , m_websocketPerform{ websocketPerformInfo }
#endif
{}

http_singleton::~http_singleton()
{
    for (auto& mockCall : m_mocks)
    {
        HCHttpCallCloseHandle(mockCall);
    }
    m_mocks.clear();
}

std::shared_ptr<http_singleton> get_http_singleton()
{
    return http_singleton::get();
}

void http_singleton::set_retry_state(
    _In_ uint32_t retryAfterCacheId,
    _In_ const http_retry_after_api_state& state)
{
    std::lock_guard<std::recursive_mutex> lock(m_retryAfterCacheLock); // STL is not safe for multithreaded writes
    http_retry_after_api_state oldstate = get_retry_state(retryAfterCacheId);
    if (oldstate.statusCode < 400)
    {
        m_retryAfterCache[retryAfterCacheId] = state;
    }
    else if (oldstate.retryAfterTime <= state.retryAfterTime)
    {
        m_retryAfterCache[retryAfterCacheId] = state;
    }
}

http_retry_after_api_state http_singleton::get_retry_state(_In_ uint32_t retryAfterCacheId)
{
    auto it = m_retryAfterCache.find(retryAfterCacheId); // STL is multithread read safe
    if (it != m_retryAfterCache.end())
    {
        return it->second; // returning a copy of state struct
    }

    return http_retry_after_api_state();
}

void http_singleton::clear_retry_state(_In_ uint32_t retryAfterCacheId)
{
    std::lock_guard<std::recursive_mutex> lock(m_retryAfterCacheLock); // STL is not safe for multithreaded writes
    m_retryAfterCache.erase(retryAfterCacheId);
}

HRESULT http_singleton::set_global_proxy(_In_ const char* proxyUri)
{
#if HC_PLATFORM == HC_PLATFORM_WIN32
    return Internal_SetGlobalProxy(m_performEnv.get(), proxyUri);
#else
    UNREFERENCED_PARAMETER(proxyUri);
    return E_NOTIMPL;
#endif
}

HttpPerformInfo& GetUserHttpPerformHandler() noexcept
{
    static HttpPerformInfo handler(&Internal_HCHttpCallPerformAsync, nullptr);
    return handler;
}

#if !HC_NOWEBSOCKETS
WebSocketPerformInfo& GetUserWebSocketPerformHandlers() noexcept
{
    static WebSocketPerformInfo handlers(
        Internal_HCWebSocketConnectAsync,
        Internal_HCWebSocketSendMessageAsync,
        Internal_HCWebSocketSendBinaryMessageAsync,
        Internal_HCWebSocketDisconnect,
        nullptr
    );
    return handlers;
}
#endif

NAMESPACE_XBOX_HTTP_CLIENT_END
<|endoftext|>


<commit_before>/*
  * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License").
  * You may not use this file except in compliance with the License.
  * A copy of the License is located at
  *
  *  http://aws.amazon.com/apache2.0
  *
  * or in the "license" file accompanying this file. This file is distributed
  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  * express or implied. See the License for the specific language governing
  * permissions and limitations under the License.
  */

#include <aws/core/http/windows/WinINetSyncHttpClient.h>

#include <aws/core/Http/HttpRequest.h>
#include <aws/core/http/standard/StandardHttpResponse.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/http/windows/WinINetConnectionPoolMgr.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/memory/stl/AWSStreamFwd.h>
#include <aws/core/utils/ratelimiter/RateLimiterInterface.h>

#include <Windows.h>
#include <WinInet.h>
#include <sstream>
#include <iostream>

using namespace Aws::Client;
using namespace Aws::Http;
using namespace Aws::Http::Standard;
using namespace Aws::Utils;
using namespace Aws::Utils::Logging;

static const uint32_t HTTP_REQUEST_WRITE_BUFFER_LENGTH = 8192;

WinINetSyncHttpClient::WinINetSyncHttpClient(const ClientConfiguration& config) :
    Base()
{
    AWS_LOGSTREAM_INFO(GetLogTag(), "Creating http client with user agent " << config.userAgent << " with max connections " <<
         config.maxConnections << ", request timeout " << config.requestTimeoutMs << ",and connect timeout " << config.connectTimeoutMs);

    m_allowRedirects = config.followRedirects;

    DWORD inetFlags = INTERNET_OPEN_TYPE_DIRECT;
    const char* proxyHosts = nullptr;
    Aws::String strProxyHosts;

    bool isUsingProxy = !config.proxyHost.empty();
    //setup initial proxy config.
    if (isUsingProxy)
    {
        const char* const proxySchemeString = Aws::Http::SchemeMapper::ToString(config.proxyScheme);
        AWS_LOGSTREAM_INFO(GetLogTag(), "Http Client is using a proxy. Setting up proxy with settings scheme " << proxySchemeString
            << ", host " << config.proxyHost << ", port " << config.proxyPort << ", username " << config.proxyUserName << ".");

        inetFlags = INTERNET_OPEN_TYPE_PROXY;
        Aws::StringStream ss;
        const char* schemeString = Aws::Http::SchemeMapper::ToString(config.scheme);
        ss << StringUtils::ToUpper(schemeString) << "=" << proxySchemeString << "://" << config.proxyHost << ":" << config.proxyPort;
        strProxyHosts.assign(ss.str());
        proxyHosts = strProxyHosts.c_str();

        AWS_LOGSTREAM_DEBUG(GetLogTag(), "Adding proxy host string to wininet " << proxyHosts);
    }

    SetOpenHandle(InternetOpenA(config.userAgent.c_str(), inetFlags, proxyHosts, nullptr, 0));

    //override offline mode.
    InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_IGNORE_OFFLINE, nullptr, 0);
    //add proxy auth credentials to everything using this handle.
    if (isUsingProxy)
    {
        if (!config.proxyUserName.empty() && !InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_PROXY_USERNAME, (LPVOID)config.proxyUserName.c_str(), (DWORD)config.proxyUserName.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting username for proxy with error code: " << GetLastError());
        if (!config.proxyPassword.empty() && !InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_PROXY_PASSWORD, (LPVOID)config.proxyPassword.c_str(), (DWORD)config.proxyPassword.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting password for proxy with error code: " << GetLastError());
    }

    if (!config.verifySSL)
    {
        AWS_LOGSTREAM_WARN(GetLogTag(), "Turning ssl unknown ca verification off.");
        DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | INTERNET_FLAG_IGNORE_CERT_CN_INVALID;

        if (!InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed to turn ssl cert ca verification off.");
    }

    AWS_LOGSTREAM_DEBUG(GetLogTag(), "API handle " << GetOpenHandle());
    SetConnectionPoolManager(Aws::New<WinINetConnectionPoolMgr>(GetLogTag(),
        GetOpenHandle(), config.maxConnections, config.requestTimeoutMs, config.connectTimeoutMs));
}

WinINetSyncHttpClient::~WinINetSyncHttpClient()
{

}

void* WinINetSyncHttpClient::OpenRequest(const Aws::Http::HttpRequest& request, void* connection, const Aws::StringStream& ss) const
{
    DWORD requestFlags =
        INTERNET_FLAG_NO_AUTH |
        INTERNET_FLAG_RELOAD |
        INTERNET_FLAG_KEEP_CONNECTION |
        (request.GetUri().GetScheme() == Scheme::HTTPS ? INTERNET_FLAG_SECURE : 0) |
        INTERNET_FLAG_NO_CACHE_WRITE |
        (m_allowRedirects ? 0 : INTERNET_FLAG_NO_AUTO_REDIRECT);

    LPCSTR accept[2] = { nullptr, nullptr };

    Aws::String acceptHeader("*/*");

    if (request.HasHeader(Aws::Http::ACCEPT_HEADER))
    {
        acceptHeader = request.GetHeaderValue(Aws::Http::ACCEPT_HEADER).c_str();
    }

    accept[0] = acceptHeader.c_str();

    HINTERNET hHttpRequest = HttpOpenRequestA(connection, HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()),
        ss.str().c_str(), nullptr, nullptr, accept, requestFlags, 0);
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "HttpOpenRequestA returned handle " << hHttpRequest);

    return hHttpRequest;
}

void WinINetSyncHttpClient::DoAddHeaders(void* hHttpRequest, Aws::String& headerStr) const
{
    if (!HttpAddRequestHeadersA(hHttpRequest, headerStr.c_str(), (DWORD)headerStr.length(), HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))
        AWS_LOGSTREAM_ERROR(GetLogTag(), "Failed to add HTTP request headers with error code: " << GetLastError());
}

uint64_t WinINetSyncHttpClient::DoWriteData(void* hHttpRequest, char* streamBuffer, uint64_t bytesRead) const
{
    DWORD bytesWritten = 0;
    if(!InternetWriteFile(hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten))
    {
        return 0;
    }

    return bytesWritten;
}

bool WinINetSyncHttpClient::DoReceiveResponse(void* hHttpRequest) const
{
    return (HttpEndRequest(hHttpRequest, nullptr, 0, 0) != 0);
}

bool WinINetSyncHttpClient::DoQueryHeaders(void* hHttpRequest, std::shared_ptr<StandardHttpResponse>& response, Aws::StringStream& ss, uint64_t& read) const
{

    char dwStatusCode[256];
    DWORD dwSize = sizeof(dwStatusCode);

    HttpQueryInfoA(hHttpRequest, HTTP_QUERY_STATUS_CODE, &dwStatusCode, &dwSize, 0);
    response->SetResponseCode((HttpResponseCode)atoi(dwStatusCode));
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received response code " << dwStatusCode);

    char contentTypeStr[1024];
    dwSize = sizeof(contentTypeStr);
    HttpQueryInfoA(hHttpRequest, HTTP_QUERY_CONTENT_TYPE, &contentTypeStr, &dwSize, 0);
    if (contentTypeStr[0] != NULL)
    {
        response->SetContentType(contentTypeStr);
        AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received content type " << contentTypeStr);
    }

    char headerStr[1024];
    dwSize = sizeof(headerStr);
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received headers:");
    while (HttpQueryInfoA(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, headerStr, &dwSize, (LPDWORD)&read) && dwSize > 0)
    {
        AWS_LOGSTREAM_DEBUG(GetLogTag(), headerStr);
        ss << headerStr;
    }
    return (read != 0);
}

bool WinINetSyncHttpClient::DoSendRequest(void* hHttpRequest) const
{
    return (HttpSendRequestEx(hHttpRequest, NULL, NULL, 0, 0) != 0);
}

bool WinINetSyncHttpClient::DoReadData(void* hHttpRequest, char* body, uint64_t size, uint64_t& read) const
{
    return (InternetReadFile(hHttpRequest, body, (DWORD)size, (LPDWORD)&read) != 0);
}

void* WinINetSyncHttpClient::GetClientModule() const
{
    return GetModuleHandle(TEXT("wininet.dll"));
}
<commit_msg>Removed superfluous c_str()<commit_after>/*
  * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License").
  * You may not use this file except in compliance with the License.
  * A copy of the License is located at
  *
  *  http://aws.amazon.com/apache2.0
  *
  * or in the "license" file accompanying this file. This file is distributed
  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  * express or implied. See the License for the specific language governing
  * permissions and limitations under the License.
  */

#include <aws/core/http/windows/WinINetSyncHttpClient.h>

#include <aws/core/Http/HttpRequest.h>
#include <aws/core/http/standard/StandardHttpResponse.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/http/windows/WinINetConnectionPoolMgr.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/memory/stl/AWSStreamFwd.h>
#include <aws/core/utils/ratelimiter/RateLimiterInterface.h>

#include <Windows.h>
#include <WinInet.h>
#include <sstream>
#include <iostream>

using namespace Aws::Client;
using namespace Aws::Http;
using namespace Aws::Http::Standard;
using namespace Aws::Utils;
using namespace Aws::Utils::Logging;

static const uint32_t HTTP_REQUEST_WRITE_BUFFER_LENGTH = 8192;

WinINetSyncHttpClient::WinINetSyncHttpClient(const ClientConfiguration& config) :
    Base()
{
    AWS_LOGSTREAM_INFO(GetLogTag(), "Creating http client with user agent " << config.userAgent << " with max connections " <<
         config.maxConnections << ", request timeout " << config.requestTimeoutMs << ",and connect timeout " << config.connectTimeoutMs);

    m_allowRedirects = config.followRedirects;

    DWORD inetFlags = INTERNET_OPEN_TYPE_DIRECT;
    const char* proxyHosts = nullptr;
    Aws::String strProxyHosts;

    bool isUsingProxy = !config.proxyHost.empty();
    //setup initial proxy config.
    if (isUsingProxy)
    {
        const char* const proxySchemeString = Aws::Http::SchemeMapper::ToString(config.proxyScheme);
        AWS_LOGSTREAM_INFO(GetLogTag(), "Http Client is using a proxy. Setting up proxy with settings scheme " << proxySchemeString
            << ", host " << config.proxyHost << ", port " << config.proxyPort << ", username " << config.proxyUserName << ".");

        inetFlags = INTERNET_OPEN_TYPE_PROXY;
        Aws::StringStream ss;
        const char* schemeString = Aws::Http::SchemeMapper::ToString(config.scheme);
        ss << StringUtils::ToUpper(schemeString) << "=" << proxySchemeString << "://" << config.proxyHost << ":" << config.proxyPort;
        strProxyHosts.assign(ss.str());
        proxyHosts = strProxyHosts.c_str();

        AWS_LOGSTREAM_DEBUG(GetLogTag(), "Adding proxy host string to wininet " << proxyHosts);
    }

    SetOpenHandle(InternetOpenA(config.userAgent.c_str(), inetFlags, proxyHosts, nullptr, 0));

    //override offline mode.
    InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_IGNORE_OFFLINE, nullptr, 0);
    //add proxy auth credentials to everything using this handle.
    if (isUsingProxy)
    {
        if (!config.proxyUserName.empty() && !InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_PROXY_USERNAME, (LPVOID)config.proxyUserName.c_str(), (DWORD)config.proxyUserName.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting username for proxy with error code: " << GetLastError());
        if (!config.proxyPassword.empty() && !InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_PROXY_PASSWORD, (LPVOID)config.proxyPassword.c_str(), (DWORD)config.proxyPassword.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting password for proxy with error code: " << GetLastError());
    }

    if (!config.verifySSL)
    {
        AWS_LOGSTREAM_WARN(GetLogTag(), "Turning ssl unknown ca verification off.");
        DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | INTERNET_FLAG_IGNORE_CERT_CN_INVALID;

        if (!InternetSetOptionA(GetOpenHandle(), INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed to turn ssl cert ca verification off.");
    }

    AWS_LOGSTREAM_DEBUG(GetLogTag(), "API handle " << GetOpenHandle());
    SetConnectionPoolManager(Aws::New<WinINetConnectionPoolMgr>(GetLogTag(),
        GetOpenHandle(), config.maxConnections, config.requestTimeoutMs, config.connectTimeoutMs));
}

WinINetSyncHttpClient::~WinINetSyncHttpClient()
{

}

void* WinINetSyncHttpClient::OpenRequest(const Aws::Http::HttpRequest& request, void* connection, const Aws::StringStream& ss) const
{
    DWORD requestFlags =
        INTERNET_FLAG_NO_AUTH |
        INTERNET_FLAG_RELOAD |
        INTERNET_FLAG_KEEP_CONNECTION |
        (request.GetUri().GetScheme() == Scheme::HTTPS ? INTERNET_FLAG_SECURE : 0) |
        INTERNET_FLAG_NO_CACHE_WRITE |
        (m_allowRedirects ? 0 : INTERNET_FLAG_NO_AUTO_REDIRECT);

    LPCSTR accept[2] = { nullptr, nullptr };

    Aws::String acceptHeader("*/*");

    if (request.HasHeader(Aws::Http::ACCEPT_HEADER))
    {
        acceptHeader = request.GetHeaderValue(Aws::Http::ACCEPT_HEADER);
    }

    accept[0] = acceptHeader.c_str();

    HINTERNET hHttpRequest = HttpOpenRequestA(connection, HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()),
        ss.str().c_str(), nullptr, nullptr, accept, requestFlags, 0);
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "HttpOpenRequestA returned handle " << hHttpRequest);

    return hHttpRequest;
}

void WinINetSyncHttpClient::DoAddHeaders(void* hHttpRequest, Aws::String& headerStr) const
{
    if (!HttpAddRequestHeadersA(hHttpRequest, headerStr.c_str(), (DWORD)headerStr.length(), HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))
        AWS_LOGSTREAM_ERROR(GetLogTag(), "Failed to add HTTP request headers with error code: " << GetLastError());
}

uint64_t WinINetSyncHttpClient::DoWriteData(void* hHttpRequest, char* streamBuffer, uint64_t bytesRead) const
{
    DWORD bytesWritten = 0;
    if(!InternetWriteFile(hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten))
    {
        return 0;
    }

    return bytesWritten;
}

bool WinINetSyncHttpClient::DoReceiveResponse(void* hHttpRequest) const
{
    return (HttpEndRequest(hHttpRequest, nullptr, 0, 0) != 0);
}

bool WinINetSyncHttpClient::DoQueryHeaders(void* hHttpRequest, std::shared_ptr<StandardHttpResponse>& response, Aws::StringStream& ss, uint64_t& read) const
{

    char dwStatusCode[256];
    DWORD dwSize = sizeof(dwStatusCode);

    HttpQueryInfoA(hHttpRequest, HTTP_QUERY_STATUS_CODE, &dwStatusCode, &dwSize, 0);
    response->SetResponseCode((HttpResponseCode)atoi(dwStatusCode));
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received response code " << dwStatusCode);

    char contentTypeStr[1024];
    dwSize = sizeof(contentTypeStr);
    HttpQueryInfoA(hHttpRequest, HTTP_QUERY_CONTENT_TYPE, &contentTypeStr, &dwSize, 0);
    if (contentTypeStr[0] != NULL)
    {
        response->SetContentType(contentTypeStr);
        AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received content type " << contentTypeStr);
    }

    char headerStr[1024];
    dwSize = sizeof(headerStr);
    AWS_LOGSTREAM_DEBUG(GetLogTag(), "Received headers:");
    while (HttpQueryInfoA(hHttpRequest, HTTP_QUERY_RAW_HEADERS_CRLF, headerStr, &dwSize, (LPDWORD)&read) && dwSize > 0)
    {
        AWS_LOGSTREAM_DEBUG(GetLogTag(), headerStr);
        ss << headerStr;
    }
    return (read != 0);
}

bool WinINetSyncHttpClient::DoSendRequest(void* hHttpRequest) const
{
    return (HttpSendRequestEx(hHttpRequest, NULL, NULL, 0, 0) != 0);
}

bool WinINetSyncHttpClient::DoReadData(void* hHttpRequest, char* body, uint64_t size, uint64_t& read) const
{
    return (InternetReadFile(hHttpRequest, body, (DWORD)size, (LPDWORD)&read) != 0);
}

void* WinINetSyncHttpClient::GetClientModule() const
{
    return GetModuleHandle(TEXT("wininet.dll"));
}
<|endoftext|>


<commit_before>#include "StackPlaneView.h"
#include "StackSession.h"
#include "StackPlaneController.h"

#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkInteractorStyle.h>
#include <vtkPointData.h>
#include "QVTKWidget.h"
#include <QtGui/QWidget>
#include <QVBoxLayout>

using namespace NeuroProof;
using std::tr1::unordered_map;

StackPlaneView::StackPlaneView(StackSession* stack_session_,
        StackPlaneController* controller_, QWidget* widget_parent_) :
        stack_session(stack_session_), controller(controller_),
        widget_parent(widget_parent_), renderWindowInteractor(0)
{
    stack_session->attach_observer(this);
}

StackPlaneView::~StackPlaneView()
{
    stack_session->detach_observer(this);
    if (qt_widget) {
        if (layout) {
            QLayoutItem * item;
            if ((item = layout->takeAt(0)) != 0) {
                layout->removeItem(item);
            }
            layout->removeWidget(qt_widget);
            delete layout;
        }
        delete qt_widget;
    }
}

void StackPlaneView::pan(int xdiff, int ydiff)
{
    double viewFocus[4], viewPoint[3];

    vtkRenderer * renderer = viewer->GetRenderer();
    vtkCamera *camera = renderer->GetActiveCamera();

    // use old focus and position points
    camera->GetFocalPoint(viewFocus);
    camera->GetPosition(viewPoint);

    camera->SetFocalPoint(xdiff + viewFocus[0], ydiff + viewFocus[1],
            viewFocus[2]);
    camera->SetPosition(xdiff + viewPoint[0], ydiff + viewPoint[1],
            viewPoint[2]);

    if (renderWindowInteractor->GetLightFollowCamera()) {
        renderer->UpdateLightsGeometryToFollowCamera();
    }
    renderWindowInteractor->Render();
}

// call update and create controller -- rag, gray, and labels must exist
void StackPlaneView::initialize()
{
    Stack* stack = stack_session->get_stack();

    VolumeLabelPtr labelvol = stack->get_labelvol();
    VolumeGrayPtr grayvol = stack->get_grayvol();
    if (!grayvol) {
        throw ErrMsg("Cannot Initialize: no gray volume loaded");
    }

    // load gray volume into vtk array
    grayarray = vtkSmartPointer<vtkUnsignedCharArray>::New();
    grayarray->SetArray(grayvol->begin(), grayvol->shape(0) *
            grayvol->shape(1) * grayvol->shape(2), 1);

    // load array into gray vtk image volume
    grayvtk = vtkSmartPointer<vtkImageData>::New();
    grayvtk->GetPointData()->SetScalars(grayarray);

    // set grayscale properties
    grayvtk->SetDimensions(grayvol->shape(0), grayvol->shape(1),
            grayvol->shape(2));
    grayvtk->SetScalarType(VTK_UNSIGNED_CHAR);
    grayvtk->SetSpacing(1, 1, 1); // hack for now; TODO: set res from stack?
    grayvtk->SetOrigin(0.0, 0.0, 0.0);

    graylookup = vtkSmartPointer<vtkLookupTable>::New();
    graylookup->SetNumberOfTableValues(256);
    graylookup->SetRange(0.0, 256);
    graylookup->SetHueRange(0.0,1.0);
    graylookup->SetValueRange(0.0,1.0);
    graylookup->Build();
    for (int i = 0; i < 256; ++i) {
        graylookup->SetTableValue(i, i/255.0, i/255.0, i/255.0, 1);
    }
    gray_mapped = vtkSmartPointer<vtkImageMapToColors>::New();
    gray_mapped->SetInput(grayvtk);
    gray_mapped->SetLookupTable(graylookup);
    gray_mapped->Update();

    // rebase label volume and enable show all labels in a different color
    unsigned int * labels_rebase = new unsigned int [labelvol->shape(0) *
        labelvol->shape(1) * labelvol->shape(2)];
    unsigned int * iter = labels_rebase;
    Label_t max_label = 0;
    volume_forXYZ(*labelvol, x, y, z) {
        Label_t label = (*labelvol)(x,y,z);
        if (label > max_label) {
            max_label = label;
        }
        *iter++ = label;
    }
    // 32 bit array takes some time to load -- could convert the 32 bit
    // image to a 8 bit uchar for color
    labelarray = vtkSmartPointer<vtkUnsignedIntArray>::New();
    labelarray->SetArray(labels_rebase, labelvol->shape(0) * labelvol->shape(1) *
            labelvol->shape(2), 0);

    // set label options
    labelvtk = vtkSmartPointer<vtkImageData>::New();
    labelvtk->GetPointData()->SetScalars(labelarray);
    labelvtk->SetDimensions(labelvol->shape(0), labelvol->shape(1),
            labelvol->shape(2));
    labelvtk->SetScalarType(VTK_UNSIGNED_INT);
    labelvtk->SetSpacing(1, 1, 1);
    labelvtk->SetOrigin(0.0, 0.0, 0.0);

    // set lookup table
    label_lookup = vtkSmartPointer<vtkLookupTable>::New();
    label_lookup->SetNumberOfTableValues(max_label+1);
    label_lookup->SetRange( 0.0, max_label);
    label_lookup->SetHueRange( 0.0, 1.0 );
    label_lookup->SetValueRange( 0.0, 1.0 );
    label_lookup->Build();

    RagPtr rag = stack->get_rag();
    load_rag_colors(rag);

    // map colors for each label
    labelvtk_mapped = vtkSmartPointer<vtkImageMapToColors>::New();
    labelvtk_mapped->SetInput(labelvtk);
    labelvtk_mapped->SetLookupTable(label_lookup);
    labelvtk_mapped->Update();

    // blend both images
    vtkblend = vtkSmartPointer<vtkImageBlend>::New();
    vtkblend->AddInputConnection(gray_mapped->GetOutputPort());
    vtkblend->AddInputConnection(labelvtk_mapped->GetOutputPort());
    vtkblend->SetOpacity(0, 1);
    vtkblend->SetOpacity(1, 0.3);
    vtkblend->Update();

    // flip along y
    vtkblend_flipped = vtkSmartPointer<vtkImageFlip>::New();
    vtkblend_flipped->SetInputConnection(vtkblend->GetOutputPort());
    vtkblend_flipped->SetFilteredAxis(1);
    vtkblend_flipped->Update();

    // create 2D view
    viewer = vtkSmartPointer<vtkImageViewer2>::New();
    viewer->SetColorLevel(127.5);
    viewer->SetColorWindow(255);
    viewer->SetInputConnection(vtkblend_flipped->GetOutputPort());

    //qt widgets

    if (widget_parent) {
        layout = new QVBoxLayout;
        qt_widget = new QVTKWidget;
        layout->addWidget(qt_widget);
        widget_parent->setLayout(layout);
        //qt_widget = new QVTKWidget(widget_parent);
        //planeView->setGeometry(QRect(0, 0, 671, 571));
    } else {
        qt_widget = new QVTKWidget;
    }

    //qt_widget->setObjectName(QString::fromUtf8("planeView"));
    //qt_widget->showMaximized();
    qt_widget->SetRenderWindow(viewer->GetRenderWindow());
    renderWindowInteractor = qt_widget->GetInteractor();

    viewer->SetupInteractor(renderWindowInteractor);
    viewer->Render();
    vtkRenderer * renderer = viewer->GetRenderer();
    vtkCamera *camera = renderer->GetActiveCamera();
    initial_zoom = camera->GetParallelScale();
}

void StackPlaneView::load_rag_colors(RagPtr rag)
{
    // compute different colors for each RAG node
    // using greedy graph coloring algorithm
    stack_session->compute_label_colors(rag);

    for (Rag_t::nodes_iterator iter = rag->nodes_begin();
            iter != rag->nodes_end(); ++iter) {
        int color_id = (*iter)->get_property<int>("color");
        unsigned char r, g, b;
        stack_session->get_rgb(color_id, r, g, b);
        label_lookup->SetTableValue((*iter)->get_node_id(), r/255.0,
                g/255.0, b/255.0, 1);
    }
}

void StackPlaneView::start()
{
    qt_widget->show();
}

void StackPlaneView::update()
{
    bool show_all;
    unsigned int plane_id;
    Label_t select_id = 0;
    Label_t select_id_old = 0;
    Label_t ignore_label = 0;
    double rgba[4];
    unordered_map<Label_t, int> active_labels;

    bool show_all_change = stack_session->get_show_all(show_all);
    double opacity_val = 1.0;
    if (!show_all) {
        opacity_val = 0.0;
    }

    VolumeLabelPtr labelvol;
    RagPtr rag;
    if (stack_session->get_reset_stack(labelvol, rag)) {
        // rebase label volume and enable show all labels in a different color
        unsigned int * labels_rebase = new unsigned int [labelvol->shape(0) * labelvol->shape(1) * labelvol->shape(2)];
        unsigned int * iter = labels_rebase;
        Label_t max_label = 0;
        volume_forXYZ(*labelvol, x, y, z) {
            Label_t label = (*labelvol)(x,y,z);
            if (label > max_label) {
                max_label = label;
            }
            *iter++ = label;
        }
        label_lookup->SetNumberOfTableValues(max_label+1);
        label_lookup->SetRange(0.0, max_label);

        labelarray = vtkSmartPointer<vtkUnsignedIntArray>::New();
        labelarray->SetArray(labels_rebase, labelvol->shape(0) * labelvol->shape(1) *
                labelvol->shape(2), 0);
        labelvtk->GetPointData()->SetScalars(labelarray);

        load_rag_colors(rag);
    }

    unsigned int xloc, yloc;
    double zoom_factor;
    // grab zoom and set absolute -- zoom should be called on reset along with plane set
    if (stack_session->get_zoom_loc(xloc, yloc, zoom_factor)) {
        vtkRenderer * renderer = viewer->GetRenderer();
        vtkCamera *camera = renderer->GetActiveCamera();

        double viewFocus[4], viewPoint[3];
        camera->GetFocalPoint(viewFocus);
        camera->GetPosition(viewPoint);

        unsigned ysize = stack_session->get_stack()->get_ysize();
        camera->SetFocalPoint(xloc, ysize - yloc - 1, viewFocus[2]);
        camera->SetPosition(xloc, ysize - yloc - 1, viewPoint[2]);

        //camera->Zoom(2.0);
        camera->SetParallelScale(initial_zoom / zoom_factor);
    }

    // color selected labels, if nothing selected, color everything
    rag = stack_session->get_stack()->get_rag();
    if (stack_session->get_active_labels(active_labels)) {
        for (int i = 0; i < label_lookup->GetNumberOfTableValues(); ++i) {
            label_lookup->GetTableValue(i, rgba);
            rgba[3] = 0;
            label_lookup->SetTableValue(i, rgba);
        }
        for (unordered_map<Label_t, int>::iterator iter = active_labels.begin();
                iter != active_labels.end(); ++iter) {
            unsigned char r, g, b;
            stack_session->get_rgb(iter->second, r, g, b);
            label_lookup->SetTableValue(iter->first, r/255.0,
                    g/255.0, b/255.0, 1);
        }
    }

    // toggle color for clicked body label
    if (stack_session->get_select_label(select_id, select_id_old)) {
        if (select_id_old && (active_labels.empty() ||
                (active_labels.find(select_id_old) != active_labels.end())) ) {
            label_lookup->GetTableValue(select_id_old, rgba);
            rgba[3] = 1.0;
            label_lookup->SetTableValue(select_id_old, rgba);
            label_lookup->Modified();
        }
    }

    if (select_id) {
        // do not toggle this label on when doing global toggle
        ignore_label = select_id;
    }

    // toggle color for all bodies
    if (show_all_change) {
        double opacity_val = 1.0;
        if (!show_all) {
            opacity_val = 0.0;
        }
        double rgba[4];

        if (!active_labels.empty()) {
            for (unordered_map<Label_t, int>::iterator iter = active_labels.begin();
                    iter != active_labels.end(); ++iter) {
                label_lookup->GetTableValue(iter->first, rgba);
                rgba[3] = opacity_val;
                label_lookup->SetTableValue(iter->first, rgba);
            }
        } else {
            for (int i = 0; i < label_lookup->GetNumberOfTableValues(); ++i) {
                label_lookup->GetTableValue(i, rgba);
                rgba[3] = opacity_val;
                label_lookup->SetTableValue(i, rgba);
            }
        }
        label_lookup->Modified();
    }

    if (ignore_label) {
        label_lookup->GetTableValue(ignore_label, rgba);
        rgba[3] = 0.0;
        label_lookup->SetTableValue(ignore_label, rgba);
        label_lookup->Modified();
    }

    // set the current plane
    if (stack_session->get_plane(plane_id)) {
        viewer->SetSlice(plane_id);
    }

    // set the current color opacity
    unsigned int curr_opacity = 0;
    if (stack_session->get_opacity(curr_opacity)) {
        vtkblend->SetOpacity(1, curr_opacity / 10.0);
    }

    viewer->Render();
}
<commit_msg>explicit cast of vigra to unsigned char<commit_after>#include "StackPlaneView.h"
#include "StackSession.h"
#include "StackPlaneController.h"

#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkInteractorStyle.h>
#include <vtkPointData.h>
#include "QVTKWidget.h"
#include <QtGui/QWidget>
#include <QVBoxLayout>

using namespace NeuroProof;
using std::tr1::unordered_map;

StackPlaneView::StackPlaneView(StackSession* stack_session_,
        StackPlaneController* controller_, QWidget* widget_parent_) :
        stack_session(stack_session_), controller(controller_),
        widget_parent(widget_parent_), renderWindowInteractor(0)
{
    stack_session->attach_observer(this);
}

StackPlaneView::~StackPlaneView()
{
    stack_session->detach_observer(this);
    if (qt_widget) {
        if (layout) {
            QLayoutItem * item;
            if ((item = layout->takeAt(0)) != 0) {
                layout->removeItem(item);
            }
            layout->removeWidget(qt_widget);
            delete layout;
        }
        delete qt_widget;
    }
}

void StackPlaneView::pan(int xdiff, int ydiff)
{
    double viewFocus[4], viewPoint[3];

    vtkRenderer * renderer = viewer->GetRenderer();
    vtkCamera *camera = renderer->GetActiveCamera();

    // use old focus and position points
    camera->GetFocalPoint(viewFocus);
    camera->GetPosition(viewPoint);

    camera->SetFocalPoint(xdiff + viewFocus[0], ydiff + viewFocus[1],
            viewFocus[2]);
    camera->SetPosition(xdiff + viewPoint[0], ydiff + viewPoint[1],
            viewPoint[2]);

    if (renderWindowInteractor->GetLightFollowCamera()) {
        renderer->UpdateLightsGeometryToFollowCamera();
    }
    renderWindowInteractor->Render();
}

// call update and create controller -- rag, gray, and labels must exist
void StackPlaneView::initialize()
{
    Stack* stack = stack_session->get_stack();

    VolumeLabelPtr labelvol = stack->get_labelvol();
    VolumeGrayPtr grayvol = stack->get_grayvol();
    if (!grayvol) {
        throw ErrMsg("Cannot Initialize: no gray volume loaded");
    }

    // load gray volume into vtk array
    grayarray = vtkSmartPointer<vtkUnsignedCharArray>::New();
    grayarray->SetArray((unsigned char *)(grayvol->begin()), grayvol->shape(0) *
            grayvol->shape(1) * grayvol->shape(2), 1);

    // load array into gray vtk image volume
    grayvtk = vtkSmartPointer<vtkImageData>::New();
    grayvtk->GetPointData()->SetScalars(grayarray);

    // set grayscale properties
    grayvtk->SetDimensions(grayvol->shape(0), grayvol->shape(1),
            grayvol->shape(2));
    grayvtk->SetScalarType(VTK_UNSIGNED_CHAR);
    grayvtk->SetSpacing(1, 1, 1); // hack for now; TODO: set res from stack?
    grayvtk->SetOrigin(0.0, 0.0, 0.0);

    graylookup = vtkSmartPointer<vtkLookupTable>::New();
    graylookup->SetNumberOfTableValues(256);
    graylookup->SetRange(0.0, 256);
    graylookup->SetHueRange(0.0,1.0);
    graylookup->SetValueRange(0.0,1.0);
    graylookup->Build();
    for (int i = 0; i < 256; ++i) {
        graylookup->SetTableValue(i, i/255.0, i/255.0, i/255.0, 1);
    }
    gray_mapped = vtkSmartPointer<vtkImageMapToColors>::New();
    gray_mapped->SetInput(grayvtk);
    gray_mapped->SetLookupTable(graylookup);
    gray_mapped->Update();

    // rebase label volume and enable show all labels in a different color
    unsigned int * labels_rebase = new unsigned int [labelvol->shape(0) *
        labelvol->shape(1) * labelvol->shape(2)];
    unsigned int * iter = labels_rebase;
    Label_t max_label = 0;
    volume_forXYZ(*labelvol, x, y, z) {
        Label_t label = (*labelvol)(x,y,z);
        if (label > max_label) {
            max_label = label;
        }
        *iter++ = label;
    }
    // 32 bit array takes some time to load -- could convert the 32 bit
    // image to a 8 bit uchar for color
    labelarray = vtkSmartPointer<vtkUnsignedIntArray>::New();
    labelarray->SetArray(labels_rebase, labelvol->shape(0) * labelvol->shape(1) *
            labelvol->shape(2), 0);

    // set label options
    labelvtk = vtkSmartPointer<vtkImageData>::New();
    labelvtk->GetPointData()->SetScalars(labelarray);
    labelvtk->SetDimensions(labelvol->shape(0), labelvol->shape(1),
            labelvol->shape(2));
    labelvtk->SetScalarType(VTK_UNSIGNED_INT);
    labelvtk->SetSpacing(1, 1, 1);
    labelvtk->SetOrigin(0.0, 0.0, 0.0);

    // set lookup table
    label_lookup = vtkSmartPointer<vtkLookupTable>::New();
    label_lookup->SetNumberOfTableValues(max_label+1);
    label_lookup->SetRange( 0.0, max_label);
    label_lookup->SetHueRange( 0.0, 1.0 );
    label_lookup->SetValueRange( 0.0, 1.0 );
    label_lookup->Build();

    RagPtr rag = stack->get_rag();
    load_rag_colors(rag);

    // map colors for each label
    labelvtk_mapped = vtkSmartPointer<vtkImageMapToColors>::New();
    labelvtk_mapped->SetInput(labelvtk);
    labelvtk_mapped->SetLookupTable(label_lookup);
    labelvtk_mapped->Update();

    // blend both images
    vtkblend = vtkSmartPointer<vtkImageBlend>::New();
    vtkblend->AddInputConnection(gray_mapped->GetOutputPort());
    vtkblend->AddInputConnection(labelvtk_mapped->GetOutputPort());
    vtkblend->SetOpacity(0, 1);
    vtkblend->SetOpacity(1, 0.3);
    vtkblend->Update();

    // flip along y
    vtkblend_flipped = vtkSmartPointer<vtkImageFlip>::New();
    vtkblend_flipped->SetInputConnection(vtkblend->GetOutputPort());
    vtkblend_flipped->SetFilteredAxis(1);
    vtkblend_flipped->Update();

    // create 2D view
    viewer = vtkSmartPointer<vtkImageViewer2>::New();
    viewer->SetColorLevel(127.5);
    viewer->SetColorWindow(255);
    viewer->SetInputConnection(vtkblend_flipped->GetOutputPort());

    //qt widgets

    if (widget_parent) {
        layout = new QVBoxLayout;
        qt_widget = new QVTKWidget;
        layout->addWidget(qt_widget);
        widget_parent->setLayout(layout);
        //qt_widget = new QVTKWidget(widget_parent);
        //planeView->setGeometry(QRect(0, 0, 671, 571));
    } else {
        qt_widget = new QVTKWidget;
    }

    //qt_widget->setObjectName(QString::fromUtf8("planeView"));
    //qt_widget->showMaximized();
    qt_widget->SetRenderWindow(viewer->GetRenderWindow());
    renderWindowInteractor = qt_widget->GetInteractor();

    viewer->SetupInteractor(renderWindowInteractor);
    viewer->Render();
    vtkRenderer * renderer = viewer->GetRenderer();
    vtkCamera *camera = renderer->GetActiveCamera();
    initial_zoom = camera->GetParallelScale();
}

void StackPlaneView::load_rag_colors(RagPtr rag)
{
    // compute different colors for each RAG node
    // using greedy graph coloring algorithm
    stack_session->compute_label_colors(rag);

    for (Rag_t::nodes_iterator iter = rag->nodes_begin();
            iter != rag->nodes_end(); ++iter) {
        int color_id = (*iter)->get_property<int>("color");
        unsigned char r, g, b;
        stack_session->get_rgb(color_id, r, g, b);
        label_lookup->SetTableValue((*iter)->get_node_id(), r/255.0,
                g/255.0, b/255.0, 1);
    }
}

void StackPlaneView::start()
{
    qt_widget->show();
}

void StackPlaneView::update()
{
    bool show_all;
    unsigned int plane_id;
    Label_t select_id = 0;
    Label_t select_id_old = 0;
    Label_t ignore_label = 0;
    double rgba[4];
    unordered_map<Label_t, int> active_labels;

    bool show_all_change = stack_session->get_show_all(show_all);
    double opacity_val = 1.0;
    if (!show_all) {
        opacity_val = 0.0;
    }

    VolumeLabelPtr labelvol;
    RagPtr rag;
    if (stack_session->get_reset_stack(labelvol, rag)) {
        // rebase label volume and enable show all labels in a different color
        unsigned int * labels_rebase = new unsigned int [labelvol->shape(0) * labelvol->shape(1) * labelvol->shape(2)];
        unsigned int * iter = labels_rebase;
        Label_t max_label = 0;
        volume_forXYZ(*labelvol, x, y, z) {
            Label_t label = (*labelvol)(x,y,z);
            if (label > max_label) {
                max_label = label;
            }
            *iter++ = label;
        }
        label_lookup->SetNumberOfTableValues(max_label+1);
        label_lookup->SetRange(0.0, max_label);

        labelarray = vtkSmartPointer<vtkUnsignedIntArray>::New();
        labelarray->SetArray(labels_rebase, labelvol->shape(0) * labelvol->shape(1) *
                labelvol->shape(2), 0);
        labelvtk->GetPointData()->SetScalars(labelarray);

        load_rag_colors(rag);
    }

    unsigned int xloc, yloc;
    double zoom_factor;
    // grab zoom and set absolute -- zoom should be called on reset along with plane set
    if (stack_session->get_zoom_loc(xloc, yloc, zoom_factor)) {
        vtkRenderer * renderer = viewer->GetRenderer();
        vtkCamera *camera = renderer->GetActiveCamera();

        double viewFocus[4], viewPoint[3];
        camera->GetFocalPoint(viewFocus);
        camera->GetPosition(viewPoint);

        unsigned ysize = stack_session->get_stack()->get_ysize();
        camera->SetFocalPoint(xloc, ysize - yloc - 1, viewFocus[2]);
        camera->SetPosition(xloc, ysize - yloc - 1, viewPoint[2]);

        //camera->Zoom(2.0);
        camera->SetParallelScale(initial_zoom / zoom_factor);
    }

    // color selected labels, if nothing selected, color everything
    rag = stack_session->get_stack()->get_rag();
    if (stack_session->get_active_labels(active_labels)) {
        for (int i = 0; i < label_lookup->GetNumberOfTableValues(); ++i) {
            label_lookup->GetTableValue(i, rgba);
            rgba[3] = 0;
            label_lookup->SetTableValue(i, rgba);
        }
        for (unordered_map<Label_t, int>::iterator iter = active_labels.begin();
                iter != active_labels.end(); ++iter) {
            unsigned char r, g, b;
            stack_session->get_rgb(iter->second, r, g, b);
            label_lookup->SetTableValue(iter->first, r/255.0,
                    g/255.0, b/255.0, 1);
        }
    }

    // toggle color for clicked body label
    if (stack_session->get_select_label(select_id, select_id_old)) {
        if (select_id_old && (active_labels.empty() ||
                (active_labels.find(select_id_old) != active_labels.end())) ) {
            label_lookup->GetTableValue(select_id_old, rgba);
            rgba[3] = 1.0;
            label_lookup->SetTableValue(select_id_old, rgba);
            label_lookup->Modified();
        }
    }

    if (select_id) {
        // do not toggle this label on when doing global toggle
        ignore_label = select_id;
    }

    // toggle color for all bodies
    if (show_all_change) {
        double opacity_val = 1.0;
        if (!show_all) {
            opacity_val = 0.0;
        }
        double rgba[4];

        if (!active_labels.empty()) {
            for (unordered_map<Label_t, int>::iterator iter = active_labels.begin();
                    iter != active_labels.end(); ++iter) {
                label_lookup->GetTableValue(iter->first, rgba);
                rgba[3] = opacity_val;
                label_lookup->SetTableValue(iter->first, rgba);
            }
        } else {
            for (int i = 0; i < label_lookup->GetNumberOfTableValues(); ++i) {
                label_lookup->GetTableValue(i, rgba);
                rgba[3] = opacity_val;
                label_lookup->SetTableValue(i, rgba);
            }
        }
        label_lookup->Modified();
    }

    if (ignore_label) {
        label_lookup->GetTableValue(ignore_label, rgba);
        rgba[3] = 0.0;
        label_lookup->SetTableValue(ignore_label, rgba);
        label_lookup->Modified();
    }

    // set the current plane
    if (stack_session->get_plane(plane_id)) {
        viewer->SetSlice(plane_id);
    }

    // set the current color opacity
    unsigned int curr_opacity = 0;
    if (stack_session->get_opacity(curr_opacity)) {
        vtkblend->SetOpacity(1, curr_opacity / 10.0);
    }

    viewer->Render();
}
<|endoftext|>