// File: rurban[P]dgnlib/dgnwrite.cpp
// Function: DGNCreateConeElem
DGNElemCore *
DGNCreateConeElem( DGNHandle hDGN,
                   double dfCenter_1X, double dfCenter_1Y,
                   double dfCenter_1Z, double dfRadius_1,
                   double dfCenter_2X, double dfCenter_2Y,
                   double dfCenter_2Z, double dfRadius_2,
                   int *panQuaternion )
{
    DGNElemCone *psCone;
    DGNElemCore *psCore;
    DGNInfo *psDGN = (DGNInfo *) hDGN;
    DGNPoint sMin, sMax, sCenter_1, sCenter_2;
    double dfScaledRadius;

    DGNLoadTCB( hDGN );

/* -------------------------------------------------------------------- */
/*      Allocate element.                                               */
/* -------------------------------------------------------------------- */
    psCone = (DGNElemCone *) CPLCalloc( sizeof(DGNElemCone), 1 );
    psCore = &(psCone->core);

    DGNInitializeElemCore( hDGN, psCore );
    psCore->stype = DGNST_CONE;
    psCore->type = DGNT_CONE;

/* -------------------------------------------------------------------- */
/*      Set cone specific information in the structure.                 */
/* -------------------------------------------------------------------- */
    sCenter_1.x = dfCenter_1X;
    sCenter_1.y = dfCenter_1Y;
    sCenter_1.z = dfCenter_1Z;
    sCenter_2.x = dfCenter_2X;
    sCenter_2.y = dfCenter_2Y;
    sCenter_2.z = dfCenter_2Z;
    psCone->center_1 = sCenter_1;
    psCone->center_2 = sCenter_2;
    psCone->radius_1 = dfRadius_1;
    psCone->radius_2 = dfRadius_2;

    memset( psCone->quat, 0, sizeof(int) * 4 );
    if( panQuaternion != NULL )
    {
        memcpy( psCone->quat, panQuaternion, sizeof(long)*4 );
    }
    else {
      psCone->quat[0] = 1 << 31;
      psCone->quat[1] = 0;
      psCone->quat[2] = 0;
      psCone->quat[3] = 0;
    }

/* -------------------------------------------------------------------- */
/*      Setup Raw data for the cone.                                    */
/* -------------------------------------------------------------------- */
    psCore->raw_bytes = 118;
    psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);

    /* unknown data */
    psCore->raw_data[36] = 0;
    psCore->raw_data[37] = 0;
    
    /* quaternion */
    DGN_WRITE_INT32( psCone->quat[0], psCore->raw_data + 38 );
    DGN_WRITE_INT32( psCone->quat[1], psCore->raw_data + 42 );
    DGN_WRITE_INT32( psCone->quat[2], psCore->raw_data + 46 );
    DGN_WRITE_INT32( psCone->quat[3], psCore->raw_data + 50 );

    /* center_1 */
    DGNInverseTransformPoint( psDGN, &sCenter_1 );
    memcpy( psCore->raw_data + 54, &sCenter_1.x, 8 );
    memcpy( psCore->raw_data + 62, &sCenter_1.y, 8 );
    memcpy( psCore->raw_data + 70, &sCenter_1.z, 8 );
    IEEE2DGNDouble( psCore->raw_data + 54 );
    IEEE2DGNDouble( psCore->raw_data + 62 );
    IEEE2DGNDouble( psCore->raw_data + 70 );

    /* radius_1 */
    dfScaledRadius = psCone->radius_1 / psDGN->scale;
    memcpy( psCore->raw_data + 78, &dfScaledRadius, 8 );
    IEEE2DGNDouble( psCore->raw_data + 78 );

    /* center_2 */
    DGNInverseTransformPoint( psDGN, &sCenter_2 );
    memcpy( psCore->raw_data + 86, &sCenter_2.x, 8 );
    memcpy( psCore->raw_data + 94, &sCenter_2.y, 8 );
    memcpy( psCore->raw_data + 102, &sCenter_2.z, 8 );
    IEEE2DGNDouble( psCore->raw_data + 86 );
    IEEE2DGNDouble( psCore->raw_data + 94 );
    IEEE2DGNDouble( psCore->raw_data + 102 );

    /* radius_2 */
    dfScaledRadius = psCone->radius_2 / psDGN->scale;
    memcpy( psCore->raw_data + 110, &dfScaledRadius, 8 );
    IEEE2DGNDouble( psCore->raw_data + 110 );
    
