Example #1
0
Vector3D<float> Tank::getBulletDirection()
{
    float ySin = sin(TO_RADIANS(mHeadRotation));
    float yCos = cos(TO_RADIANS(mHeadRotation));

    Vector3D<float> direction(ySin, 0.0f, yCos);
    return direction;
}
Example #2
0
// x, z -> new x and z rotated theta around y axis
// theta in degrees
void rotate2d(float &x, float &z, const float theta) {
   float x1, z1;
   const float cos_th = cos(TO_RADIANS(theta));
   const float sin_th = sin(TO_RADIANS(theta));
   x1 = x * cos_th - z * sin_th;
   z1 = x * sin_th + z * cos_th;
   x = x1;
   z = z1;
}
Example #3
0
Vector3D<float> Tank::getBulletStart()
{
    float ySin = sin(TO_RADIANS(mHeadRotation));
    float yCos = cos(TO_RADIANS(mHeadRotation));

    float oldZ = mTurretCenter[2] + mTurretSize[2];
    float x = oldZ * ySin;
    float z = oldZ * yCos;

    x += mPosition[0];
    z += mPosition[2];

    Vector3D<float> position(x, mPosition[1] + mHeadCenter[1], z);

    return position;
}
Vector2 Vector2::rotate(float angle)
{
	double rad = TO_RADIANS(angle);
	double cosine = cos(rad);
	double sine = sin(rad);

	return Vector2(x * cosine - y * sine, x * sine + y * cosine);
}
Example #5
0
void Frustum::render() const
{
    if( type == Projection::PERSPECTIVE ) {
        static float vert[9 * 3];
        static vec3 p[8];

        vert[0] = origin.x;
        vert[1] = origin.y;
        vert[2] = origin.z;

        vec3 n = glm::normalize(this->origin - this->at);
        vec3 u = glm::normalize(glm::cross(this->up, n));
        vec3 v = glm::normalize(glm::cross(n, u));

        float dy = mNear * tanf( (float)TO_RADIANS(fovy) / 2.0f );
        float dx = ar * dy;
        vec3 c = origin - n * mNear;  // Center of near plane
        p[0] = c + u * dx + v * dy;
        p[1] = c - u * dx + v * dy;
        p[2] = c - u * dx - v * dy;
        p[3] = c + u * dx - v * dy;
        dy = mFar * tanf( (float)TO_RADIANS(fovy) / 2.0f );
        dx = ar * dy;
        c = origin - n * mFar;      // Center of far plane
        p[4] = c + u * dx + v * dy;
        p[5] = c - u * dx + v * dy;
        p[6] = c - u * dx - v * dy;
        p[7] = c + u * dx - v * dy;

        int idx = 3;
        for( int i = 0; i < 8 ; i++ ) {
            vert[idx++] = p[i].x;
            vert[idx++] = p[i].y;
            vert[idx++] = p[i].z;
        }

        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, handle[0]);
        glBufferData(GL_ARRAY_BUFFER, 9 * 3 * sizeof(float), vert, GL_DYNAMIC_DRAW);
        glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
        glEnableVertexAttribArray(0);  // Vertex position

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[1]);
        glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0);
    }
}
void RendererBase::loadScene()
{
	m_camera->setPosDir(glm::vec3(0.0f, 5.0f, 0.0f), glm::vec2(TO_RADIANS(175.0f), 0.0f));


	ModelObject *ground = new ModelObject(&m_modelCube);
	ground->scale(glm::vec3(200.0f, 1.0f, 200.0f));
	ground->pos(glm::vec3(0.0f, 0.0f, 0.0f));

	m_modelObjects.push_back(ground);

	int index = 0;
	for (int x = 0; x < 8; x++) {
		for (int y = 0; y < 8; y++) {
			LightPoint *lp = new LightPoint;
			lp->position = glm::vec3(-10.0f + (x*  12 ), 5.0f, -20.0f + (y*  12 ));

			ModelObject *teapot = new ModelObject(&m_modelTeapot);
			teapot->scale(glm::vec3(20.0f, 20.0f, 20.0f));
			teapot->pos(glm::vec3(lp->position.x-1.0f,
								  0.5f,
								  lp->position.z));

			m_pointLights.push_back(lp);

			m_modelObjects.push_back(teapot);
		}
	}
	
	// Textures
	m_textureGround.load("Ground_SmoothRocks_1k_d.tga", 16);
	m_textureGround.setTextTile(50.0f);
	m_textureGround.setKd(glm::vec3(1.0f));
	m_textureGround.setShininess(100.0f);
	m_textureGround.setSpec(0.1f);

	m_textureTeapot.load("Metal_WallPanel_1k_d.tga", 16);
	m_textureTeapot.setTextTile(4.0f);
	m_textureTeapot.setKd(glm::vec3(1.0f));
	m_textureTeapot.setShininess(100.0f);
	m_textureTeapot.setSpec(2.7f);

	
	m_textureColorTerrain.setKd(glm::vec3(0.0f, 0.0f, 1.0f));
	m_textureColorTerrain.setShininess(100.0f);
	m_textureColorTerrain.setSpec(2.7f);

	std::vector<glm::vec3> verticesList;
	std::vector<glm::vec3> normalsList;
	std::vector<glm::vec2> tcList;
	std::vector<GLushort> indices;

	CreateCube(1, verticesList, normalsList, tcList, indices);
	m_terrainCube.fillVertecies(verticesList, normalsList, tcList, indices);

	m_terrainCube.pos(glm::vec3(0.0f, 1.0f, 0.0f));
	m_terrainCube.scale(glm::vec3(4.0f));
}
Example #7
0
void Viewer::setPerspective(float fovy, float ratio, float znear, float zfar)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	// fovy in degree
	float right = znear * tan(TO_RADIANS(fovy/2.0));
	float top = ratio * right;
	glFrustum(-right,right,-top,top,znear,zfar);
	glMatrixMode(GL_MODELVIEW_MATRIX);
}
    void Camera::smartPan(float inX, float inY)
    {
         float theta = TO_RADIANS(mRotation);
         float c = cos(theta);
         float s = sin(theta);

         float dxp = c * inX;
         float dyp = -s * inX;
         dxp += s * inY;
         dyp += c * inY;

         mPosition[0] += dxp;
         mPosition[1] += dyp;
    }
