Esempio n. 1
0
File: ckw01.c Progetto: Dbelsa/coft
/* $Procedure  CKW01 ( C-Kernel, write segment to C-kernel, data type 1 ) */
/* Subroutine */ int ckw01_(integer *handle, doublereal *begtim, doublereal *
	endtim, integer *inst, char *ref, logical *avflag, char *segid, 
	integer *nrec, doublereal *sclkdp, doublereal *quats, doublereal *
	avvs, ftnlen ref_len, ftnlen segid_len)
{
    /* System generated locals */
    integer i__1, i__2;
    doublereal d__1;

    /* Local variables */
    integer ndir, i__;
    extern /* Subroutine */ int chkin_(char *, ftnlen), dafps_(integer *, 
	    integer *, doublereal *, integer *, doublereal *);
    doublereal descr[5];
    extern /* Subroutine */ int errch_(char *, char *, ftnlen, ftnlen);
    integer index, value;
    extern /* Subroutine */ int errdp_(char *, doublereal *, ftnlen), dafada_(
	    doublereal *, integer *), dafbna_(integer *, doublereal *, char *,
	     ftnlen), dafena_(void);
    extern logical failed_(void);
    integer refcod;
    extern /* Subroutine */ int namfrm_(char *, integer *, ftnlen);
    extern integer lastnb_(char *, ftnlen);
    doublereal dirent;
    extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, 
	    ftnlen), setmsg_(char *, ftnlen), errint_(char *, integer *, 
	    ftnlen);
    extern logical vzerog_(doublereal *, integer *), return_(void);
    doublereal dcd[2];
    integer icd[6];

/* $ Abstract */

/*     Add a type 1 segment to a C-kernel. */

/* $ Disclaimer */

/*     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
/*     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
/*     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
/*     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
/*     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
/*     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
/*     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
/*     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
/*     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
/*     SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */

/*     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
/*     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
/*     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
/*     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
/*     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
/*     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */

/*     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
/*     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
/*     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
/*     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */

/* $ Required_Reading */

/*     CK */
/*     DAF */
/*     SCLK */

/* $ Keywords */

/*     POINTING */
/*     UTILITY */

/* $ Declarations */
/* $ Brief_I/O */

/*     Variable  I/O  Description */
/*     --------  ---  -------------------------------------------------- */
/*     HANDLE     I   Handle of an open CK file. */
/*     BEGTIM     I   The beginning encoded SCLK of the segment. */
/*     ENDTIM     I   The ending encoded SCLK of the segment. */
/*     INST       I   The NAIF instrument ID code. */
/*     REF        I   The reference frame of the segment. */
/*     AVFLAG     I   True if the segment will contain angular velocity. */
/*     SEGID      I   Segment identifier. */
/*     NREC       I   Number of pointing records. */
/*     SCLKDP     I   Encoded SCLK times. */
/*     QUATS      I   SPICE quaternions representing instrument pointing. */
/*     AVVS       I   Angular velocity vectors. */

/* $ Detailed_Input */

/*     HANDLE     is the handle of the CK file to which the segment will */
/*                be written. The file must have been opened with write */
/*                access. */

/*     BEGTIM     is the beginning encoded SCLK time of the segment. This */
/*                value should be less than or equal to the first time in */
/*                the segment. */

/*     ENDTIM     is the encoded SCLK time at which the segment ends. */
/*                This value should be greater than or equal to the last */
/*                time in the segment. */

/*     INST       is the NAIF integer ID code for the instrument. */

/*     REF        is a character string which specifies the */
/*                reference frame of the segment. This should be one of */
/*                the frames supported by the SPICELIB routine NAMFRM */
/*                which is an entry point of FRAMEX. */

/*     AVFLAG     is a logical flag which indicates whether or not the */
/*                segment will contain angular velocity. */

/*     SEGID      is the segment identifier.  A CK segment identifier may */
/*                contain up to 40 characters. */

/*     NREC       is the number of pointing instances in the segment. */

/*     SCLKDP     are the encoded spacecraft clock times associated with */
/*                each pointing instance. These times must be strictly */
/*                increasing. */

/*     QUATS      is an array of SPICE-style quaternions representing a */
/*                sequence of C-matrices. See the discussion of */
/*                quaternion styles in Particulars below. */

/*     AVVS       are the angular velocity vectors ( optional ). */

/*                If AVFLAG is FALSE then this array is ignored by the */
/*                routine, however it still must be supplied as part of */
/*                the calling sequence. */

/* $ Detailed_Output */

/*     None.  See Files section. */

/* $ Parameters */

/*     None. */

/* $ Exceptions */

/*     1)  If HANDLE is not the handle of a C-kernel opened for writing */
/*         the error will be diagnosed by routines called by this */
/*         routine. */

/*     2)  If SEGID is more than 40 characters long, the error */
/*         SPICE(SEGIDTOOLONG) is signalled. */

/*     3)  If SEGID contains any nonprintable characters, the error */
/*         SPICE(NONPRINTABLECHARS) is signalled. */

/*     4)  If the first encoded SCLK time is negative then the error */
/*         SPICE(INVALIDSCLKTIME) is signalled. If any subsequent times */
/*         are negative the error SPICE(TIMESOUTOFORDER) is signalled. */

/*     5)  If the encoded SCLK times are not strictly increasing, */
/*         the error SPICE(TIMESOUTOFORDER) is signalled. */

/*     6)  If BEGTIM is greater than SCLKDP(1) or ENDTIM is less than */
/*         SCLKDP(NREC), the error SPICE(INVALIDDESCRTIME) is */
/*         signalled. */

/*     7)  If the name of the reference frame is not one of those */
/*         supported by the routine NAMFRM, the error */
/*         SPICE(INVALIDREFFRAME) is signalled. */

/*     8)  If NREC, the number of pointing records, is less than or */
/*         equal to 0, the error SPICE(INVALIDNUMRECS) is signalled. */

/*     9)  If the squared length of any quaternion differes from 1 */
/*         by more than 1.0D-2, the error SPICE(NONUNITQUATERNION) is */
/*         signalled. */

/* $ Files */

/*     This routine adds a type 1 segment to a C-kernel.  The C-kernel */
/*     may be either a new one or an existing one opened for writing. */

/* $ Particulars */

/*     For a detailed description of a type 1 CK segment please see the */
/*     CK Required Reading. */

/*     This routine relieves the user from performing the repetitive */
/*     calls to the DAF routines necessary to construct a CK segment. */


/*     Quaternion Styles */
/*     ----------------- */

/*     There are different "styles" of quaternions used in */
/*     science and engineering applications. Quaternion styles */
/*     are characterized by */

/*        - The order of quaternion elements */

/*        - The quaternion multiplication formula */

/*        - The convention for associating quaternions */
/*          with rotation matrices */

/*     Two of the commonly used styles are */

/*        - "SPICE" */

/*           > Invented by Sir William Rowan Hamilton */
/*           > Frequently used in mathematics and physics textbooks */

/*        - "Engineering" */

/*           > Widely used in aerospace engineering applications */


/*     SPICELIB subroutine interfaces ALWAYS use SPICE quaternions. */
/*     Quaternions of any other style must be converted to SPICE */
/*     quaternions before they are passed to SPICELIB routines. */


/*     Relationship between SPICE and Engineering Quaternions */
/*     ------------------------------------------------------ */

/*     Let M be a rotation matrix such that for any vector V, */

/*        M*V */

/*     is the result of rotating V by theta radians in the */
/*     counterclockwise direction about unit rotation axis vector A. */
/*     Then the SPICE quaternions representing M are */

