Пример #1
0
void QTriangulatingStroker::moveTo(const qreal *pts)
{
    m_cx = pts[0];
    m_cy = pts[1];

    float x2 = pts[2];
    float y2 = pts[3];
    normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy);


    // To acheive jumps we insert zero-area tringles. This is done by
    // adding two identical points in both the end of previous strip
    // and beginning of next strip
    bool invisibleJump = m_vertices.size();

    switch (m_cap_style) {
    case Qt::FlatCap:
        if (invisibleJump) {
            m_vertices.add(m_cx + m_nvx);
            m_vertices.add(m_cy + m_nvy);
        }
        break;
    case Qt::SquareCap: {
        float sx = m_cx - m_nvy;
        float sy = m_cy + m_nvx;
        if (invisibleJump) {
            m_vertices.add(sx + m_nvx);
            m_vertices.add(sy + m_nvy);
        }
        emitLineSegment(sx, sy, m_nvx, m_nvy);
        break; }
    case Qt::RoundCap: {
        QVarLengthArray<float> points;
        arcPoints(m_cx, m_cy, m_cx + m_nvx, m_cy + m_nvy, m_cx - m_nvx, m_cy - m_nvy, points);
        m_vertices.resize(m_vertices.size() + points.size() + 2 * int(invisibleJump));
        int count = m_vertices.size();
        int front = 0;
        int end = points.size() / 2;
        while (front != end) {
            m_vertices.at(--count) = points[2 * end - 1];
            m_vertices.at(--count) = points[2 * end - 2];
            --end;
            if (front == end)
                break;
            m_vertices.at(--count) = points[2 * front + 1];
            m_vertices.at(--count) = points[2 * front + 0];
            ++front;
        }

        if (invisibleJump) {
            m_vertices.at(count - 1) = m_vertices.at(count + 1);
            m_vertices.at(count - 2) = m_vertices.at(count + 0);
        }
        break; }
    default: break; // ssssh gcc...
    }
    emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
}
Пример #2
0
double
NBHeightMapper::Triangle::getZ(const Position& geo) const {
    // en.wikipedia.org/wiki/Line-plane_intersection
    Position p0 = myCorners.front();
    Position line(0, 0, 1);
    p0.sub(geo); // p0 - l0
    Position normal = normalVector();
    return p0.dotProduct(normal) / line.dotProduct(normal);
}
Пример #3
0
 inline
 Circle3d
 Circle3d::transformedBy(const TTransformation& transformation) const {
     return Circle3d(
         centerPoint().transformedBy(transformation),
         normalVector().transformedBy(transformation),
         transformation.scale() * radius()
     );
 }
Пример #4
0
void GLC_MeshData::setVboUsage(bool usage)
{
	if (usage && (m_PositionSize != -1) && (!m_Positions.isEmpty()) && (!m_VertexBuffer.isCreated()))
	{
		createVBOs();

		fillVbo(GLC_MeshData::GLC_Vertex);
		fillVbo(GLC_MeshData::GLC_Normal);
		fillVbo(GLC_MeshData::GLC_Texel);
		fillVbo(GLC_MeshData::GLC_Color);
		useVBO(false, GLC_MeshData::GLC_Color);

		const int lodCount= m_LodList.count();
		for (int i= 0; i < lodCount; ++i)
		{
			m_LodList.at(i)->setIboUsage(usage);
		}

	}
	else if (!usage && m_VertexBuffer.isCreated())
	{
		m_Positions= positionVector();
		m_PositionSize= m_Positions.size();
		m_VertexBuffer.destroy();

		m_Normals= normalVector();
		m_NormalBuffer.destroy();

		if (m_TexelBuffer.isCreated())
		{
			m_Texels= texelVector();
			m_TexelsSize= m_Texels.size();
			m_TexelBuffer.destroy();
		}
		if (m_ColorBuffer.isCreated())
		{
			m_Colors= colorVector();
			m_ColorSize= m_Colors.size();
			m_ColorBuffer.destroy();
		}

		const int lodCount= m_LodList.count();
		for (int i= 0; i < lodCount; ++i)
		{
			m_LodList.at(i)->setIboUsage(usage);
		}
	}
	m_UseVbo= usage;

}
Пример #5
0
void GLC_MeshData::copyVboToClientSide()
{

	if (m_VertexBuffer.isCreated() && m_Positions.isEmpty())
	{
		Q_ASSERT(m_NormalBuffer.isCreated());
		m_Positions= positionVector();
		m_Normals= normalVector();
		if (m_TexelBuffer.isCreated())
		{
			m_Texels= texelVector();
		}
		if (m_ColorBuffer.isCreated())
		{
			m_Colors= colorVector();
		}
	}
}
Пример #6
0
/*!
Compute the angle that the vector normal to the plane forms with xy plane

\return
The angle that the vector normal to this forms with the xy plane, return a value in the interval [0 ; 2*PI],
positive angles is counterclockwise, or DBL_MAX if this is not valid
*/
double GM_3dPlane::xyAngle() const {
	double ret = DBL_MAX;
	if (!isValid())
		return ret;

	GM_3dVector normVector = normalVector();
	double dz = normVector.z();
	double dxy = sqrt(normVector.x()*normVector.x() + normVector.y()*normVector.y());
	double tanAng = atan2(dz, dxy);
	if (tanAng < 0.0) {
		ret = (2.0 * GM_PI) + tanAng;
	}
	else {
		ret = tanAng;
	}
	
	return ret;
}
Пример #7
0
 Box3d
 Circle3d::bounds() const {
     double nx2 = normalVector().x() * normalVector().x();
     double ny2 = normalVector().y() * normalVector().y();
     double nz2 = normalVector().z() * normalVector().z();
     double dx = radius() * sqrt(ny2 + nz2);
     double dy = radius() * sqrt(nx2 + nz2);
     double dz = radius() * sqrt(nx2 + ny2);
     return Box3d(
         Interval(centerPoint().x() - dx, centerPoint().x() + dx),
         Interval(centerPoint().y() - dy, centerPoint().y() + dy),
         Interval(centerPoint().z() - dz, centerPoint().z() + dz)
     );
 }