Example #9
0
int main() {
    double i_abc[3], i_alfabeta[2], i_dq[2];
    double i_alfabeta_prime[2], i_dq_prime[2];
    motor_err_t err;

    double theta;
    int i;


    //open loop simulation
    i_dq[ID]=0.0;
    i_dq[IQ]=1.0; //1 Amp for example

    printf("Header\n");
    printf("i, theta, id, iq, ialfa, ibeta, ia, ib, ic, ialfa_prime, ibeta_prime, id_prime, iq_prime\n");
    for (i=0; i<360; i++) {
        theta = TO_RADIANS(i);

        err = Convert_dq_to_alfabeta(i_dq, theta, i_alfabeta);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_alfabeta_to_abc(i_alfabeta, i_abc);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_abc_to_alfabeta(i_abc, i_alfabeta_prime);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_alfabeta_to_dq(i_alfabeta_prime, theta, i_dq_prime);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        printf("%d, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f\n",
               i, theta,
               i_dq[ID], i_dq[IQ],
               i_alfabeta[IALFA], i_alfabeta[IBETA],
               i_abc[IA], i_abc[IB], i_abc[IC],
               i_alfabeta_prime[IALFA], i_alfabeta_prime[IBETA],
               i_dq_prime[ID], i_dq_prime[IQ]);
    }
    return 0;
}
Example #10
0
void Tank::changeMovementVector()
{
    mMomentum[0] = sin(TO_RADIANS(mRotation[1])) * mCurrentMoveRate;
    mMomentum[2] = cos(TO_RADIANS(mRotation[1])) * mCurrentMoveRate;
}
Example #11
0
/**************************************************
*   Calculates one step for the tank based on its
*   movement and rotation vectors.  It then works out
*   how that movement affects its orientation on the
*   terrain and runs it against the collision engine.
*
*   This function should be written as procedurally as possible
*   because it is called every frame for every tank.
**************************************************/
void Tank::move()
{
    mRotation[1] += mCurrentRotationRate;

    float ySin = sin(TO_RADIANS(mRotation[1]));
    float yCos = cos(TO_RADIANS(mRotation[1]));

    Vector3D<float> driveMomentum;

    driveMomentum[0] = ySin * mCurrentMoveRate;
    driveMomentum[2] = yCos * mCurrentMoveRate;

    Vector3D<float> newPosition = mPosition + driveMomentum;


    if (mTurretConstantRotate)
    {
        mHeadRotation += mHeadRotationDirection;
    }

    if (mAIRotateCalled)
    {
        if (abs(mHeadRotation - mHeadTargetDirection) < mHeadRotationRate)
        {
            mHeadRotation = mHeadTargetDirection;
            mHeadTargetDirection = mHeadRotation;
        }
        else
        {
            mHeadRotation += mHeadRotationDirection;
            mHeadTargetDirection -= mHeadRotationRate;
        }
    }


    //transform the four control points to determine how the tank should sit
    //on the terrrain
    mTransformedBackLeftControl = mBackLeftControl;
    mTransformedBackRightControl = mBackRightControl;
    mTransformedFrontLeftControl = mFrontLeftControl;
    mTransformedFrontRightControl = mFrontRightControl;


    mTransformedFrontLeftControl[0] = mFrontLeftControl[0] * yCos + mFrontLeftControl[2] * ySin;
    mTransformedFrontLeftControl[2] = mFrontLeftControl[0] * -ySin + mFrontLeftControl[2] * yCos;
    mTransformedFrontLeftControl[0] += newPosition[0];
    mTransformedFrontLeftControl[2] += newPosition[2];
    mTransformedFrontLeftControl[1]
        += mTerrain->findHeight(mTransformedFrontLeftControl[0],
        mTransformedFrontLeftControl[2]) + mTankSize[1] / 2.0;
    float highestControlPoint = mTransformedFrontLeftControl[1];
    float lowestControlPoint = mTransformedFrontLeftControl[1];

    mTransformedFrontRightControl[0] = mFrontRightControl[0] * yCos + mFrontRightControl[2] * ySin;
    mTransformedFrontRightControl[2] = mFrontRightControl[0] * -ySin + mFrontRightControl[2] * yCos;
    mTransformedFrontRightControl[0] += newPosition[0];
    mTransformedFrontRightControl[2] += newPosition[2];
    mTransformedFrontRightControl[1]
        += mTerrain->findHeight(mTransformedFrontRightControl[0],
        mTransformedFrontRightControl[2]) + mTankSize[1] / 2.0;

    if (mTransformedFrontRightControl[1] > highestControlPoint)
    {
        highestControlPoint = mTransformedFrontRightControl[1];
    }
    else if (mTransformedFrontRightControl[1] < lowestControlPoint)
    {
        lowestControlPoint = mTransformedFrontRightControl[1];
    }

    mTransformedBackLeftControl[0] = mBackLeftControl[0] * yCos
        + mBackLeftControl[2] * ySin;
    mTransformedBackLeftControl[2] = mBackLeftControl[0] * -ySin
        + mBackLeftControl[2] * yCos;
    mTransformedBackLeftControl[0] += newPosition[0];
    mTransformedBackLeftControl[2] += newPosition[2];
    mTransformedBackLeftControl[1]
        += mTerrain->findHeight(mTransformedBackLeftControl[0],
        mTransformedBackLeftControl[2]) + mTankSize[1] / 2.0;

    if ( mTransformedBackLeftControl[1] > highestControlPoint)
    {
        highestControlPoint = mTransformedBackLeftControl[1];
    }
    else if (mTransformedBackLeftControl[1] < lowestControlPoint)
    {
        lowestControlPoint = mTransformedBackLeftControl[1];
    }

    mTransformedBackRightControl[0] = mBackRightControl[0] * yCos + mBackRightControl[2] * ySin;
    mTransformedBackRightControl[2] = mBackRightControl[0] * -ySin + mBackRightControl[2] * yCos;
    mTransformedBackRightControl[0] += newPosition[0];
    mTransformedBackRightControl[2] += newPosition[2];
    mTransformedBackRightControl[1]
        += mTerrain->findHeight(mTransformedBackRightControl[0],
        mTransformedBackRightControl[2]) + mTankSize[1] / 2.0;

    if (mTransformedBackRightControl[1] > highestControlPoint)
    {
        highestControlPoint = mTransformedBackRightControl[1];
    }
    else if (mTransformedBackRightControl[1] < lowestControlPoint)
    {
        lowestControlPoint = mTransformedBackRightControl[1];
    }

    //use the transformed control points to determine what angle the tank should sit at
    float zFront = atan((mTransformedFrontLeftControl[1] - mTransformedFrontRightControl[1]) / mTankSize[0]);
    float zBack = atan((mTransformedBackLeftControl[1] - mTransformedBackRightControl[1]) / mTankSize[0]);
    mRotation[2] = (abs(zFront) > abs(zBack)) ? TO_DEGREES(zFront)
        : TO_DEGREES(zBack);

    float xLeft = atan(( mTransformedBackLeftControl[1] - mTransformedFrontLeftControl[1]) / mTankSize[0]);
    float xRight = atan(( mTransformedBackRightControl[1] - mTransformedFrontRightControl[1]) / mTankSize[0]);
    mRotation[0] = (abs(xLeft) > abs(xRight)) ? TO_DEGREES(xLeft)
        : TO_DEGREES(xRight);

    //set the position to the highest of the four control points
    mPosition[1] = (highestControlPoint + lowestControlPoint) / 2.0
        + mTankSize[1] / 2.0;

    mPreviousPosition = mPosition;

    float friction = mTerrain->getFriction(mPosition[0], mPosition[2]);
    float cmr = fabs(mCurrentMoveRate);

    driveMomentum *= friction;
    mMomentum *= (1.0f - friction);
    if (mMomentum.isZero()) mMomentum.set(0.0f);

    float magnitude = mMomentum.length();
    mMomentum += driveMomentum;
    if (mMomentum.length() > cmr)
    {
        mMomentum.normalizeTo(magnitude > cmr ? magnitude : cmr);
    }

    mPosition += mMomentum;

    if (mPosition[0] < 1.25)
    {
        mPosition[0] = 1.25;
    }
    else if (mPosition[0] > mTerrainWidth - 2.25)
    {
        mPosition[0] = mTerrainWidth - 2.25;
    }

    if (mPosition[2] < 1.25)
    {
        mPosition[2] = 1.25;
    }
    else if (mPosition[2] > mTerrainHeight - 2.25)
    {
        mPosition[2] = mTerrainHeight - 2.25;
    }

}
Example #12
0
void Frustum::enclose( const Frustum & other )
{
    vec3 n = glm::normalize(other.origin - other.at);
    vec3 u = glm::normalize(glm::cross(other.up, n));
    vec3 v = glm::normalize(glm::cross(n, u));
    if( type == Projection::PERSPECTIVE )
        this->orient( origin, other.getCenter(), up );
    mat4 m = this->getViewMatrix();

    vec3 p[8];

    // Get 8 points that define the frustum
    if( other.type == Projection::PERSPECTIVE ) {
        float dy = other.mNear * tanf( (float)TO_RADIANS(other.fovy) / 2.0f );
        float dx = other.ar * dy;
        vec3 c = other.origin - n * other.mNear;
        p[0] = c + u * dx + v * dy;
        p[1] = c - u * dx + v * dy;
        p[2] = c - u * dx - v * dy;
        p[3] = c + u * dx - v * dy;
        dy = other.mFar * tanf( (float)TO_RADIANS(other.fovy) / 2.0f );
        dx = other.ar * dy;
        c = other.origin - n * other.mFar;
        p[4] = c + u * dx + v * dy;
        p[5] = c - u * dx + v * dy;
        p[6] = c - u * dx - v * dy;
        p[7] = c + u * dx - v * dy;
    } else {
        vec3 c = other.origin - n * other.mNear;
        p[0] = c + u * other.xmax + v * other.ymax;
        p[1] = c + u * other.xmax + v * other.ymin;
        p[2] = c + u * other.xmin + v * other.ymax;
        p[3] = c + u * other.xmin + v * other.ymin;
        c = other.origin - n * other.mFar;
        p[4] = c + u * other.xmax + v * other.ymax;
        p[5] = c + u * other.xmax + v * other.ymin;
        p[6] = c + u * other.xmin + v * other.ymax;
        p[7] = c + u * other.xmin + v * other.ymin;
    }

    // Adjust frustum to contain
    if( type == Projection::PERSPECTIVE ) {
        fovy = 0.0f;
        mFar = 0.0f;
        mNear = std::numeric_limits<float>::max();
        float maxHorizAngle = 0.0f;
        for( int i = 0; i < 8; i++) {
            // Convert to local space
            vec4 pt = m * vec4(p[i],1.0f);

            if( pt.z < 0.0f ) {
                float d = -pt.z;
                float angle = atanf( fabs(pt.x) / d );
                if( angle > maxHorizAngle ) maxHorizAngle = angle;
                angle = (float)TO_DEGREES( atanf( fabs(pt.y) / d ) );
                if( angle * 2.0f > fovy ) fovy = angle * 2.0f;
                if( mNear > d ) mNear = d;
                if( mFar < d ) mFar = d;
            }
        }
        float h = ( mNear * tanf( (float)TO_RADIANS(fovy)/ 2.0f) ) * 2.0f;
        float w = ( mNear * tanf( maxHorizAngle ) ) * 2.0f;
        ar = w / h;
    } else {
        xmin = ymin = mNear = std::numeric_limits<float>::max();
        xmax = ymax = mFar = std::numeric_limits<float>::min();
        for( int i = 0; i < 8; i++) {
            // Convert to local space
            vec4 pt = m * vec4(p[i],1.0f);
            if( xmin > pt.x ) xmin = pt.x;
            if( xmax < pt.x ) xmax = pt.x;
            if( ymin > pt.y ) ymin = pt.y;
            if( ymax < pt.y ) ymax = pt.y;
            if( mNear > -pt.z ) mNear = -pt.z;
            if( mFar < -pt.z ) mFar = -pt.z;
        }
    }

}
Example #13
0
Icing::Icing(const CIwFVec2 position, Game* game, Player* owner) : owner(owner), scale(0.02f), finalScale(.12f), WorldObject(position, game)  { 
	angle = TO_RADIANS(IwRandMinMax(0, 360));
	texture_names.push_back(IwHashString("icing"));
}
Example #14
0
DMZ_INTERNAL CvLinePolar llcv_hough(const CvArr *src_image, IplImage *dx, IplImage *dy, float rho, float theta, int threshold, float theta_min, float theta_max, bool vertical, float gradient_angle_threshold) {
    CvMat img_stub, *img = (CvMat*)src_image;
    img = cvGetMat(img, &img_stub);

    CvMat dx_stub, *dx_mat = (CvMat*)dx;
    dx_mat = cvGetMat(dx_mat, &dx_stub);

    CvMat dy_stub, *dy_mat = (CvMat*)dy;
    dy_mat = cvGetMat(dy_mat, &dy_stub);

    if(!CV_IS_MASK_ARR(img)) {
      CV_Error(CV_StsBadArg, "The source image must be 8-bit, single-channel");
    }

    if(rho <= 0 || theta <= 0 || threshold <= 0) {
      CV_Error(CV_StsOutOfRange, "rho, theta and threshold must be positive");
    }

    if(theta_max < theta_min + theta) {
      CV_Error(CV_StsBadArg, "theta + theta_min (param1) must be <= theta_max (param2)");
    }

    cv::AutoBuffer<int> _accum;
    cv::AutoBuffer<int> _tabSin, _tabCos;

    const uchar* image;
    int step, width, height;
    int numangle, numrho;
    float ang;
    int r, n;
    int i, j;
    float irho = 1 / rho;
    float scale;

    CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );

    image = img->data.ptr;
    step = img->step;
    width = img->cols;
    height = img->rows;

    const uint8_t *dx_mat_ptr = (uint8_t *)(dx_mat->data.ptr);
    int dx_step = dx_mat->step;
    const uint8_t *dy_mat_ptr = (uint8_t *)(dy_mat->data.ptr);
    int dy_step = dy_mat->step;

    numangle = cvRound((theta_max - theta_min) / theta);
    numrho = cvRound(((width + height) * 2 + 1) / rho);

    _accum.allocate((numangle+2) * (numrho+2));
    _tabSin.allocate(numangle);
    _tabCos.allocate(numangle);
    int *accum = _accum;
    int *tabSin = _tabSin, *tabCos = _tabCos;
    
    memset(accum, 0, sizeof(accum[0]) * (numangle + 2) * (numrho + 2));