/*        (+/-) (  cos(theta/2), */
/*                 sin(theta/2) A(1), */
/*                 sin(theta/2) A(2), */
/*                 sin(theta/2) A(3)  ) */

/*     while the engineering quaternions representing M are */

/*        (+/-) ( -sin(theta/2) A(1), */
/*                -sin(theta/2) A(2), */
/*                -sin(theta/2) A(3), */
/*                 cos(theta/2)       ) */

/*     For both styles of quaternions, if a quaternion q represents */
/*     a rotation matrix M, then -q represents M as well. */

/*     Given an engineering quaternion */

/*        QENG   = ( q0,  q1,  q2,  q3 ) */

/*     the equivalent SPICE quaternion is */

/*        QSPICE = ( q3, -q0, -q1, -q2 ) */


/*     Associating SPICE Quaternions with Rotation Matrices */
/*     ---------------------------------------------------- */

/*     Let FROM and TO be two right-handed reference frames, for */
/*     example, an inertial frame and a spacecraft-fixed frame. Let the */
/*     symbols */

/*        V    ,   V */
/*         FROM     TO */

/*     denote, respectively, an arbitrary vector expressed relative to */
/*     the FROM and TO frames. Let M denote the transformation matrix */
/*     that transforms vectors from frame FROM to frame TO; then */

/*        V   =  M * V */
/*         TO         FROM */

/*     where the expression on the right hand side represents left */
/*     multiplication of the vector by the matrix. */

/*     Then if the unit-length SPICE quaternion q represents M, where */

/*        q = (q0, q1, q2, q3) */

/*     the elements of M are derived from the elements of q as follows: */

/*          +-                                                         -+ */
/*          |           2    2                                          | */
/*          | 1 - 2*( q2 + q3 )   2*(q1*q2 - q0*q3)   2*(q1*q3 + q0*q2) | */
/*          |                                                           | */
/*          |                                                           | */
/*          |                               2    2                      | */
/*      M = | 2*(q1*q2 + q0*q3)   1 - 2*( q1 + q3 )   2*(q2*q3 - q0*q1) | */
/*          |                                                           | */
/*          |                                                           | */
/*          |                                                   2    2  | */
/*          | 2*(q1*q3 - q0*q2)   2*(q2*q3 + q0*q1)   1 - 2*( q1 + q2 ) | */
/*          |                                                           | */
/*          +-                                                         -+ */

/*     Note that substituting the elements of -q for those of q in the */
/*     right hand side leaves each element of M unchanged; this shows */
/*     that if a quaternion q represents a matrix M, then so does the */
/*     quaternion -q. */

/*     To map the rotation matrix M to a unit quaternion, we start by */
/*     decomposing the rotation matrix as a sum of symmetric */
/*     and skew-symmetric parts: */

/*                                        2 */
/*        M = [ I  +  (1-cos(theta)) OMEGA  ] + [ sin(theta) OMEGA ] */

/*                     symmetric                   skew-symmetric */


/*     OMEGA is a skew-symmetric matrix of the form */

/*                   +-             -+ */
/*                   |  0   -n3   n2 | */
/*                   |               | */
/*         OMEGA  =  |  n3   0   -n1 | */
/*                   |               | */
/*                   | -n2   n1   0  | */
/*                   +-             -+ */

/*     The vector N of matrix entries (n1, n2, n3) is the rotation axis */
/*     of M and theta is M's rotation angle.  Note that N and theta */
/*     are not unique. */

/*     Let */

/*        C = cos(theta/2) */
/*        S = sin(theta/2) */

/*     Then the unit quaternions Q corresponding to M are */

/*        Q = +/- ( C, S*n1, S*n2, S*n3 ) */

/*     The mappings between quaternions and the corresponding rotations */
/*     are carried out by the SPICELIB routines */

/*        Q2M {quaternion to matrix} */
/*        M2Q {matrix to quaternion} */

/*     M2Q always returns a quaternion with scalar part greater than */
/*     or equal to zero. */


/*     SPICE Quaternion Multiplication Formula */
/*     --------------------------------------- */

/*     Given a SPICE quaternion */

/*        Q = ( q0, q1, q2, q3 ) */

/*     corresponding to rotation axis A and angle theta as above, we can */
/*     represent Q using "scalar + vector" notation as follows: */

/*        s =   q0           = cos(theta/2) */

/*        v = ( q1, q2, q3 ) = sin(theta/2) * A */

/*        Q = s + v */

/*     Let Q1 and Q2 be SPICE quaternions with respective scalar */
/*     and vector parts s1, s2 and v1, v2: */

/*        Q1 = s1 + v1 */
/*        Q2 = s2 + v2 */

/*     We represent the dot product of v1 and v2 by */

/*        <v1, v2> */

/*     and the cross product of v1 and v2 by */

/*        v1 x v2 */

/*     Then the SPICE quaternion product is */

/*        Q1*Q2 = s1*s2 - <v1,v2>  + s1*v2 + s2*v1 + (v1 x v2) */

/*     If Q1 and Q2 represent the rotation matrices M1 and M2 */
/*     respectively, then the quaternion product */

/*        Q1*Q2 */

/*     represents the matrix product */

/*        M1*M2 */


/* $ Examples */

/*  C */
/*  C     This example writes a type 1 C-kernel segment for the */
/*  C     Galileo scan platform to a previously opened file attached to */
/*  C     HANDLE. */

/*  C */
/*  C     Assume arrays of quaternions, angular velocities, and the */
/*  C     associated SCLK times are produced elsewhere. */
/*  C */
/*        . */
/*        . */
/*        . */

/*  C */
/*  C     The subroutine CKW01 needs the following items for the */
/*  C     segment descriptor: */
/*  C */
/*  C        1) SCLK limits of the segment. */
/*  C        2) Instrument code. */
/*  C        3) Reference frame. */
/*  C        4) The angular velocity flag. */
/*  C */
/*        BEGTIM = SCLK (    1 ) */
/*        ENDTIM = SCLK ( NREC ) */

/*        INST   = -77001 */
/*        REF    = 'J2000' */
/*        AVFLAG = .TRUE. */

/*        SEGID  = 'GLL SCAN PLT - DATA TYPE 1' */

/*  C */
/*  C     Write the segment. */
/*  C */
/*        CALL CKW01 ( HANDLE, BEGTIM, ENDTIM, INST, REF, AVFLAG, */
/*     .               SEGID,  NREC,   SCLKDP, QUATS, AVVS         ) */


/* $ Restrictions */

/*     None. */

/* $ Literature_References */

/*     None. */

/* $ Author_and_Institution */

/*     W.L. Taber      (JPL) */
/*     K.R. Gehringer  (JPL) */
/*     N.J. Bachman    (JPL) */
/*     J.M. Lynch      (JPL) */

/* $ Version */

/* -    SPICELIB Version 3.0.0, 01-JUN-2010 (NJB) */

/*        The check for non-unit quaternions has been replaced */
/*        with a check for zero-length quaternions. */

/* -    SPICELIB Version 2.2.0, 26-FEB-2008 (NJB) */

/*        Updated header; added information about SPICE */
/*        quaternion conventions. */

/*        Minor typo in a long error message was corrected. */

/* -    SPICELIB Version 2.1.0, 22-FEB-1999 (WLT) */

/*        Added check to make sure that all quaternions are unit */
/*        length to single precision. */

/* -    SPICELIB Version 2.0.0, 28-DEC-1993 (WLT) */

/*        The routine was upgraded to support non-inertial reference */
/*        frames. */