Пример #8
0
// Return the color Vector
GLfloatVector GLC_MeshData::colorVector() const
{
	if (m_ColorBuffer.isCreated())
	{
		// VBO created get data from VBO
		const int sizeOfVbo= m_ColorSize;
		const GLsizeiptr dataSize= sizeOfVbo * sizeof(GLfloat);
		GLfloatVector normalVector(sizeOfVbo);

		const_cast<QGLBuffer&>(m_ColorBuffer).bind();
		GLvoid* pVbo = const_cast<QGLBuffer&>(m_ColorBuffer).map(QGLBuffer::ReadOnly);
		memcpy(normalVector.data(), pVbo, dataSize);
		const_cast<QGLBuffer&>(m_ColorBuffer).unmap();
		const_cast<QGLBuffer&>(m_ColorBuffer).release();
		return normalVector;
	}
	else
	{
		return m_Colors;
	}
}
Пример #9
0
void QTriangulatingStroker::cubicTo(const qreal *pts)
{
    const QPointF *p = (const QPointF *) pts;
    QBezier bezier = QBezier::fromPoints(*(p - 1), p[0], p[1], p[2]);

    QRectF bounds = bezier.bounds();
    float rad = qMax(bounds.width(), bounds.height());
    int threshold = qMin<float>(64, (rad + m_curvyness_add) * m_curvyness_mul);
    if (threshold < 4)
        threshold = 4;
    qreal threshold_minus_1 = threshold - 1;
    float vx, vy;

    float cx = m_cx, cy = m_cy;
    float x, y;

    for (int i=1; i<threshold; ++i) {
        qreal t = qreal(i) / threshold_minus_1;
        QPointF p = bezier.pointAt(t);
        x = p.x();
        y = p.y();

        normalVector(cx, cy, x, y, &vx, &vy);

        emitLineSegment(x, y, vx, vy);

        cx = x;
        cy = y;
    }

    m_cx = cx;
    m_cy = cy;

    m_nvx = vx;
    m_nvy = vy;
}
Пример #10
0
void QTriangulatingStroker::join(const qreal *pts)
{
    // Creates a join to the next segment (m_cx, m_cy) -> (pts[0], pts[1])
    normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy);

    switch (m_join_style) {
    case Qt::BevelJoin:
        break;
    case Qt::SvgMiterJoin:
    case Qt::MiterJoin: {
        // Find out on which side the join should be.
        int count = m_vertices.size();
        float prevNvx = m_vertices.at(count - 2) - m_cx;
        float prevNvy = m_vertices.at(count - 1) - m_cy;
        float xprod = prevNvx * m_nvy - prevNvy * m_nvx;
        float px, py, qx, qy;

        // If the segments are parallel, use bevel join.
        if (qFuzzyIsNull(xprod))
            break;

        // Find the corners of the previous and next segment to join.
        if (xprod < 0) {
            px = m_vertices.at(count - 2);
            py = m_vertices.at(count - 1);
            qx = m_cx - m_nvx;
            qy = m_cy - m_nvy;
        } else {
            px = m_vertices.at(count - 4);
            py = m_vertices.at(count - 3);
            qx = m_cx + m_nvx;
            qy = m_cy + m_nvy;
        }

        // Find intersection point.
        float pu = px * prevNvx + py * prevNvy;
        float qv = qx * m_nvx + qy * m_nvy;
        float ix = (m_nvy * pu - prevNvy * qv) / xprod;
        float iy = (prevNvx * qv - m_nvx * pu) / xprod;

        // Check that the distance to the intersection point is less than the miter limit.
        if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= m_miter_limit * m_miter_limit) {
            m_vertices.add(ix);
            m_vertices.add(iy);
            m_vertices.add(ix);
            m_vertices.add(iy);
        }
        // else
        // Do a plain bevel join if the miter limit is exceeded or if
        // the lines are parallel. This is not what the raster
        // engine's stroker does, but it is both faster and similar to
        // what some other graphics API's do.

        break; }
    case Qt::RoundJoin: {
        QVarLengthArray<float> points;
        int count = m_vertices.size();
        float prevNvx = m_vertices.at(count - 2) - m_cx;
        float prevNvy = m_vertices.at(count - 1) - m_cy;
        if (m_nvx * prevNvy - m_nvy * prevNvx < 0) {
            arcPoints(0, 0, m_nvx, m_nvy, -prevNvx, -prevNvy, points);
            for (int i = points.size() / 2; i > 0; --i)
                emitLineSegment(m_cx, m_cy, points[2 * i - 2], points[2 * i - 1]);
        } else {
            arcPoints(0, 0, -prevNvx, -prevNvy, m_nvx, m_nvy, points);
            for (int i = 0; i < points.size() / 2; ++i)
                emitLineSegment(m_cx, m_cy, points[2 * i + 0], points[2 * i + 1]);
        }
        break; }
    default: break; // gcc warn--
    }

    emitLineSegment(m_cx, m_cy, m_nvx, m_nvy);
}
Пример #11
0
void GLC_Cone::createMeshAndWire()
{
	Q_ASSERT(GLC_Mesh::isEmpty());
	Q_ASSERT(m_WireData.isEmpty());

	// Create cosinus and sinus array according to the discretion and radius
	const int vertexNumber= m_Discret + 1;
	// Normals values
	QVector<float> cosNormalArray(vertexNumber);
	QVector<float> sinNormalArray(vertexNumber);

	QVector<float> cosArray(vertexNumber);
	QVector<float> sinArray(vertexNumber);

	const double angle= (2.0 * glc::PI) / static_cast<double>(m_Discret);

	// Normal Z value
	GLC_Vector3d normalVector(1.0, 0.0, 0.0);
	GLC_Matrix4x4 rotation(glc::Y_AXIS, -atan(m_Radius / m_Length));
	normalVector= rotation * normalVector;
	const float normalZ= static_cast<float>(normalVector.z());
	const double factor= normalVector.x(); // Normailsation factor

	for (int i= 0; i < vertexNumber; ++i)
	{
		const double cosValue= cos(static_cast<double>(i) * angle);
		const double sinValue= sin(static_cast<double>(i) * angle);

		cosNormalArray[i]= static_cast<GLfloat>(factor * cosValue);
		sinNormalArray[i]= static_cast<GLfloat>(factor * sinValue);

		cosArray[i]= static_cast<GLfloat>(m_Radius * cosValue);
		sinArray[i]= static_cast<GLfloat>(m_Radius * sinValue);
	}


	// Mesh Data
	GLfloatVector verticeVector;
	GLfloatVector normalsVector;
	GLfloatVector texelVector;

	// Wire Data
	GLfloatVector bottomWireData(vertexNumber * 3);

	const int size= vertexNumber * 3;
	verticeVector.resize(3 * size);
	normalsVector.resize(3 * size);
	texelVector.resize(2 * size);

	for (int i= 0; i < vertexNumber; ++i)
	{
		// Bottom Mesh
		verticeVector[3 * i]= cosArray[i];
		verticeVector[3 * i + 1]= sinArray[i];
		verticeVector[3 * i + 2]= 0.0f;

		normalsVector[3 * i]= cosNormalArray[i];
		normalsVector[3 * i + 1]= sinNormalArray[i];
		normalsVector[3 * i + 2]= normalZ;

		texelVector[2 * i]= static_cast<float>(i) / static_cast<float>(m_Discret);
		texelVector[2 * i + 1]= 0.0f;

		// Bottom Wire
		bottomWireData[3 * i]= cosArray[i];
		bottomWireData[3 * i + 1]= sinArray[i];
		bottomWireData[3 * i + 2]= 0.0f;

		// Top
		verticeVector[3 * i + 3 * vertexNumber]= 0.0f;
		verticeVector[3 * i + 1 + 3 * vertexNumber]= 0.0f;
		verticeVector[3 * i + 2 + 3 * vertexNumber]= static_cast<float>(m_Length);

		normalsVector[3 * i + 3 * vertexNumber]= cosNormalArray[i];
		normalsVector[3 * i + 1 + 3 * vertexNumber]= sinNormalArray[i];
		normalsVector[3 * i + 2 + 3 * vertexNumber]= normalZ;

		texelVector[2 * i + 2 * vertexNumber]= texelVector[i];
		texelVector[2 * i + 1 + 2 * vertexNumber]= 1.0f;

		// Bottom Cap ends
		verticeVector[3 * i + 2 * 3 * vertexNumber]= cosArray[i];
		verticeVector[3 * i + 1 + 2 * 3 * vertexNumber]= sinArray[i];
		verticeVector[3 * i + 2 + 2 * 3 * vertexNumber]= 0.0f;

		normalsVector[3 * i + 2 * 3 * vertexNumber]= 0.0f;
		normalsVector[3 * i + 1 + 2 * 3 * vertexNumber]= 0.0f;
		normalsVector[3 * i + 2 + 2 * 3 * vertexNumber]= -1.0f;

		texelVector[2 * i + 2 * 2 * vertexNumber]= texelVector[i];
		texelVector[2 * i + 1 + 2 * 2 * vertexNumber]= 0.0f;

	}

	// Add bulk data in to the mesh
	GLC_Mesh::addVertice(verticeVector);
	GLC_Mesh::addNormals(normalsVector);
	GLC_Mesh::addTexels(texelVector);

	// Add polyline to wire data
	GLC_Geometry::addPolyline(bottomWireData);

	// Set the material to use
	GLC_Material* pCylinderMaterial;
	if (hasMaterial())
	{
		pCylinderMaterial= this->firstMaterial();
	}
	else
	{
		pCylinderMaterial= new GLC_Material();
	}

	IndexList circumferenceStrips;
	// Create the index
	for (int i= 0; i < vertexNumber; ++i)
	{
		circumferenceStrips.append(i + vertexNumber);
		circumferenceStrips.append(i);
	}
	addTrianglesStrip(pCylinderMaterial, circumferenceStrips);

	{
		IndexList bottomCap;
		IndexList topCap;
		int id1= 0;
		int id2= m_Discret - 1;
		const int size= m_Discret / 2 + (m_Discret % 2);
		for (int i= 0; i < size; ++i)
		{
			bottomCap.append(id1 + 2 * vertexNumber);
			bottomCap.append(id2 + 2 * vertexNumber);

			id1+= 1;
			id2-= 1;
		}
		addTrianglesStrip(pCylinderMaterial, bottomCap);
	}

	finish();
}
Пример #12
0
void xaeBlockScene::setRebound(coor c)
{
    /** 法线向量 */
    coor cNormal = c;
    cNormal.x -= m_fBallX;
    cNormal.y -= m_fBallY;

    /** 速度向量 */
    coor cSpeed(m_fBallSpeedX, m_fBallSpeedY);

    switch(g_nReboundAlgorithm)
    {
    case 1:
        {
            /** 许波同学的算法 */
            float a = cNormal.y / cNormal.x;
            float m = cSpeed.x;
            float n = cSpeed.y;

            float x = ((1 - a * a) * m + 2 * a * n) / (a * a + 1);
            float y = ((a * a - 1) * n + 2 * a * m) / (a * a + 1);

            m_fBallSpeedX = x;
            m_fBallSpeedY = y;
            break;
        }

    case 2:
        {
            /** 宋莹莹的算法 */
            float x1 = cSpeed.x, y1 = cSpeed.y;
            float x2 = cNormal.x, y2 = cNormal.y;

            float x3 = 2 * (x2 * (y1 * y2 + x1 * x2) / (x2 * x2 + y2 * y2)) - x1;
            float y3 = 2 * (y2 * (y1 * y2 + x1 * x2) / (x2 * x2 + y2 * y2)) - y1;

            m_fBallSpeedX = x3;
            m_fBallSpeedY = y3;
            break;
        }

    case 3:
        {
            /** 垃圾的算法 */
            m_fBallSpeedX = -m_fBallSpeedX;
            m_fBallSpeedY = -m_fBallSpeedY;

            m_fBallSpeedX += ((rand() % 10) - 5);
            m_fBallSpeedY += ((rand() % 10) - 5);
            break;
        }

    case 100:
        {
            /** 重写的算法 */
            int x = c.x - m_fBallX;
            int y = c.y - m_fBallY;
            
            /** 上下方碰撞 */
            if(abs(y) >= abs(x))
            {
                m_fBallSpeedY = -m_fBallSpeedY;
            }
            else
            /** 左右方碰撞 */
            {
                m_fBallSpeedX = -m_fBallSpeedX;
            }

            break;
        }

    case 4:
    default:
        {
            /** 陈洁操的算法 */
            hgeVector normalVector(cNormal.x, cNormal.y);
            hgeVector speedVector(cSpeed.x, cSpeed.y);

            float sink = ((normalVector.x * speedVector.y) + (normalVector.y * speedVector.x)) / (normalVector.Length() * speedVector.Length());
            float cosk = normalVector.Dot(&speedVector) / (normalVector.Length() * speedVector.Length());

            float newx = normalVector.x * cosk + normalVector.y * sink;
            float newy = normalVector.y * sink - normalVector.x * sink;

            hgeVector newSpeedVector(newx, newy);
            newSpeedVector = (newSpeedVector / newSpeedVector.Length()) * speedVector.Length();

            m_fBallSpeedX = newSpeedVector.x;
            m_fBallSpeedY = newSpeedVector.y;
            break;
        }
    }
}
Пример #13
0
 inline
 Axis3d
 Circle3d::axis() const {
     return Axis3d(centerPoint(), normalVector());
 }