#define FIXED_POINT_EXPONENT 10
#define FIXED_POINT_MULTIPLIER (1 << FIXED_POINT_EXPONENT)

    for(ang = theta_min, n = 0; n < numangle; ang += theta, n++) {
        tabSin[n] = (int)floorf(FIXED_POINT_MULTIPLIER * sinf(ang) * irho);
        tabCos[n] = (int)floorf(FIXED_POINT_MULTIPLIER * cosf(ang) * irho);
    }

    float slope_bound_a, slope_bound_b;
    if(vertical) {
        slope_bound_a = tanf((float)TO_RADIANS(180 - gradient_angle_threshold));
        slope_bound_b = tanf((float)TO_RADIANS(180 + gradient_angle_threshold));
    } else {
        slope_bound_a = tanf((float)TO_RADIANS(90 - gradient_angle_threshold));
        slope_bound_b = tanf((float)TO_RADIANS(90 + gradient_angle_threshold));
    }

    // stage 1. fill accumulator
    for(i = 0; i < height; i++) {
        int16_t *dx_row_ptr = (int16_t *)(dx_mat_ptr + i * dx_step);
        int16_t *dy_row_ptr = (int16_t *)(dy_mat_ptr + i * dy_step);
        for(j = 0; j < width; j++) {
            if(image[i * step + j] != 0) {
                int16_t del_x = dx_row_ptr[j];
                int16_t del_y = dy_row_ptr[j];

                bool use_pixel = false;

                if(dmz_likely(del_x != 0)) { // avoid div by 0
                  float slope = (float)del_y / (float)del_x;
                  if(vertical) {
                    if(slope >= slope_bound_a && slope <= slope_bound_b) {
                      use_pixel = true;
                    }
                  } else {
                    if(slope >= slope_bound_a || slope <= slope_bound_b) {
                      use_pixel = true;
                    }
                  }
                } else {
                  use_pixel = !vertical;
                }

                if(use_pixel) {
                    for(n = 0; n < numangle; n++) {
                        r = (j * tabCos[n] + i * tabSin[n]) >> FIXED_POINT_EXPONENT;
                        r += (numrho - 1) / 2;
                        accum[(n+1) * (numrho+2) + r+1]++;
                    }
                }
            }
        }
    }