/* -    SPICELIB Version 1.1.1, 05-SEP-1993 (KRG) */

/*        Removed all references to a specific method of opening the CK */
/*        file in the $ Brief_I/O, $ Detailed_Input, $ Exceptions, */
/*        $ Files, and $ Examples sections of the header. It is assumed */
/*        that a person using this routine has some knowledge of the DAF */
/*        system and the methods for obtaining file handles. */

/* -    SPICELIB Version 1.1.0, 25-NOV-1992 (JML) */

/*        If the number of pointing records is not positive an error */
/*        is now signalled. */

/*        FAILED is checked after the call to DAFBNA. */

/*        The variable HLDCLK was removed from the loop where the times */
/*        were checked. */

/* -    SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */

/*        Comment section for permuted index source lines was added */
/*        following the header. */

/* -    SPICELIB Version 1.0.0, 30-AUG-1991 (JML) (NJB) */

/* -& */
/* $ Index_Entries */

/*     write ck type_1 pointing data segment */

/* -& */
/* $ Revisions */

/* -    SPICELIB Version 1.1.1, 05-SEP-1993 (KRG) */

/*        Removed all references to a specific method of opening the CK */
/*        file in the $ Brief_I/O, $ Detailed_Input, $ Exceptions, */
/*        $ Files, and $ Examples sections of the header. It is assumed */
/*        that a person using this routine has some knowledge of the DAF */
/*        system and the methods for obtaining file handles. */

/* -    SPICELIB Version 1.1.0, 25-NOV-1992 (JML) */

/*        If the number of pointing records is not positive an error */
/*        is now signalled. */

/*        FAILED is checked after the call to DAFBNA. */

/*        The variable HLDCLK was removed from the loop where the times */
/*        were checked. */

/* -    SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */

/*        Comment section for permuted index source lines was added */
/*        following the header. */

/* -    SPICELIB Version 1.0.0, 30-AUG-1991 (JML) (NJB) */

/* -& */

/*     SPICELIB functions */


/*     Local parameters */

/*     SIDLEN    is the maximum number of characters allowed in a CK */
/*               segment identifier. */

/*     NDC       is the size of a packed CK segment descriptor. */

/*     ND        is the number of double precision components in a CK */
/*               segment descriptor. */

/*     NI        is the number of integer components in a CK segment */
/*               descriptor. */

/*     DTYPE     is the data type of the segment that this routine */
/*               operates on. */

/*     FPRINT    is the integer value of the first printable ASCII */
/*               character. */

/*     LPRINT    is the integer value of the last printable ASCII */
/*               character. */



/*     Local variables */


/*     Standard SPICE error handling. */

    if (return_()) {
	return 0;
    }
    chkin_("CKW01", (ftnlen)5);

/*     The first thing that we will do is create the segment descriptor. */

/*     The structure of the segment descriptor is as follows. */

/*           DCD( 1 ) and DCD( 2 ) -- SCLK limits of the segment. */
/*           ICD( 1 )              -- Instrument code. */
/*           ICD( 2 )              -- Reference frame ID. */
/*           ICD( 3 )              -- Data type of the segment. */
/*           ICD( 4 )              -- Angular rates flag. */
/*           ICD( 5 )              -- Beginning address of segment. */
/*           ICD( 6 )              -- Ending address of segment. */


/*     Make sure that there is a positive number of pointing records. */

    if (*nrec <= 0) {
	setmsg_("# is an invalid number of pointing instances for type 1.", (
		ftnlen)56);
	errint_("#", nrec, (ftnlen)1);
	sigerr_("SPICE(INVALIDNUMREC)", (ftnlen)20);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }

/*     Check that the SCLK bounds on the segment are reasonable. */

    if (*begtim > sclkdp[0]) {
	setmsg_("The first d.p. component of the descriptor is invalid. DCD("
		"1) = # and SCLKDP(1) = # ", (ftnlen)84);
	errdp_("#", begtim, (ftnlen)1);
	errdp_("#", sclkdp, (ftnlen)1);
	sigerr_("SPICE(INVALIDDESCRTIME)", (ftnlen)23);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }
    if (*endtim < sclkdp[*nrec - 1]) {
	setmsg_("The second d.p. component of the descriptor is invalid. DCD"
		"(2) = # and SCLKDP(NREC) = # ", (ftnlen)88);
	errdp_("#", endtim, (ftnlen)1);
	errdp_("#", &sclkdp[*nrec - 1], (ftnlen)1);
	sigerr_("SPICE(INVALIDDESCRTIME)", (ftnlen)23);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }
    dcd[0] = *begtim;
    dcd[1] = *endtim;

/*     Get the NAIF integer code for the reference frame. */

    namfrm_(ref, &refcod, ref_len);
    if (refcod == 0) {
	setmsg_("The reference frame # is not supported.", (ftnlen)39);
	errch_("#", ref, (ftnlen)1, ref_len);
	sigerr_("SPICE(INVALIDREFFRAME)", (ftnlen)22);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }

/*     Assign values to the integer components of the segment descriptor. */

    icd[0] = *inst;
    icd[1] = refcod;
    icd[2] = 1;
    if (*avflag) {
	icd[3] = 1;
    } else {
	icd[3] = 0;
    }

/*     Now pack the segment descriptor. */

    dafps_(&c__2, &c__6, dcd, icd, descr);

/*     Check that all the characters in the segid can be printed. */

    i__1 = lastnb_(segid, segid_len);
    for (i__ = 1; i__ <= i__1; ++i__) {
	value = *(unsigned char *)&segid[i__ - 1];
	if (value < 32 || value > 126) {
	    setmsg_("The segment identifier contains nonprintable characters",
		     (ftnlen)55);
	    sigerr_("SPICE(NONPRINTABLECHARS)", (ftnlen)24);
	    chkout_("CKW01", (ftnlen)5);
	    return 0;
	}
    }

/*     Also check to see if the segment identifier is too long. */

    if (lastnb_(segid, segid_len) > 40) {
	setmsg_("Segment identifier contains more than 40 characters.", (
		ftnlen)52);
	sigerr_("SPICE(SEGIDTOOLONG)", (ftnlen)19);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }

/*     Now check that the encoded SCLK times are positive and strictly */
/*     increasing. */

/*     Check that the first time is nonnegative. */

    if (sclkdp[0] < 0.) {
	setmsg_("The first SCLKDP time: # is negative.", (ftnlen)37);
	errdp_("#", sclkdp, (ftnlen)1);
	sigerr_("SPICE(INVALIDSCLKTIME)", (ftnlen)22);
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }

/*     Now check that the times are ordered properly. */

    i__1 = *nrec;
    for (i__ = 2; i__ <= i__1; ++i__) {
	if (sclkdp[i__ - 1] <= sclkdp[i__ - 2]) {
	    setmsg_("The SCLKDP times are not strictly increasing. SCLKDP(#)"
		    " = # and SCLKDP(#) = #.", (ftnlen)78);
	    errint_("#", &i__, (ftnlen)1);
	    errdp_("#", &sclkdp[i__ - 1], (ftnlen)1);
	    i__2 = i__ - 1;
	    errint_("#", &i__2, (ftnlen)1);
	    errdp_("#", &sclkdp[i__ - 2], (ftnlen)1);
	    sigerr_("SPICE(TIMESOUTOFORDER)", (ftnlen)22);
	    chkout_("CKW01", (ftnlen)5);
	    return 0;
	}
    }