Пример #14
0
 inline
 Plane3d
 Circle3d::plane() const {
     return Plane3d(centerPoint(), normalVector());
 }
Пример #15
0
void Orbit::integrate(PotentialField& potentialField, ElectricField& electricField,
		Field<int>& faceTypeField, CodeField& vertexTypeField,
		ShortestEdgeField shortestEdgeField, FILE *outFile, double orbitLabelValue) {
	// TODO: need some clever way to set tMax and/or detect trapped orbits
//	double dt=min(0.005,0.005/initialVelocity.norm()), tMax=100;
//	double dt=min(0.01,0.01/initialVelocity.norm()), tMax=100;
	double dt=min(0.02,0.02/initialVelocity.norm()), tMax=100;
//	vect3d currentPosition = initialPosition;
	// TODO: should be consistent about starting position
	vect3d currentPosition = initialPosition + (initialVelocity+extern_VEXB)*SMALL_TIME;
	vect3d currentVelocity = initialVelocity;
	// TODO: shouldn't hard-code quasi-neutral operation
	double phiSurface = -4;
	vertexType = vertexTypeField.getField(initialNode);
	vect3d vertexNormalVector;
	vect3d initialNormalVelocity;
	if (vertexType==4 && charge<0.) {
		vertexNormalVector =
				mesh_ptr->getVertexNormalVector(initialNode, faceTypeField);
		vect3d coords = mesh_ptr->getCoordinates(initialNode);
		initialNormalVelocity =
				currentVelocity.dot(vertexNormalVector)*vertexNormalVector;
		// TODO: could do something like below to get distribution at surface
//		currentVelocity += sqrt(2.*charge*phiSurface)*vertexNormalVector;
	}
//	initialEnergy = 0.5*pow(initialVelocity.norm(),2.)
//		+ charge*potentialField.getField(initialNode);
	// Don't integrate orbit if doesn't have enough energy to escape potential
	// TODO: this should be refined
//	if (0.5*pow(initialVelocity.norm(),2.)+0.22 <
//	if ((0.5*pow(initialVelocity.norm(),2.) +
//	if ((0.5*pow(initialVelocity[2],2.) +
//			charge*potentialField.getField(initialNode)) < 0.) {
//		negativeEnergy = true;
//		tMax = 0.;
//	} else {
		negativeEnergy = false;
//	}
	// TODO: treat inwards electrons in a better way?
	if (vertexType==4 &&
			0.5*pow(initialNormalVelocity.norm(),2.)<charge*phiSurface &&
			currentVelocity.dot(vertexNormalVector)<0.) {
		currentVelocity -= 2.*initialNormalVelocity;
	}

	int nSteps=0;
	double potential=0.;
	bool endLoop=false;
	bool foundTet=false;

	boost::array<Eigen::Matrix<double,NDIM,1>, 2> positionAndVelocity;
	boost::array<Eigen::Matrix<double,NDIM,1>, 2> positionAndVelocityOut;
	positionAndVelocity[0] = currentPosition;
	positionAndVelocity[1] = currentVelocity;
//	VelocityVerletStepper<NDIM> timestepper;
//	CyclotronicStepper timestepper;
//	TaylorStepper timestepper;
	DriftStepper timestepper;
//	boost::numeric::odeint::runge_kutta4<boost::array<vect3d,2> >
//		timestepper;
	VelocityAndAcceleration<NDIM> velocityAndAcceleration(potentialField,
//			electricField, charge, initialNode, initialVelocity, false);
			electricField, charge, initialNode, initialVelocity, true);
	foundTet = velocityAndAcceleration.foundTet;
//	assert(foundTet);
	// TODO: do this more cleanly
	if (foundTet) {
	initialPotential = velocityAndAcceleration.currentPotential;
	double driftPotential=extern_E.dot(initialPosition);
	initialPotential += driftPotential;
	initialEnergy = 0.5*pow((initialVelocity+extern_VEXB).norm(),2.)
//	initialEnergy = 0.5*pow(initialVelocity.norm(),2.)
		+ charge*initialPotential;
	double currentPotential=initialPotential;
	double currentEnergy=initialEnergy;

	MinimumBasisFunction minimumBasisFunction(mesh_ptr, &positionAndVelocity,
			&velocityAndAcceleration, &timestepper);


//	// For second order leap-frog, offset position from velocity in time
//	currentPosition -= currentVelocity*dt/2.;
//	for (double t=0.; t<tMax; t+=dt) {
	double t=0;
	double numberOfStepsPerRegion = 3.;
	int numberOfSteps = 100000*numberOfStepsPerRegion;
	// TODO: set max number of steps more cleverly (since also need to limit by accel)
	for (int iT=0; iT<numberOfSteps  && !negativeEnergy; iT++) {
		dt = shortestEdgeField[velocityAndAcceleration.currentRegionIndex]
				/(fabs(currentVelocity[2])+extern_VEXB.norm()+SMALL_VELOCITY)/
//				/(fabs(currentVelocity[2])+DELTA_LENGTH)/
				numberOfStepsPerRegion;
//				/currentVelocity.norm()/5.;
		// TODO: Need acceleration info as well, since v_z changes during time-step
//		dt = min(0.01,dt);
//		dt = 0.01;
		// TODO: can this fail (need to ensure minimumBasisFunction(0.)>0.?
		dt = SMALL_TIME;
		t += dt;
		try {
			timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, dt);
		} catch (...) {
			cout << "Failed to do SMALL_TIME step into interior." << endl;
		}
		// TODO: optimise this or replace with better way?
		double dtMultiplier=10.;
		double dtAtWhichNegative=sqrt(SMALL_TIME)/dtMultiplier;
		// TODO: minimumBasisFunction() should not throw provided positionAndVelocity[0] is within tet
		try {
			while (dtAtWhichNegative<tMax && minimumBasisFunction(dtAtWhichNegative)>0.) {
				dtAtWhichNegative *= dtMultiplier;
			}
		} catch (...) {
			cout << "Failed to evaluate minimumBasisFunction(" << dtAtWhichNegative << ")" << endl;
		}
//		// TODO: debugging
////		cout << minimumBasisFunction(-dtAtWhichNegative) << endl;
//		cout << minimumBasisFunction(SMALL_TIME) << endl;
//		cout << minimumBasisFunction(dtAtWhichNegative) << endl << endl;
////		cout << mesh_ptr->minimumBasisFunction(positionAndVelocity[0]+dtAtWhichNegative*(
////				positionAndVelocity[1]+VEXB),
////				velocityAndAcceleration.currentRegionIndex) << endl;
//		if (extern_orbitNumber==64313 7328) {
//		if (extern_orbitNumber==64313) {
//			cout << velocityAndAcceleration.currentPosition.transpose() << endl;
//			cout << dtAtWhichNegative << endl;
//			cout << minimumBasisFunction(0.) << " " << minimumBasisFunction(dtAtWhichNegative) << endl;
////			cout << minimumBasisFunction(SMALL_TIME) << " " << minimumBasisFunction(dtAtWhichNegative) << endl;
//		}
	    boost::uintmax_t max_iter=500;
	    // tolerance is number of bits
	    boost::math::tools::eps_tolerance<double> tol(8);
	    std::pair<double, double> dtInterval;
	    dtInterval.first=0.;
	    dtInterval.second=SMALL_TIME;
		try {
			dtInterval = boost::math::tools::toms748_solve(minimumBasisFunction, 0.,
						dtAtWhichNegative, tol, max_iter);
//				boost::math::tools::toms748_solve(minimumBasisFunction, SMALL_TIME,
//						dtAtWhichNegative, tol, max_iter);
		} catch (...) {
			cout << "toms748 failed to find root." << endl;
		}
//	    dt = dtInterval.first;
	    // TODO: find better way to ensure next point is not in same region
	    dt = dtInterval.second+SMALL_TIME;
//	    double additionalDtToExitRegion = (dtInterval.second-dtInterval.first);
	    double additionalDtToExitRegion = 0.;
		// TODO: debugging
//		cout << minimumBasisFunction(dt) << endl;
//		cout << minimumBasisFunction(dt+additionalDtToExitRegion) << endl << endl;
	    t += dt;
		nSteps++;
//		// TODO: debugging
//		cout << nSteps << " : " << t << endl;
//		cout << positionAndVelocity[0].transpose() << endl;
		// TODO: DriftStepper::do_step() should not throw, but others might...
		try {
			timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, dt);
		} catch (...) {
			cout << "Failed to step out of tet." << endl;
		}
		currentPosition = positionAndVelocity[0];
		currentVelocity = positionAndVelocity[1];
//		// TODO: debugging
//		cout << positionAndVelocity[0].transpose() << endl;
//		timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, -dt);
//		cout << positionAndVelocity[0].transpose() << endl;
//		timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, dt/2.);
//		cout << positionAndVelocity[0].transpose() << endl;
//		timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, dt/2.);
//		cout << positionAndVelocity[0].transpose() << endl;

	    dt = additionalDtToExitRegion;
		t+=dt;
		if (isnan(currentPosition.norm()))
				throw string("currentPosition is NaN in Orbit.cpp");
		vect3d previousPosition = currentPosition;
		vect3d previousVelocity = currentVelocity;
		entHandle previousElement = velocityAndAcceleration.currentElement;
//		currentPosition += dt*currentVelocity;
//		vect3d currentAcceleration(0.,0.,0.);
//		// TODO: replace this hack
//		if (t==0.) {
//			currentElement = mesh_ptr->findTet(previousPosition,
//					currentPosition, initialNode, &foundTet, false);
//			// TODO: figure out why sometimes throw here (grazing orbits?)
////			if (!foundTet)
////				throw;
//			int dimension=mesh_ptr->getEntityDimension(currentElement);
//			if (dimension!=iBase_REGION)
//				foundTet = false;
//		}
////		if (!foundTet)
////			break;
//		if (foundTet) {
			try {
				positionAndVelocity[0] = currentPosition;
				positionAndVelocity[1] = currentVelocity;
				// TODO: debugging
//				cout << minimumBasisFunction(SMALL_TIME) << endl;
//				cout << minimumBasisFunction(dt) << endl << endl;
				timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t, dt);
//				// TODO: always exit with small time-step to minimize energy error...do better?
//				timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t+dt,
//						additionalDtToExitRegion);
				// TODO: replace this hack to update currentElement?
				timestepper.do_step(boost::ref(velocityAndAcceleration), positionAndVelocity, t+dt, SMALL_TIME);
//				// TODO: figure out why inout arg leads to problems
//				//		 (Eigen not liking certain optimization tricks in odeint?.
				//		 Actually, just missing initialization)
//				timestepper.do_step(boost::ref(velocityAndAcceleration),
//						positionAndVelocity, t, positionAndVelocityOut, dt);
//				positionAndVelocity[0] = positionAndVelocityOut[0];
//				positionAndVelocity[1] = positionAndVelocityOut[1];
//				timestepper.do_step(velocityAndAcceleration, positionAndVelocity, t, dt);
				currentPosition = positionAndVelocity[0];
				currentVelocity = positionAndVelocity[1];
				currentElement = velocityAndAcceleration.currentElement;
				if (currentElement==previousElement)
					throw string("Did not step to new element...something is wrong.");
				// TODO: change this to use regionIndex
				foundTet = mesh_ptr->checkIfInTet(currentPosition, currentElement);
				if (!foundTet) {
					// TODO: figure out why sometimes lose track of tet
					throw int(OUTSIDE_DOMAIN);
//					currentElement = mesh_ptr->findTet(previousPosition, currentPosition,
//							currentElement, &foundTet);
				}
//				finalEnergy = 0.5*pow(currentVelocity.norm(),2.)
//					+ charge*potentialField.getField(currentPosition);
				// TODO: this doesn't account for final step, but as long as boundary
				//       is at potential zero it shouldn't matter for orbits with non-zero weight
				//       (actually, am using finalPotential later)
				driftPotential = extern_E.dot(currentPosition);
				currentPotential = velocityAndAcceleration.currentPotential;
				currentPotential += driftPotential;
				currentEnergy = 0.5*pow((currentVelocity+extern_VEXB).norm(),2.)
//				currentEnergy = 0.5*pow(currentVelocity.norm(),2.)
//					+ charge*velocityAndAcceleration.currentPotential;
					+ charge*(currentPotential);
//				// TODO: set order through input parameter?
//				int interpolationOrder = INTERPOLATIONORDER;
////				currentAcceleration = charge*
////						electricField.getField(currentPosition, &currentElement);
//				potential = potentialField.getField(currentPosition, &currentElement,
//						interpolationOrder);
//				if (isnan(potential))
//					potential = potentialField.getField(currentPosition,
//							&currentElement, 1);
//				// TODO: hard-coding dimension here...
//				for (int i=0; i<3; i++) {
//					vect3d perturbedPosition = currentPosition +
//							vect3d::Unit(i)*DELTA_LENGTH;
//					double perturbedPotential = potentialField.getField(
//							perturbedPosition, &currentElement, interpolationOrder);
//					// TODO: track down why perturbedPotential sometimes is NaN
////					cout << "calculation of error term succeeded." <<
////							i << " " << currentElement << endl;
//					if (isnan(perturbedPotential)) {
//						perturbedPotential = potentialField.getField(
//								perturbedPosition, &currentElement, 1);
//						cout << "calculation of error term failed." <<
//								i << " " << currentElement << endl;
//					}
////					if (isnan(potential) || isnan(perturbedPotential)) {
////						cout << potential << " " << perturbedPotential <<
////						" " << currentPosition.transpose() << endl;
////						throw;
////					}
//					currentAcceleration[i] =
//							-charge*(perturbedPotential-potential)/DELTA_LENGTH;
//				}
			} catch (int signal) {
				switch (signal) {
				case OUTSIDE_DOMAIN:
					foundTet = false;
					// TODO: not guaranteed that outside domain (since different than stepper)
					// TODO: Revisit this in magnetized case
//					currentPosition += dt*currentVelocity;
					currentPosition = positionAndVelocity[0];
					currentVelocity = positionAndVelocity[1];
					break;
				default:
					// TODO: handle other exceptions?
					throw;
					break;
				}
			} catch (...) {
				// TODO: handle other exceptions?
				throw;
			}