/* -------------------------------------------------------------------- */
/*      Set the core raw data, including the bounds.                    */
/* -------------------------------------------------------------------- */
    DGNUpdateElemCoreExtended( hDGN, psCore );

    //FIXME: Calculate bounds. Do we need to take the quaternion into account?
    // kintel 20030819

    // Old implementation attempt:
    // What if center_1.z > center_2.z ?
//     double largestRadius = 
//       psCone->radius_1>psCone->radius_2?psCone->radius_1:psCone->radius_2;
//     sMin.x = psCone->center_1.x-largestRadius;
//     sMin.y = psCone->center_1.y-largestRadius;
//     sMin.z = psCone->center_1.z;
//     sMax.x = psCone->center_2.x+largestRadius;
//     sMax.y = psCone->center_2.y+largestRadius;
//     sMax.z = psCone->center_2.z;

    DGNWriteBounds( psDGN, psCore, &sMin, &sMax );
    
    return psCore;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movq %rdi, -0x8(%rbp)
movsd %xmm0, -0x10(%rbp)
movsd %xmm1, -0x18(%rbp)
movsd %xmm2, -0x20(%rbp)
movsd %xmm3, -0x28(%rbp)
movsd %xmm4, -0x30(%rbp)
movsd %xmm5, -0x38(%rbp)
movsd %xmm6, -0x40(%rbp)
movsd %xmm7, -0x48(%rbp)
movq %rsi, -0x50(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x8(%rbp), %rdi
callq 0x11190
movl $0xa8, %edi
movl $0x1, %esi
callq 0x2fc0
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x135f0
movq -0x60(%rbp), %rax
movl $0xc, 0xc(%rax)
movq -0x60(%rbp), %rax
movl $0x17, 0x14(%rax)
movsd -0x10(%rbp), %xmm0
movsd %xmm0, -0xb0(%rbp)
movsd -0x18(%rbp), %xmm0
movsd %xmm0, -0xa8(%rbp)
movsd -0x20(%rbp), %xmm0
movsd %xmm0, -0xa0(%rbp)
movsd -0x30(%rbp), %xmm0
movsd %xmm0, -0xc8(%rbp)
movsd -0x38(%rbp), %xmm0
movsd %xmm0, -0xc0(%rbp)
movsd -0x40(%rbp), %xmm0
movsd %xmm0, -0xb8(%rbp)
movq -0x58(%rbp), %rax
movq -0xb0(%rbp), %rcx
movq %rcx, 0x68(%rax)
movq -0xa8(%rbp), %rcx
movq %rcx, 0x70(%rax)
movq -0xa0(%rbp), %rcx
movq %rcx, 0x78(%rax)
movq -0x58(%rbp), %rax
movq -0xc8(%rbp), %rcx
movq %rcx, 0x88(%rax)
movq -0xc0(%rbp), %rcx
movq %rcx, 0x90(%rax)
movq -0xb8(%rbp), %rcx
movq %rcx, 0x98(%rax)
movsd -0x28(%rbp), %xmm0
movq -0x58(%rbp), %rax
movsd %xmm0, 0x80(%rax)
movsd -0x48(%rbp), %xmm0
movq -0x58(%rbp), %rax
movsd %xmm0, 0xa0(%rax)
movq -0x58(%rbp), %rdi
addq $0x54, %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x2170
cmpq $0x0, -0x50(%rbp)
je 0x146d1
movq -0x58(%rbp), %rax
movq -0x50(%rbp), %rcx
movq (%rcx), %rdx
movq %rdx, 0x54(%rax)
movq 0x8(%rcx), %rdx
movq %rdx, 0x5c(%rax)
movq 0x10(%rcx), %rdx
movq %rdx, 0x64(%rax)
movq 0x18(%rcx), %rcx
movq %rcx, 0x6c(%rax)
jmp 0x146fd
movq -0x58(%rbp), %rax
movl $0x80000000, 0x54(%rax) # imm = 0x80000000
movq -0x58(%rbp), %rax
movl $0x0, 0x58(%rax)
movq -0x58(%rbp), %rax
movl $0x0, 0x5c(%rax)
movq -0x58(%rbp), %rax
movl $0x0, 0x60(%rax)
movq -0x60(%rbp), %rax
movl $0x76, 0x40(%rax)
movq -0x60(%rbp), %rax
movslq 0x40(%rax), %rdi
movl $0x1, %esi
callq 0x2fc0
movq %rax, %rcx
movq -0x60(%rbp), %rax
movq %rcx, 0x48(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb $0x0, 0x24(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb $0x0, 0x25(%rax)
movq -0x58(%rbp), %rax
movl 0x54(%rax), %eax
movl %eax, -0xd4(%rbp)
movl -0xd4(%rbp), %eax
andl $0xff0000, %eax         # imm = 0xFF0000
sarl $0x10, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x26(%rax)
movl -0xd4(%rbp), %eax
andl $0xff000000, %eax       # imm = 0xFF000000
shrl $0x18, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x27(%rax)
movl -0xd4(%rbp), %eax
andl $0xff, %eax
sarl $0x0, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x28(%rax)
movl -0xd4(%rbp), %eax
andl $0xff00, %eax           # imm = 0xFF00
sarl $0x8, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x29(%rax)
movq -0x58(%rbp), %rax
movl 0x58(%rax), %eax
movl %eax, -0xd8(%rbp)
movl -0xd8(%rbp), %eax
andl $0xff0000, %eax         # imm = 0xFF0000
sarl $0x10, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2a(%rax)
movl -0xd8(%rbp), %eax
andl $0xff000000, %eax       # imm = 0xFF000000
shrl $0x18, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2b(%rax)
movl -0xd8(%rbp), %eax
andl $0xff, %eax
sarl $0x0, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2c(%rax)
movl -0xd8(%rbp), %eax
andl $0xff00, %eax           # imm = 0xFF00
sarl $0x8, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2d(%rax)
movq -0x58(%rbp), %rax
movl 0x5c(%rax), %eax
movl %eax, -0xdc(%rbp)
movl -0xdc(%rbp), %eax
andl $0xff0000, %eax         # imm = 0xFF0000
sarl $0x10, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2e(%rax)
movl -0xdc(%rbp), %eax
andl $0xff000000, %eax       # imm = 0xFF000000
shrl $0x18, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x2f(%rax)
movl -0xdc(%rbp), %eax
andl $0xff, %eax
sarl $0x0, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x30(%rax)
movl -0xdc(%rbp), %eax
andl $0xff00, %eax           # imm = 0xFF00
sarl $0x8, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x31(%rax)
movq -0x58(%rbp), %rax
movl 0x60(%rax), %eax
movl %eax, -0xe0(%rbp)
movl -0xe0(%rbp), %eax
andl $0xff0000, %eax         # imm = 0xFF0000
sarl $0x10, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x32(%rax)
movl -0xe0(%rbp), %eax
andl $0xff000000, %eax       # imm = 0xFF000000
shrl $0x18, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x33(%rax)
movl -0xe0(%rbp), %eax
andl $0xff, %eax
sarl $0x0, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x34(%rax)
movl -0xe0(%rbp), %eax
andl $0xff00, %eax           # imm = 0xFF00
sarl $0x8, %eax
movb %al, %cl
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movb %cl, 0x35(%rax)
movq -0x68(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x10d60
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xb0(%rbp), %rcx
movq %rcx, 0x36(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xa8(%rbp), %rcx
movq %rcx, 0x3e(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xa0(%rbp), %rcx
movq %rcx, 0x46(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x36, %rdi
callq 0xa320
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x3e, %rdi
callq 0xa320
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x46, %rdi
callq 0xa320
movq -0x58(%rbp), %rax
movsd 0x80(%rax), %xmm0
movq -0x68(%rbp), %rax
divsd 0x20020(%rax), %xmm0
movsd %xmm0, -0xd0(%rbp)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xd0(%rbp), %rcx
movq %rcx, 0x4e(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x4e, %rdi
callq 0xa320
movq -0x68(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x10d60
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xc8(%rbp), %rcx
movq %rcx, 0x56(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xc0(%rbp), %rcx
movq %rcx, 0x5e(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xb8(%rbp), %rcx
movq %rcx, 0x66(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x56, %rdi
callq 0xa320
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x5e, %rdi
callq 0xa320
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x66, %rdi
callq 0xa320
movq -0x58(%rbp), %rax
movsd 0xa0(%rax), %xmm0
movq -0x68(%rbp), %rax
divsd 0x20020(%rax), %xmm0
movsd %xmm0, -0xd0(%rbp)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rax
movq -0xd0(%rbp), %rcx
movq %rcx, 0x6e(%rax)
movq -0x60(%rbp), %rax
movq 0x48(%rax), %rdi
addq $0x6e, %rdi
callq 0xa320
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x12f50
movq -0x68(%rbp), %rdi
movq -0x60(%rbp), %rsi
leaq -0x80(%rbp), %rdx
leaq -0x98(%rbp), %rcx
callq 0x13630
movq -0x60(%rbp), %rax
addq $0xe0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)