/*     Make sure that the quaternions are non-zero. This is just */
/*     a check for uninitialized data. */

    i__1 = *nrec;
    for (i__ = 1; i__ <= i__1; ++i__) {
	if (vzerog_(&quats[(i__ << 2) - 4], &c__4)) {
	    setmsg_("The quaternion at index # has magnitude zero.", (ftnlen)
		    45);
	    errint_("#", &i__, (ftnlen)1);
	    sigerr_("SPICE(ZEROQUATERNION)", (ftnlen)21);
	    chkout_("CKW01", (ftnlen)5);
	    return 0;
	}
    }

/*     No more checks, begin writing the segment. */

    dafbna_(handle, descr, segid, segid_len);
    if (failed_()) {
	chkout_("CKW01", (ftnlen)5);
	return 0;
    }

/*     Now add the quaternions and optionally, the angular velocity */
/*     vectors. */

    if (*avflag) {
	i__1 = *nrec;
	for (i__ = 1; i__ <= i__1; ++i__) {
	    dafada_(&quats[(i__ << 2) - 4], &c__4);
	    dafada_(&avvs[i__ * 3 - 3], &c__3);
	}
    } else {
	i__1 = *nrec;
	for (i__ = 1; i__ <= i__1; ++i__) {
	    dafada_(&quats[(i__ << 2) - 4], &c__4);
	}
    }

/*     Add the SCLK times. */

    dafada_(sclkdp, nrec);

/*     The time tag directory.  The Ith element is defined to be the */
/*     average of the (I*100)th and the (I*100+1)st SCLK time. */

    ndir = (*nrec - 1) / 100;
    index = 100;
    i__1 = ndir;
    for (i__ = 1; i__ <= i__1; ++i__) {
	dirent = (sclkdp[index - 1] + sclkdp[index]) / 2.;
	dafada_(&dirent, &c__1);
	index += 100;
    }

/*     Finally, the number of records. */

    d__1 = (doublereal) (*nrec);
    dafada_(&d__1, &c__1);

/*     End the segment. */

    dafena_();
    chkout_("CKW01", (ftnlen)5);
    return 0;
} /* ckw01_ */
Esempio n. 2
0
/* $Procedure      CKW05 ( Write CK segment, type 5 ) */
/* Subroutine */ int ckw05_(integer *handle, integer *subtyp, integer *degree,
	 doublereal *begtim, doublereal *endtim, integer *inst, char *ref, 
	logical *avflag, char *segid, integer *n, doublereal *sclkdp, 
	doublereal *packts, doublereal *rate, integer *nints, doublereal *
	starts, ftnlen ref_len, ftnlen segid_len)
{
    /* System generated locals */
    integer i__1, i__2;
    doublereal d__1;

    /* Local variables */
    integer addr__, i__;
    extern /* Subroutine */ int chkin_(char *, ftnlen), dafps_(integer *, 
	    integer *, doublereal *, integer *, doublereal *);
    doublereal descr[5];
    extern /* Subroutine */ int errch_(char *, char *, ftnlen, ftnlen), 
	    errdp_(char *, doublereal *, ftnlen), dafada_(doublereal *, 
	    integer *);
    doublereal dc[2];
    extern /* Subroutine */ int dafbna_(integer *, doublereal *, char *, 
	    ftnlen);
    integer ic[6];
    extern /* Subroutine */ int dafena_(void);
    extern logical failed_(void);
    integer chrcod, refcod;
    extern integer bsrchd_(doublereal *, integer *, doublereal *);
    extern /* Subroutine */ int namfrm_(char *, integer *, ftnlen);
    extern integer lastnb_(char *, ftnlen);
    integer packsz;
    extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, 
	    ftnlen), setmsg_(char *, ftnlen), errint_(char *, integer *, 
	    ftnlen);
    extern integer lstltd_(doublereal *, integer *, doublereal *);
    extern logical vzerog_(doublereal *, integer *), return_(void);
    integer winsiz;
    extern logical odd_(integer *);

/* $ Abstract */

/*     Write a type 5 segment to a CK file. */

/* $ Disclaimer */

/*     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
/*     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
/*     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
/*     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
/*     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
/*     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
/*     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
/*     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
/*     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
/*     SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */

/*     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
/*     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
/*     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
/*     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
/*     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
/*     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */

/*     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
/*     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
/*     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
/*     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */

/* $ Required_Reading */

/*     CK */
/*     NAIF_IDS */
/*     ROTATION */
/*     TIME */

/* $ Keywords */

/*     POINTING */
/*     FILES */

/* $ Declarations */
/* $ Abstract */

/*     Declare parameters specific to CK type 05. */

/* $ Disclaimer */

/*     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
/*     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
/*     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
/*     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
/*     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
/*     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
/*     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
/*     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
/*     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
/*     SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */

/*     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
/*     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
/*     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
/*     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
/*     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
/*     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */

/*     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
/*     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
/*     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
/*     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */

/* $ Required_Reading */

/*     CK */

/* $ Keywords */

/*     CK */

/* $ Restrictions */

/*     None. */

/* $ Author_and_Institution */

/*     N.J. Bachman      (JPL) */

/* $ Literature_References */

/*     None. */

/* $ Version */

/* -    SPICELIB Version 1.0.0, 20-AUG-2002 (NJB) */

/* -& */

/*     CK type 5 subtype codes: */


/*     Subtype 0:  Hermite interpolation, 8-element packets. Quaternion */
/*                 and quaternion derivatives only, no angular velocity */
/*                 vector provided. Quaternion elements are listed */
/*                 first, followed by derivatives. Angular velocity is */
/*                 derived from the quaternions and quaternion */
/*                 derivatives. */


/*     Subtype 1:  Lagrange interpolation, 4-element packets. Quaternion */
/*                 only. Angular velocity is derived by differentiating */
/*                 the interpolating polynomials. */


/*     Subtype 2:  Hermite interpolation, 14-element packets. */
/*                 Quaternion and angular angular velocity vector, as */
/*                 well as derivatives of each, are provided. The */
/*                 quaternion comes first, then quaternion derivatives, */
/*                 then angular velocity and its derivatives. */


/*     Subtype 3:  Lagrange interpolation, 7-element packets. Quaternion */
/*                 and angular velocity vector provided.  The quaternion */
/*                 comes first. */


/*     Packet sizes associated with the various subtypes: */


/*     End of file ck05.inc. */

/* $ Brief_I/O */

/*     Variable  I/O  Description */
/*     --------  ---  -------------------------------------------------- */
/*     HANDLE     I   Handle of an CK file open for writing. */
/*     SUBTYP     I   CK type 5 subtype code. */
/*     DEGREE     I   Degree of interpolating polynomials. */
/*     BEGTIM     I   Start time of interval covered by segment. */
/*     ENDTIM     I   End time of interval covered by segment. */
/*     INST       I   NAIF code for a s/c instrument or structure. */
/*     REF        I   Reference frame name. */
/*     AVFLAG     I   True if the segment will contain angular velocity. */
/*     SEGID      I   Segment identifier. */
/*     N          I   Number of packets. */
/*     SCLKDP     I   Encoded SCLK times. */
/*     PACKTS     I   Array of packets. */
/*     RATE       I   Nominal SCLK rate in seconds per tick. */
/*     NINTS      I   Number of intervals. */
/*     STARTS     I   Encoded SCLK interval start times. */
/*     MAXDEG     P   Maximum allowed degree of interpolating polynomial. */

/* $ Detailed_Input */

/*     HANDLE         is the file handle of a CK file that has been */
/*                    opened for writing. */

/*     SUBTYP         is an integer code indicating the subtype of the */
/*                    the segment to be created. */