//		}

		if (foundTet==false) {
			// TODO: if near vertex could leave domain through non-boundary face
			//       by crossing sliver of other tet in one time-step
//			entHandle faceCrossed = mesh_ptr->findFaceCrossed(
//					previousElement, previousPosition, currentPosition);
			int faceCrossedIndex = mesh_ptr->findBoundaryFaceCrossed(
					mesh_ptr->indicesOfEntities[previousElement],
					previousPosition, currentPosition,
					faceTypeField, vertexTypeField);
			entHandle faceCrossed = NULL;
			if (faceCrossedIndex>=0) {
				faceCrossed = mesh_ptr->entitiesVectors[iBase_FACE][faceCrossedIndex];
			}
			// TODO: grazing orbits don't enter domain in first time-step
			int faceType;
			vect3d normalVector(0.,0.,0.), normalVelocity(0.,0.,0.);
			if (faceCrossed!=NULL) {
				faceType = faceTypeField.getField(faceCrossed);
				normalVector = mesh_ptr->getNormalVector(faceCrossed,
								previousPosition);
				normalVelocity =
						currentVelocity.dot(normalVector)*normalVector;
//				// TODO: debugging
//				if (extern_orbitNumber==15) {
//					cout << currentPotential << endl;
//				}
//				finalPotential = 0.;
//				vector<entHandle> vertices =
//						mesh_ptr->getVertices(faceCrossed);
//				for (int i=0; i<vertices.size(); i++) {
//					// TODO: should use point where left domain here
//					finalPotential += 1./3.*potentialField.getField(vertices[i]);
//				}
//				// TODO: debugging
//				if (extern_orbitNumber==15) {
//					cout << finalPotential << endl;
//				}
				vect3d exitPosition;
				vector<vect3d> vertexVectors =
						mesh_ptr->getVertexVectors(faceCrossed);
				// TODO: straight line intersection may not be accurate for magnetized orbits
				mesh_ptr->checkIfIntersectsTriangle(previousPosition,
						currentPosition, vertexVectors, &exitPosition);
				vect3d centroid(0.,0.,0.);
//				vector<vect3d> vVs = mesh_ptr->getVertexVectors(i,iBase_REGION);
//				centroid = (vVs[0]+vVs[1]+vVs[2]+vVs[3])/4.;
//				vect3d interiorDirection=centroid-exitPosition;
//				interiorDirection /= interiorDirection.norm();
				// TODO: Don't hard-code this correction
//				exitPosition += sqrt(LENGTH_TOLERANCE)*interiorDirection;
				exitPosition -= sqrt(LENGTH_TOLERANCE)*normalVector;
				// TODO: figure out why this fails with interpolationorder=1
//				currentPotential = potentialField.getField(exitPosition);
				// TODO: for consistency should strictly evaluate everything at exitPosition
//				driftPotential = E.dot(currentPosition);
//				currentPotential += driftPotential;
//				currentEnergy = 0.5*pow((currentVelocity+VEXB).norm(),2.)
////				currentEnergy = 0.5*pow(currentVelocity.norm(),2.)
//					+ charge*currentPotential;
				finalPotential = currentPotential;
				finalEnergy = currentEnergy;
//				// TODO: debugging
//				if (extern_orbitNumber==15) {
//					cout << finalPotential << endl;
////					cout << previousPosition.transpose() << endl;
////					cout <<	exitPosition.transpose() << endl;
////					cout << currentPosition.transpose() << endl;
////					cout << potentialField.getField(previousPosition) << endl;
////					cout <<	potentialField.getField(exitPosition) << endl;
//				}
				// TODO: shouldn't hard-code boundary code
			} else {
				faceType = 0;
			}
//			if (faceType==0) {
//				cout << previousElement << " " <<
//						faceCrossed << " " << currentPosition.norm() <<
//						" " << previousPosition.norm() << endl;
//			}
			finalFaceType = faceType;
			// TODO: need to account for shielding potential here
			if (faceType==4 && 0.5*pow(normalVelocity.norm(),2.)<charge*phiSurface) {
				currentElement = previousElement;
				foundTet = true;
				// TODO: resetting position isn't quite right
				currentPosition = previousPosition;
				// TODO: revisit this in magnetized case
				// TODO: calc this from previousVelocity?
				currentVelocity -= 2.*normalVelocity;
			} else {
//				if (faceType==0)
//					cout << "last face crossed was an interior one" << endl;
				endLoop=true;
			}
		}