Example #15
0
static void
gerber_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
		 Angle start_angle, Angle delta_angle)
{
  bool m = false;
  double arcStartX, arcStopX, arcStartY, arcStopY;

  /* we never draw zero-width lines */
  if (gc->width == 0)
    return;

  use_gc (gc, 0);
  if (!f)
    return;

  arcStartX = cx - width * cos (TO_RADIANS (start_angle));
  arcStartY = cy + height * sin (TO_RADIANS (start_angle));

  /* I checked three different gerber viewers, and they all disagreed
     on how ellipses should be drawn.  The spec just calls G74/G75
     "circular interpolation" so there's a chance it just doesn't
     support ellipses at all.  Thus, we draw them out with line
     segments.  Note that most arcs in pcb are circles anyway.  */
  if (width != height)
    {
      double step, angle;
      Coord max = width > height ? width : height;
      Coord minr = max - gc->width / 10;
      int nsteps;
      Coord x0, y0, x1, y1;

      if (minr >= max)
	minr = max - 1;
      step = acos((double)minr/(double)max) * 180.0/M_PI;
      if (step > 5)
	step = 5;
      nsteps = abs(delta_angle) / step + 1;
      step = (double)delta_angle / nsteps;

      x0 = arcStartX;
      y0 = arcStartY;
      angle = start_angle;
      while (nsteps > 0)
	{
	  nsteps --;
	  x1 = cx - width * cos (TO_RADIANS (angle+step));
	  y1 = cy + height * sin (TO_RADIANS (angle+step));
	  gerber_draw_line (gc, x0, y0, x1, y1);
	  x0 = x1;
	  y0 = y1;
	  angle += step;
	}
      return;
    }

  arcStopX = cx - width * cos (TO_RADIANS (start_angle + delta_angle));
  arcStopY = cy + height * sin (TO_RADIANS (start_angle + delta_angle));
  if (arcStartX != lastX)
    {
      m = true;
      lastX = arcStartX;
      print_xcoord (f, PCB, lastX);
    }
  if (arcStartY != lastY)
    {
      m = true;
      lastY = arcStartY;
      print_ycoord (f, PCB, lastY);
    }
  if (m)
    fprintf (f, "D02*");
  pcb_fprintf (f,
	   metric ? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" :
	   "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n",
	   (delta_angle < 0) ? 2 : 3,
	   gerberX (PCB, arcStopX), gerberY (PCB, arcStopY),
	   gerberXOffset (PCB, cx - arcStartX),
	   gerberYOffset (PCB, cy - arcStartY));
  lastX = arcStopX;
  lastY = arcStopY;
}