/*     DEGREE         is the degree of the polynomials used to */
/*                    interpolate the quaternions contained in the input */
/*                    packets.  All components of the quaternions are */
/*                    interpolated by polynomials of fixed degree. */

/*     BEGTIM, */
/*     ENDTIM         are the beginning and ending encoded SCLK times */
/*                    for which the segment provides pointing */
/*                    information. BEGTIM must be less than or equal to */
/*                    ENDTIM, and at least one data packet must have a */
/*                    time tag T such that */

/*                       BEGTIM  <  T  <  ENDTIM */
/*                               -     - */

/*     INST           is the NAIF integer code for the instrument or */
/*                    structure for which a segment is to be created. */

/*     REF            is the NAIF name for a reference frame relative to */
/*                    which the pointing information for INST is */
/*                    specified. */

/*     AVFLAG         is a logical flag which indicates whether or not */
/*                    the segment will contain angular velocity. */

/*     SEGID          is the segment identifier.  A CK segment */
/*                    identifier may contain up to 40 characters. */

/*     N              is the number of packets in the input packet */
/*                    array. */

/*     SCLKDP         are the encoded spacecraft clock times associated */
/*                    with each pointing instance. These times must be */
/*                    strictly increasing. */

/*     PACKTS         contains a time-ordered array of data packets */
/*                    representing the orientation of INST relative to */
/*                    the frame REF. Each packet contains a SPICE-style */
/*                    quaternion and optionally, depending on the */
/*                    segment subtype, attitude derivative data, from */
/*                    which a C-matrix and an angular velocity vector */
/*                    may be derived. */

/*                    See the discussion of quaternion styles in */
/*                    Particulars below. */

/*                    The C-matrix represented by the Ith data packet is */
/*                    a rotation matrix that transforms the components */
/*                    of a vector expressed in the base frame specified */
/*                    by REF to components expressed in the instrument */
/*                    fixed frame at the time SCLKDP(I). */

/*                    Thus, if a vector V has components x, y, z in the */
/*                    base frame, then V has components x', y', z' */
/*                    in the instrument fixed frame where: */

/*                       [ x' ]     [          ] [ x ] */
/*                       | y' |  =  |   CMAT   | | y | */
/*                       [ z' ]     [          ] [ z ] */


/*                    The attitude derivative information in PACKTS(I) */
/*                    gives the angular velocity of the instrument fixed */
/*                    frame at time SCLKDP(I) with respect to the */
/*                    reference frame specified by REF. */

/*                    The direction of an angular velocity vector gives */
/*                    the right-handed axis about which the instrument */
/*                    fixed reference frame is rotating. The magnitude */
/*                    of the vector is the magnitude of the */
/*                    instantaneous velocity of the rotation, in radians */
/*                    per second. */

/*                    Packet contents and the corresponding */
/*                    interpolation methods depend on the segment */
/*                    subtype, and are as follows: */

/*                       Subtype 0:  Hermite interpolation, 8-element */
/*                                   packets. Quaternion and quaternion */
/*                                   derivatives only, no angular */
/*                                   velocity vector provided. */
/*                                   Quaternion elements are listed */
/*                                   first, followed by derivatives. */
/*                                   Angular velocity is derived from */
/*                                   the quaternions and quaternion */
/*                                   derivatives. */

/*                       Subtype 1:  Lagrange interpolation, 4-element */
/*                                   packets. Quaternion only. Angular */
/*                                   velocity is derived by */
/*                                   differentiating the interpolating */
/*                                   polynomials. */

/*                       Subtype 2:  Hermite interpolation, 14-element */
/*                                   packets.  Quaternion and angular */
/*                                   angular velocity vector, as well as */
/*                                   derivatives of each, are provided. */
/*                                   The quaternion comes first, then */
/*                                   quaternion derivatives, then */
/*                                   angular velocity and its */
/*                                   derivatives. */

/*                       Subtype 3:  Lagrange interpolation, 7-element */
/*                                   packets. Quaternion and angular */
/*                                   velocity vector provided.  The */
/*                                   quaternion comes first. */

/*                    Angular velocity is always specified relative to */
/*                    the base frame. */

/*     RATE           is the nominal rate of the spacecraft clock */
/*                    associated with INST.  Units are seconds per */
/*                    tick.  RATE is used to scale angular velocity */
/*                    to radians/second. */

/*     NINTS          is the number of intervals that the pointing */
/*                    instances are partitioned into. */

/*     STARTS         are the start times of each of the interpolation */
/*                    intervals. These times must be strictly increasing */
/*                    and must coincide with times for which the segment */
/*                    contains pointing. */

/* $ Detailed_Output */

/*     None.  See $Particulars for a description of the effect of this */
/*     routine. */

/* $ Parameters */

/*     MAXDEG         is the maximum allowed degree of the interpolating */
/*                    polynomial.  If the value of MAXDEG is increased, */
/*                    the SPICELIB routine CKPFS must be changed */
/*                    accordingly.  In particular, the size of the */
/*                    record passed to CKRnn and CKEnn must be */
/*                    increased, and comments describing the record size */
/*                    must be changed. */

/* $ Exceptions */

/*     If any of the following exceptions occur, this routine will return */
/*     without creating a new segment. */

/*     1)  If HANDLE is not the handle of a C-kernel opened for writing */
/*         the error will be diagnosed by routines called by this */
/*         routine. */

/*     2)  If the last non-blank character of SEGID occurs past index 40, */
/*         the error SPICE(SEGIDTOOLONG) is signaled. */

/*     3)  If SEGID contains any nonprintable characters, the error */
/*         SPICE(NONPRINTABLECHARS) is signaled. */

/*     4)  If the first encoded SCLK time is negative then the error */
/*         SPICE(INVALIDSCLKTIME) is signaled. If any subsequent times */
/*         are negative the error will be detected in exception (5). */

/*     5)  If the encoded SCLK times are not strictly increasing, */
/*         the error SPICE(TIMESOUTOFORDER) is signaled. */

/*     6)  If the name of the reference frame is not one of those */
/*         supported by the routine FRAMEX, the error */
/*         SPICE(INVALIDREFFRAME) is signaled. */

/*     7)  If the number of packets N is not at least 1, the error */
/*         SPICE(TOOFEWPACKETS) will be signaled. */

/*     8)  If NINTS, the number of interpolation intervals, is less than */
/*         or equal to 0, the error SPICE(INVALIDNUMINTS) is signaled. */

/*     9)  If the encoded SCLK interval start times are not strictly */
/*         increasing, the error SPICE(TIMESOUTOFORDER) is signaled. */

/*    10)  If an interval start time does not coincide with a time for */
/*         which there is an actual pointing instance in the segment, */
/*         then the error SPICE(INVALIDSTARTTIME) is signaled. */

/*    11)  This routine assumes that the rotation between adjacent */
/*         quaternions that are stored in the same interval has a */
/*         rotation angle of THETA radians, where */

/*            0  <  THETA  <  pi. */
/*               _ */

/*         The routines that evaluate the data in the segment produced */
/*         by this routine cannot distinguish between rotations of THETA */
/*         radians, where THETA is in the interval [0, pi), and */
/*         rotations of */

/*            THETA   +   2 * k * pi */

/*         radians, where k is any integer.  These "large" rotations will */
/*         yield invalid results when interpolated.  You must ensure that */
/*         the data stored in the segment will not be subject to this */
/*         sort of ambiguity. */

/*    12)  If any quaternion has magnitude zero, the error */
/*         SPICE(ZEROQUATERNION) is signaled. */