//		if (nSteps==1 && !foundTet) {
//			cout << currentPosition.transpose() << " " <<
//					currentVelocity.transpose() << " " <<
//					currentPosition.dot(currentVelocity) << endl;
//		}

//		double eFieldR = currentAcceleration.dot(currentPosition)/
//				currentPosition.norm();
////		 // TODO: comment out this
////		currentAcceleration = -charge*currentPosition/
////				pow(currentPosition.norm(),3.);
//		currentVelocity += dt*currentAcceleration;
//		vect3d velocityAtPosition = currentVelocity - 1./2.*dt*currentAcceleration;
//		double energy = 1./2.*pow(velocityAtPosition.norm(),2.) + charge*potential;
//		if (foundTet) {
//			potential = potentialField.getField(currentPosition,
//					&velocityAndAcceleration.currentElement,
//					velocityAndAcceleration.interpolationOrder);
//		} else {
			potential = 0.;
//		}
//		assert(currentPosition.norm()<10.);
		double energy = 0.;
//		double energy = 1./2.*pow(currentVelocity.norm(),2.) + charge*finalPotential;
		if (outFile) {
//		if (outFile && (extern_orbitNumber==15 || extern_orbitNumber==790)) {
//			fprintf(outFile, "%f %f %f %p\n", currentPosition[0], currentPosition[1],
//					currentPosition[2], (void*)currentElement);
			// TODO: fix occasional very large coordinate values
//			// TODO: comment this out unless using spheres mesh
//			if (currentPosition.norm()<=5.)
//			fprintf(outFile, "%f %f %f %d\n", currentPosition[0], currentPosition[1],
//					currentPosition[2], extern_orbitNumber);
			fprintf(outFile, "%f %f %f %f\n", currentPosition[0], currentPosition[1],
//					currentPosition[2], currentEnergy);
//					currentPosition[2], currentPotential);
//					currentPosition[2], 0.5*pow((currentVelocity+VEXB).norm(),2.));
//					currentPosition[2], eFieldR);
					currentPosition[2], orbitLabelValue);
		}
		if (endLoop)
			break;
	}
	} else { // !foundTet
		// TODO: check that only get here if starting from node on boundary
		finalFaceType = vertexTypeField.getField(initialNode);
		finalPotential = potentialField.getField(initialNode);
	}