/*    13)  If the interpolation window size implied by DEGREE is not */
/*         even, the error SPICE(INVALIDDEGREE) is signaled.  The window */
/*         size is DEGREE+1 for Lagrange subtypes and is (DEGREE+1)/2 */
/*         for Hermite subtypes. */

/*    14)  If an unrecognized subtype code is supplied, the error */
/*         SPICE(NOTSUPPORTED) is signaled. */

/*    15)  If DEGREE is not at least 1 or is greater than MAXDEG, the */
/*         error SPICE(INVALIDDEGREE) is signaled. */

/*    16)  If the segment descriptor bounds are out of order, the */
/*         error SPICE(BADDESCRTIMES) is signaled. */

/*    17)  If there is no element of SCLKDP that lies between BEGTIM and */
/*         ENDTIM inclusive, the error SPICE(EMPTYSEGMENT) is signaled. */

/*    18)  If RATE is zero, the error SPICE(INVALIDVALUE) is signaled. */


/* $ Files */

/*     A new type 5 CK segment is written to the CK file attached */
/*     to HANDLE. */

/* $ Particulars */

/*     This routine writes a CK type 5 data segment to the open CK */
/*     file according to the format described in the type 5 section of */
/*     the CK Required Reading. The CK file must have been opened with */
/*     write access. */


/*     Quaternion Styles */
/*     ----------------- */

/*     There are different "styles" of quaternions used in */
/*     science and engineering applications. Quaternion styles */
/*     are characterized by */

/*        - The order of quaternion elements */

/*        - The quaternion multiplication formula */

/*        - The convention for associating quaternions */
/*          with rotation matrices */

/*     Two of the commonly used styles are */

/*        - "SPICE" */

/*           > Invented by Sir William Rowan Hamilton */
/*           > Frequently used in mathematics and physics textbooks */

/*        - "Engineering" */

/*           > Widely used in aerospace engineering applications */


/*     SPICELIB subroutine interfaces ALWAYS use SPICE quaternions. */
/*     Quaternions of any other style must be converted to SPICE */
/*     quaternions before they are passed to SPICELIB routines. */


/*     Relationship between SPICE and Engineering Quaternions */
/*     ------------------------------------------------------ */

/*     Let M be a rotation matrix such that for any vector V, */

/*        M*V */

/*     is the result of rotating V by theta radians in the */
/*     counterclockwise direction about unit rotation axis vector A. */
/*     Then the SPICE quaternions representing M are */

/*        (+/-) (  cos(theta/2), */
/*                 sin(theta/2) A(1), */
/*                 sin(theta/2) A(2), */
/*                 sin(theta/2) A(3)  ) */

/*     while the engineering quaternions representing M are */

/*        (+/-) ( -sin(theta/2) A(1), */
/*                -sin(theta/2) A(2), */
/*                -sin(theta/2) A(3), */
/*                 cos(theta/2)       ) */

/*     For both styles of quaternions, if a quaternion q represents */
/*     a rotation matrix M, then -q represents M as well. */

/*     Given an engineering quaternion */

/*        QENG   = ( q0,  q1,  q2,  q3 ) */

/*     the equivalent SPICE quaternion is */

/*        QSPICE = ( q3, -q0, -q1, -q2 ) */


/*     Associating SPICE Quaternions with Rotation Matrices */
/*     ---------------------------------------------------- */

/*     Let FROM and TO be two right-handed reference frames, for */
/*     example, an inertial frame and a spacecraft-fixed frame. Let the */
/*     symbols */

/*        V    ,   V */
/*         FROM     TO */

/*     denote, respectively, an arbitrary vector expressed relative to */
/*     the FROM and TO frames. Let M denote the transformation matrix */
/*     that transforms vectors from frame FROM to frame TO; then */

/*        V   =  M * V */
/*         TO         FROM */

/*     where the expression on the right hand side represents left */
/*     multiplication of the vector by the matrix. */

/*     Then if the unit-length SPICE quaternion q represents M, where */

/*        q = (q0, q1, q2, q3) */

/*     the elements of M are derived from the elements of q as follows: */

/*          +-                                                         -+ */
/*          |           2    2                                          | */
/*          | 1 - 2*( q2 + q3 )   2*(q1*q2 - q0*q3)   2*(q1*q3 + q0*q2) | */
/*          |                                                           | */
/*          |                                                           | */
/*          |                               2    2                      | */
/*      M = | 2*(q1*q2 + q0*q3)   1 - 2*( q1 + q3 )   2*(q2*q3 - q0*q1) | */
/*          |                                                           | */
/*          |                                                           | */
/*          |                                                   2    2  | */
/*          | 2*(q1*q3 - q0*q2)   2*(q2*q3 + q0*q1)   1 - 2*( q1 + q2 ) | */
/*          |                                                           | */
/*          +-                                                         -+ */

/*     Note that substituting the elements of -q for those of q in the */
/*     right hand side leaves each element of M unchanged; this shows */
/*     that if a quaternion q represents a matrix M, then so does the */
/*     quaternion -q. */

/*     To map the rotation matrix M to a unit quaternion, we start by */
/*     decomposing the rotation matrix as a sum of symmetric */
/*     and skew-symmetric parts: */

/*                                        2 */
/*        M = [ I  +  (1-cos(theta)) OMEGA  ] + [ sin(theta) OMEGA ] */

/*                     symmetric                   skew-symmetric */


/*     OMEGA is a skew-symmetric matrix of the form */

/*                   +-             -+ */
/*                   |  0   -n3   n2 | */
/*                   |               | */
/*         OMEGA  =  |  n3   0   -n1 | */
/*                   |               | */
/*                   | -n2   n1   0  | */
/*                   +-             -+ */

/*     The vector N of matrix entries (n1, n2, n3) is the rotation axis */
/*     of M and theta is M's rotation angle.  Note that N and theta */
/*     are not unique. */

/*     Let */

/*        C = cos(theta/2) */
/*        S = sin(theta/2) */

/*     Then the unit quaternions Q corresponding to M are */

/*        Q = +/- ( C, S*n1, S*n2, S*n3 ) */

/*     The mappings between quaternions and the corresponding rotations */
/*     are carried out by the SPICELIB routines */

/*        Q2M {quaternion to matrix} */
/*        M2Q {matrix to quaternion} */

/*     M2Q always returns a quaternion with scalar part greater than */
/*     or equal to zero. */


/*     SPICE Quaternion Multiplication Formula */
/*     --------------------------------------- */

/*     Given a SPICE quaternion */

/*        Q = ( q0, q1, q2, q3 ) */

/*     corresponding to rotation axis A and angle theta as above, we can */
/*     represent Q using "scalar + vector" notation as follows: */

/*        s =   q0           = cos(theta/2) */

/*        v = ( q1, q2, q3 ) = sin(theta/2) * A */

/*        Q = s + v */

/*     Let Q1 and Q2 be SPICE quaternions with respective scalar */
/*     and vector parts s1, s2 and v1, v2: */

/*        Q1 = s1 + v1 */
/*        Q2 = s2 + v2 */

/*     We represent the dot product of v1 and v2 by */

/*        <v1, v2> */

/*     and the cross product of v1 and v2 by */

/*        v1 x v2 */

/*     Then the SPICE quaternion product is */

/*        Q1*Q2 = s1*s2 - <v1,v2>  + s1*v2 + s2*v1 + (v1 x v2) */

/*     If Q1 and Q2 represent the rotation matrices M1 and M2 */
/*     respectively, then the quaternion product */

/*        Q1*Q2 */

/*     represents the matrix product */

/*        M1*M2 */


/* $ Examples */

/*     Suppose that you have data packets and are prepared to produce */
/*     a segment of type 5 in a CK file. */

/*     The following code fragment could be used to add the new segment */
/*     to a previously opened CK file attached to HANDLE. The file must */
/*     have been opened with write access. */

/*        C */
/*        C     Create a segment identifier. */
/*        C */
/*              SEGID = 'MY_SAMPLE_CK_TYPE_5_SEGMENT' */

/*        C */
/*        C     Write the segment. */
/*        C */
/*              CALL CKW05 ( HANDLE, SUBTYP, DEGREE, BEGTIM, ENDTIM, */
/*             .             INST,   REF,    AVFLAG, SEGID,  N, */
/*             .             SCLKDP, PACKTS, RATE,   NINTS,  STARTS ) */


/* $ Restrictions */

/*     None. */

/* $ Literature_References */

/*     None. */

/* $ Author_and_Institution */

/*     N.J. Bachman    (JPL) */
/*     W.L. Taber      (JPL) */
/*     K.R. Gehringer  (JPL) */
/*     J.M. Lynch      (JPL) */

/* $ Version */

/* -    SPICELIB Version 2.0.0, 08-FEB-2010 (NJB) */

/*        The check for non-unit quaternions has been replaced */
/*        with a check for zero-length quaternions. */

/* -    SPICELIB Version 1.1.0, 26-FEB-2008 (NJB) */

/*        Updated header; added information about SPICE */
/*        quaternion conventions. */

/*        Minor typo in a long error message was corrected. */

/* -    SPICELIB Version 1.0.1, 07-JAN-2005 (NJB) */

/*        Description in Detailed_Input header section of */
/*        constraints on BEGTIM and ENDTIM was corrected. */

/* -    SPICELIB Version 1.0.0, 30-AUG-2002 (NJB) (KRG) (JML) (WLT) */

/* -& */
/* $ Index_Entries */

/*     write ck type_5 data segment */

/* -& */
/* $ Revisions */

/* -    SPICELIB Version 2.0.0, 08-FEB-2010 (NJB) */

/*        The check for non-unit quaternions has been replaced */
/*        with a check for zero-length quaternions. */

/*        This change was made to accommodate CK generation, */
/*        via the non-SPICE utility MEX2KER, for European missions. */

/* -& */

/*     SPICELIB functions */


/*     Local parameters */


/*     Packet structure parameters */


/*     Local variables */


/*     Standard SPICE error handling. */

    if (return_()) {
	return 0;
    } else {
	chkin_("CKW05", (ftnlen)5);
    }