//	cout << "Final radius=" << currentPosition.norm() << " nSteps=" <<
//			nSteps << "faceType =" << finalFaceType << endl;
	finalPosition = currentPosition;
	// TODO: correct for time-step offset?
	finalVelocity = currentVelocity;
	// TODO: debugging
	double fractionalEnergyChange = (finalEnergy-initialEnergy)/initialEnergy;
//	if (fabs(fractionalEnergyChange) > 0.0 && finalPotential-driftPotential > -1.) {
//	if (fabs(fractionalEnergyChange) > 0.0 && finalPotential > -1.) {
//		cout << fractionalEnergyChange << " energy change for orbit " <<
//				extern_orbitNumber << " : " << finalPotential << " / " <<
//				initialPotential <<	" " << finalVelocity.norm() << " / " <<
//				initialVelocity.norm() <<	" " << finalEnergy << " / " <<
//				initialEnergy << endl;
//	}
}
Пример #16
0
void
Lattice2d_mt :: computeInternalSourceRhsVectorAt(FloatArray &answer, TimeStep *atTime, ValueModeType mode)
{
    int i, j, n, nLoads;
    double dV;
    bcGeomType ltype;
    Load *load;
    IntegrationRule *iRule = integrationRulesArray [ 0 ];
    GaussPoint *gp;
    Node *nodeA, *nodeB;


    FloatArray deltaX(3), normalVector(3);
    FloatArray val, helpLoadVector, globalIPcoords;
    FloatMatrix nm;
    double k;
    answer.resize(0);

    FloatArray gravityHelp(2);

    nLoads    = this->giveBodyLoadArray()->giveSize();
    for ( i = 1; i <= nLoads; i++ ) {
        n     = bodyLoadArray.at(i);
        load  = ( Load * ) domain->giveLoad(n);
        ltype = load->giveBCGeoType();

        if ( ltype == GravityPressureBGT ) {
            //Compute change of coordinates
            nodeA   = this->giveNode(1);
            nodeB   = this->giveNode(2);
            deltaX.at(1) = nodeB->giveCoordinate(1) - nodeA->giveCoordinate(1);
            deltaX.at(2) = nodeB->giveCoordinate(2) - nodeA->giveCoordinate(2);
            deltaX.at(3) = nodeB->giveCoordinate(2) - nodeA->giveCoordinate(2);

            //Compute the local coordinate system
            gp  = iRule->getIntegrationPoint(0);

            gravityHelp.at(1) = 1.;
            gravityHelp.at(2) = -1.;

            dV  = this->computeVolumeAround(gp);
            load->computeValueAt(val, atTime, deltaX, mode);

            k = static_cast< TransportMaterial * >( this->giveMaterial() )->giveCharacteristicValue(Conductivity_hh, gp, atTime);

            double helpFactor = val.at(1) * k * dV;

            helpFactor /= pow(this->giveLength(), 2.);
            gravityHelp.times(helpFactor);

            if ( helpLoadVector.isEmpty() ) {
                helpLoadVector.resize( gravityHelp.giveSize() );
            }

            for ( j = 1; j <= gravityHelp.giveSize(); j++ ) {
                helpLoadVector.at(j) += gravityHelp.at(j);
            }
        }

        answer.add(helpLoadVector);
    }

    return;
}