/*     Make sure that the number of packets is positive. */

    if (*n < 1) {
	setmsg_("At least 1 packet is required for CK type 5. Number of pack"
		"ets supplied:  #", (ftnlen)75);
	errint_("#", n, (ftnlen)1);
	sigerr_("SPICE(TOOFEWPACKETS)", (ftnlen)20);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Make sure that there is a positive number of interpolation */
/*     intervals. */

    if (*nints <= 0) {
	setmsg_("# is an invalid number of interpolation intervals for type "
		"5.", (ftnlen)61);
	errint_("#", nints, (ftnlen)1);
	sigerr_("SPICE(INVALIDNUMINTS)", (ftnlen)21);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Get the NAIF integer code for the reference frame. */

    namfrm_(ref, &refcod, ref_len);
    if (refcod == 0) {
	setmsg_("The reference frame # is not supported.", (ftnlen)39);
	errch_("#", ref, (ftnlen)1, ref_len);
	sigerr_("SPICE(INVALIDREFFRAME)", (ftnlen)22);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Check to see if the segment identifier is too long. */

    if (lastnb_(segid, segid_len) > 40) {
	setmsg_("Segment identifier contains more than 40 characters.", (
		ftnlen)52);
	sigerr_("SPICE(SEGIDTOOLONG)", (ftnlen)19);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Now check that all the characters in the segment identifier */
/*     can be printed. */

    i__1 = lastnb_(segid, segid_len);
    for (i__ = 1; i__ <= i__1; ++i__) {
	chrcod = *(unsigned char *)&segid[i__ - 1];
	if (chrcod < 32 || chrcod > 126) {
	    setmsg_("The segment identifier contains nonprintable characters",
		     (ftnlen)55);
	    sigerr_("SPICE(NONPRINTABLECHARS)", (ftnlen)24);
	    chkout_("CKW05", (ftnlen)5);
	    return 0;
	}
    }

/*     Now check that the encoded SCLK times are positive and strictly */
/*     increasing. */

/*     Check that the first time is nonnegative. */

    if (sclkdp[0] < 0.) {
	setmsg_("The first SCLKDP time: # is negative.", (ftnlen)37);
	errdp_("#", sclkdp, (ftnlen)1);
	sigerr_("SPICE(INVALIDSCLKTIME)", (ftnlen)22);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Now check that the times are ordered properly. */

    i__1 = *n;
    for (i__ = 2; i__ <= i__1; ++i__) {
	if (sclkdp[i__ - 1] <= sclkdp[i__ - 2]) {
	    setmsg_("The SCLKDP times are not strictly increasing. SCLKDP(#)"
		    " = # and SCLKDP(#) = #.", (ftnlen)78);
	    errint_("#", &i__, (ftnlen)1);
	    errdp_("#", &sclkdp[i__ - 1], (ftnlen)1);
	    i__2 = i__ - 1;
	    errint_("#", &i__2, (ftnlen)1);
	    errdp_("#", &sclkdp[i__ - 2], (ftnlen)1);
	    sigerr_("SPICE(TIMESOUTOFORDER)", (ftnlen)22);
	    chkout_("CKW05", (ftnlen)5);
	    return 0;
	}
    }

/*     Now check that the interval start times are ordered properly. */

    i__1 = *nints;
    for (i__ = 2; i__ <= i__1; ++i__) {
	if (starts[i__ - 1] <= starts[i__ - 2]) {
	    setmsg_("The interval start times are not strictly increasing. S"
		    "TARTS(#) = # and STARTS(#) = #.", (ftnlen)86);
	    errint_("#", &i__, (ftnlen)1);
	    errdp_("#", &starts[i__ - 1], (ftnlen)1);
	    i__2 = i__ - 1;
	    errint_("#", &i__2, (ftnlen)1);
	    errdp_("#", &starts[i__ - 2], (ftnlen)1);
	    sigerr_("SPICE(TIMESOUTOFORDER)", (ftnlen)22);
	    chkout_("CKW05", (ftnlen)5);
	    return 0;
	}
    }

/*     Now make sure that all of the interval start times coincide with */
/*     one of the times associated with the actual pointing. */

    i__1 = *nints;
    for (i__ = 1; i__ <= i__1; ++i__) {

/*        We know the SCLKDP array is ordered, so a binary search is */
/*        ok. */

	if (bsrchd_(&starts[i__ - 1], n, sclkdp) == 0) {
	    setmsg_("Interval start time number # is invalid. STARTS(#) = *", 
		    (ftnlen)54);
	    errint_("#", &i__, (ftnlen)1);
	    errint_("#", &i__, (ftnlen)1);
	    errdp_("*", &starts[i__ - 1], (ftnlen)1);
	    sigerr_("SPICE(INVALIDSTARTTIME)", (ftnlen)23);
	    chkout_("CKW05", (ftnlen)5);
	    return 0;
	}
    }

/*     Set the window, packet size and angular velocity flag, all of */
/*     which are functions of the subtype. */

    if (*subtyp == 0) {
	winsiz = (*degree + 1) / 2;
	packsz = 8;
    } else if (*subtyp == 1) {
	winsiz = *degree + 1;
	packsz = 4;
    } else if (*subtyp == 2) {
	winsiz = (*degree + 1) / 2;
	packsz = 14;
    } else if (*subtyp == 3) {
	winsiz = *degree + 1;
	packsz = 7;
    } else {
	setmsg_("CK type 5 subtype <#> is not supported.", (ftnlen)39);
	errint_("#", subtyp, (ftnlen)1);
	sigerr_("SPICE(NOTSUPPORTED)", (ftnlen)19);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Make sure that the quaternions are non-zero. This is just */
/*     a check for uninitialized data. */

    i__1 = *n;
    for (i__ = 1; i__ <= i__1; ++i__) {

/*        We have to address the quaternion explicitly, since the shape */
/*        of the packet array is not known at compile time. */

	addr__ = packsz * (i__ - 1) + 1;
	if (vzerog_(&packts[addr__ - 1], &c__4)) {
	    setmsg_("The quaternion at index # has magnitude zero.", (ftnlen)
		    45);
	    errint_("#", &i__, (ftnlen)1);
	    sigerr_("SPICE(ZEROQUATERNION)", (ftnlen)21);
	    chkout_("CKW05", (ftnlen)5);
	    return 0;
	}
    }

/*     Make sure that the degree of the interpolating polynomials is */
/*     in range. */

    if (*degree < 1 || *degree > 15) {
	setmsg_("The interpolating polynomials have degree #; the valid degr"
		"ee range is [1, #]", (ftnlen)77);
	errint_("#", degree, (ftnlen)1);
	errint_("#", &c__15, (ftnlen)1);
	sigerr_("SPICE(INVALIDDEGREE)", (ftnlen)20);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Make sure that the window size is even.  If not, the input */
/*     DEGREE is incompatible with the subtype. */

    if (odd_(&winsiz)) {
	setmsg_("The interpolating polynomials have degree #; for CK type 5,"
		" the degree must be equivalent to 3 mod 4 for Hermite interp"
		"olation and odd for for Lagrange interpolation.", (ftnlen)166)
		;
	errint_("#", degree, (ftnlen)1);
	sigerr_("SPICE(INVALIDDEGREE)", (ftnlen)20);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     If we made it this far, we're ready to start writing the segment. */

/*     Create the segment descriptor. */

/*     Assign values to the integer components of the segment descriptor. */

    ic[0] = *inst;
    ic[1] = refcod;
    ic[2] = 5;
    if (*avflag) {
	ic[3] = 1;
    } else {
	ic[3] = 0;
    }
    dc[0] = *begtim;
    dc[1] = *endtim;

/*     Make sure the descriptor times are in increasing order. */

    if (*endtim < *begtim) {
	setmsg_("Descriptor bounds are non-increasing: #:#", (ftnlen)41);
	errdp_("#", begtim, (ftnlen)1);
	errdp_("#", endtim, (ftnlen)1);
	sigerr_("SPICE(BADDESCRTIMES)", (ftnlen)20);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Make sure that at least one time tag lies between BEGTIM and */
/*     ENDTIM.  The first time tag not less than BEGTIM must exist */
/*     and must be less than or equal to ENDTIM. */

    i__ = lstltd_(begtim, n, sclkdp);
    if (i__ == *n) {
	setmsg_("All time tags are less than segment start time #.", (ftnlen)
		49);
	errdp_("#", begtim, (ftnlen)1);
	sigerr_("SPICE(EMPTYSEGMENT)", (ftnlen)19);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    } else if (sclkdp[i__] > *endtim) {
	setmsg_("No time tags lie between the segment start time # and segme"
		"nt end time #", (ftnlen)72);
	errdp_("#", begtim, (ftnlen)1);
	errdp_("#", endtim, (ftnlen)1);
	sigerr_("SPICE(EMPTYSEGMENT)", (ftnlen)19);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     The clock rate must be non-zero. */

    if (*rate == 0.) {
	setmsg_("The SCLK rate RATE was zero.", (ftnlen)28);
	sigerr_("SPICE(INVALIDVALUE)", (ftnlen)19);
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     Now pack the segment descriptor. */

    dafps_(&c__2, &c__6, dc, ic, descr);

/*     Begin a new segment. */

    dafbna_(handle, descr, segid, segid_len);
    if (failed_()) {
	chkout_("CKW05", (ftnlen)5);
	return 0;
    }

/*     The type 5 segment structure is eloquently described by this */
/*     diagram from the CK Required Reading: */

/*        +-----------------------+ */
/*        | Packet 1              | */
/*        +-----------------------+ */
/*        | Packet 2              | */
/*        +-----------------------+ */
/*                    . */
/*                    . */
/*                    . */
/*        +-----------------------+ */
/*        | Packet N              | */
/*        +-----------------------+ */
/*        | Epoch 1               | */
/*        +-----------------------+ */
/*        | Epoch 2               | */
/*        +-----------------------+ */
/*                    . */
/*                    . */
/*                    . */
/*        +----------------------------+ */
/*        | Epoch N                    | */
/*        +----------------------------+ */
/*        | Epoch 100                  | (First directory) */
/*        +----------------------------+ */
/*                    . */
/*                    . */
/*                    . */
/*        +----------------------------+ */
/*        | Epoch ((N-1)/100)*100      | (Last directory) */
/*        +----------------------------+ */
/*        | Start time 1               | */
/*        +----------------------------+ */
/*        | Start time 2               | */
/*        +----------------------------+ */
/*                    . */
/*                    . */
/*                    . */
/*        +----------------------------+ */
/*        | Start time M               | */
/*        +----------------------------+ */
/*        | Start time 100             | (First interval start */
/*        +----------------------------+  time directory) */
/*                    . */
/*                    . */
/*                    . */
/*        +----------------------------+ */
/*        | Start time ((M-1)/100)*100 | (Last interval start */
/*        +----------------------------+  time directory) */
/*        | Seconds per tick           | */
/*        +----------------------------+ */
/*        | Subtype code               | */
/*        +----------------------------+ */
/*        | Window size                | */
/*        +----------------------------+ */
/*        | Number of interp intervals | */
/*        +----------------------------+ */
/*        | Number of packets          | */
/*        +----------------------------+ */


    i__1 = *n * packsz;
    dafada_(packts, &i__1);
    dafada_(sclkdp, n);
    i__1 = (*n - 1) / 100;
    for (i__ = 1; i__ <= i__1; ++i__) {
	dafada_(&sclkdp[i__ * 100 - 1], &c__1);
    }

/*     Now add the interval start times. */

    dafada_(starts, nints);

/*     And the directory of interval start times.  The directory of */
/*     start times will simply be every (DIRSIZ)th start time. */

    i__1 = (*nints - 1) / 100;
    for (i__ = 1; i__ <= i__1; ++i__) {
	dafada_(&starts[i__ * 100 - 1], &c__1);
    }

/*     Add the SCLK rate, segment subtype, window size, interval */
/*     count, and packet count. */

    dafada_(rate, &c__1);
    d__1 = (doublereal) (*subtyp);
    dafada_(&d__1, &c__1);
    d__1 = (doublereal) winsiz;
    dafada_(&d__1, &c__1);
    d__1 = (doublereal) (*nints);
    dafada_(&d__1, &c__1);
    d__1 = (doublereal) (*n);
    dafada_(&d__1, &c__1);

/*     As long as nothing went wrong, end the segment. */

    if (! failed_()) {
	dafena_();
    }
    chkout_("CKW05", (ftnlen)5);
    return 0;
} /* ckw05_ */