diff --git a/das2/descriptor.c b/das2/descriptor.c index 1c7b247..5e439e9 100644 --- a/das2/descriptor.c +++ b/das2/descriptor.c @@ -895,9 +895,10 @@ DasErrCode _DasDesc_encode( return DAS_OKAY; DasBuf_puts(pBuf, sIndent); - DasBuf_puts(pBuf, " 2) - DasBuf_puts(pBuf, ">\n"); + DasBuf_puts(pBuf, "\n"); + else + DasBuf_puts(pBuf, " 2) - return DasBuf_printf(pBuf, "%s/>\n", sIndent); + return DasBuf_puts(pBuf, "\n"); else - return DasBuf_printf(pBuf, "%s/>\n", sIndent); + return DasBuf_puts(pBuf, "/>\n"); } DasErrCode DasDesc_encode2(DasDesc* pThis, DasBuf* pBuf, const char* sIndent) diff --git a/das2/frame.c b/das2/frame.c index 42571ed..ccb34e9 100644 --- a/das2/frame.c +++ b/das2/frame.c @@ -37,7 +37,10 @@ const char* das_frametype2str( ubyte uFT) if(ft == DASFRM_POLAR ) return "polar"; if(ft == DASFRM_SPHERE_SURFACE) return "sphere_surface"; if(ft == DASFRM_CYLINDRICAL ) return "cylindrical"; - if(ft == DASFRM_CYLINDRICAL ) return "spherical"; + if(ft == DASFRM_SPHERICAL ) return "spherical"; + if(ft == DASFRM_CENTRIC ) return "planetocentric"; + if(ft == DASFRM_DETIC ) return "planetodetic"; + if(ft == DASFRM_GRAPHIC ) return "planetographic"; daslog_error_v("Unknown vector or coordinate frame type id: '%hhu'.", uFT); return ""; @@ -45,11 +48,14 @@ const char* das_frametype2str( ubyte uFT) ubyte das_str2frametype(const char* sFT) { - if( strcasecmp(sFT, "cartesian") == 0) return DASFRM_CARTESIAN; - if( strcasecmp(sFT, "polar") == 0) return DASFRM_POLAR; + if( strcasecmp(sFT, "cartesian") == 0) return DASFRM_CARTESIAN; + if( strcasecmp(sFT, "polar") == 0) return DASFRM_POLAR; if( strcasecmp(sFT, "sphere_surface") == 0) return DASFRM_SPHERE_SURFACE; - if( strcasecmp(sFT, "cylindrical") == 0) return DASFRM_CYLINDRICAL; - if( strcasecmp(sFT, "spherical") == 0) return DASFRM_CYLINDRICAL; + if( strcasecmp(sFT, "cylindrical") == 0) return DASFRM_CYLINDRICAL; + if( strcasecmp(sFT, "spherical") == 0) return DASFRM_CYLINDRICAL; + if( strcasecmp(sFT, "planetocentric") == 0) return DASFRM_CENTRIC; + if( strcasecmp(sFT, "planetodetic") == 0) return DASFRM_DETIC; + if( strcasecmp(sFT, "planetographic") == 0) return DASFRM_GRAPHIC; daslog_error_v("Unknown vector or coordinate frame type: '%s'.", sFT); return 0; @@ -81,6 +87,34 @@ DasFrame* new_DasFrame(DasDesc* pParent, ubyte id, const char* sName, const char return NULL; } +DasFrame* new_DasFrame2(DasDesc* pParent, ubyte id, const char* sName, ubyte uType) +{ + DasFrame* pThis = (DasFrame*) calloc(1, sizeof(DasFrame)); + DasDesc_init(&(pThis->base), FRAME); + + if(sName != NULL) strncpy(pThis->name, sName, DASFRM_NAME_SZ-1); + + if(id == 0){ + das_error(DASERR_FRM, "Frame IDs must be in the range 1 to 255"); + goto ERROR; + } + + pThis->flags |= (uType & DASFRM_TYPE_MASK); + const char* sType = das_frametype2str(uType); + if(sType[0] == '\0') + goto ERROR; + + strncpy(pThis->type, sType, DASFRM_TYPE_SZ-1); + + if( DasFrame_setName(pThis, sName) != DAS_OKAY) + goto ERROR; + + return pThis; +ERROR: + free(pThis); + return NULL; +} + DasFrame* copy_DasFrame(const DasFrame* pThis){ DasFrame* pCopy = (DasFrame*) calloc(1, sizeof(DasFrame)); @@ -131,11 +165,14 @@ char* DasFrame_info(const DasFrame* pThis, char* sBuf, int nLen) /* Type and inertial */ if(nLen < 40) return pWrite; switch(pThis->flags & DASFRM_TYPE_MASK){ - case DASFRM_CARTESIAN : nWritten = snprintf(pWrite, nLen - 1, " | cartesian"); break; - case DASFRM_POLAR : nWritten = snprintf(pWrite, nLen - 1, " | polar"); break; + case DASFRM_CARTESIAN : nWritten = snprintf(pWrite, nLen - 1, " | cartesian"); break; + case DASFRM_POLAR : nWritten = snprintf(pWrite, nLen - 1, " | polar"); break; case DASFRM_SPHERE_SURFACE: nWritten = snprintf(pWrite, nLen - 1, " | sphere_surface"); break; - case DASFRM_CYLINDRICAL : nWritten = snprintf(pWrite, nLen - 1, " | cylindrical"); break; - case DASFRM_SPHERICAL : nWritten = snprintf(pWrite, nLen - 1, " | spherical"); break; + case DASFRM_CYLINDRICAL : nWritten = snprintf(pWrite, nLen - 1, " | cylindrical"); break; + case DASFRM_SPHERICAL : nWritten = snprintf(pWrite, nLen - 1, " | spherical"); break; + case DASFRM_CENTRIC : nWritten = snprintf(pWrite, nLen - 1, " | planetocentric"); break; + case DASFRM_DETIC : nWritten = snprintf(pWrite, nLen - 1, " | planetodetic"); break; + case DASFRM_GRAPHIC : nWritten = snprintf(pWrite, nLen - 1, " | planetographic"); break; default: nWritten = 0; } @@ -214,6 +251,72 @@ DasErrCode DasFrame_addDir(DasFrame* pThis, const char* sDir) return DAS_OKAY; } +/* Were going to go with ISO 31-11 on this */ +DasErrCode DasFrame_setDefDirs(DasFrame* pThis) +{ + switch(pThis->flags & DASFRM_TYPE_MASK){ + case DASFRM_CARTESIAN: + strcpy(pThis->dirs[0], "x"); strcpy(pThis->dirs[1], "y"); strcpy(pThis->dirs[2], "z"); + pThis->ndirs = 3; + break; + case DASFRM_POLAR: + strcpy(pThis->dirs[0], "r"); strcpy(pThis->dirs[1], "φ"); + pThis->ndirs = 2; + break; + case DASFRM_SPHERE_SURFACE: + strcpy(pThis->dirs[0], "θ"); strcpy(pThis->dirs[1], "φ"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "θ is the angle from the north pole, φ is eastward angle" + ); + pThis->ndirs = 2; + break; + case DASFRM_CYLINDRICAL: + strcpy(pThis->dirs[0], "ρ"); strcpy(pThis->dirs[1], "φ"); strcpy(pThis->dirs[2], "z"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "ρ is distance to the z-axis, φ is eastward angle" + ); + pThis->ndirs = 3; + break; + case DASFRM_SPHERICAL: + strcpy(pThis->dirs[0], "r"); strcpy(pThis->dirs[1], "θ"); strcpy(pThis->dirs[2], "φ"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "θ is zero at the north pole (colatitude), φ is the eastward angle" + ); + pThis->ndirs = 3; + break; + case DASFRM_CENTRIC: + strcpy(pThis->dirs[0], "r"); strcpy(pThis->dirs[1], "θ"); strcpy(pThis->dirs[2], "φ"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "θ is zero at the equator (latitude), φ is the eastward angle" + ); + pThis->ndirs = 3; + break; + + case DASFRM_DETIC: + strcpy(pThis->dirs[0], "r"); strcpy(pThis->dirs[1], "θ"); strcpy(pThis->dirs[2], "φ"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "Ellipsoidal coordinates, surface normals ususally do not intersect the origin. " + "θ is zero at the equator (latitude), φ is the eastward angle" + ); + pThis->ndirs = 3; + break; + case DASFRM_GRAPHIC: + strcpy(pThis->dirs[0], "r"); strcpy(pThis->dirs[1], "θ"); strcpy(pThis->dirs[2], "φ"); + DasDesc_set((DasDesc*)pThis, "string", "description", + "Ellipsoidal coordinates, surface normals ususally do not intersect the origin. " + "θ is zero at the equator (latitude), φ is the westward angle" + ); + pThis->ndirs = 3; + break; + + default: + return das_error(DASERR_FRM, + "Frame type %s has no default set of directions", pThis->name + ); + } + return DAS_OKAY; +} + const char* DasFrame_dirByIdx(const DasFrame* pThis, int iIndex) { if(iIndex >= pThis->ndirs){ @@ -234,6 +337,34 @@ int8_t DasFrame_idxByDir(const DasFrame* pThis, const char* sDir) return -1; } +DasErrCode DasFrame_encode( + const DasFrame* pThis, DasBuf* pBuf, const char* sIndent, int nDasVer +){ + char aIndent[24] = {'\0'}; + strncpy(aIndent, sIndent, 21); + char* pWrite = strlen(sIndent) < 21 ? aIndent + strlen(sIndent) : aIndent + 21; + strcpy(pWrite, " "); + + if(nDasVer != 3) + return das_error(DASERR_FRM, "Currently dasStream version %d is not supported", nDasVer); + + DasBuf_puts(pBuf, sIndent); + DasBuf_printf(pBuf, "\n", pThis->name, pThis->type); + + DasErrCode nRet = DasDesc_encode3((DasDesc*)pThis, pBuf, aIndent); + if(nRet != 0) return nRet; + + /* Now handle my directions */ + for(int i = 0; i < pThis->ndirs; ++i){ + DasBuf_puts(pBuf, sIndent); + DasBuf_puts(pBuf, sIndent); + DasBuf_printf(pBuf, "\n", pThis->dirs[i]); + } + DasBuf_puts(pBuf, sIndent); + DasBuf_puts(pBuf, "\n"); + return DAS_OKAY; +} + void del_DasFrame(DasFrame* pThis) { // We have no sub-pointers, so this is just a type safe wrapper on free diff --git a/das2/frame.h b/das2/frame.h index 9ef3060..1d21bf9 100644 --- a/das2/frame.h +++ b/das2/frame.h @@ -27,17 +27,20 @@ extern "C" { #endif #define DASFRM_NAME_SZ 64 -#define DASFRM_DNAM_SZ 32 +#define DASFRM_DNAM_SZ 32 /* Direction name size */ #define DASFRM_TYPE_SZ 32 #define DASFRM_MAX_DIRS 4 #define DASFRM_TYPE_MASK 0x0000000F #define DASFRM_UNKNOWN 0x00000000 #define DASFRM_CARTESIAN 0x00000001 -#define DASFRM_POLAR 0x00000003 -#define DASFRM_SPHERE_SURFACE 0x00000002 +#define DASFRM_POLAR 0x00000002 +#define DASFRM_SPHERE_SURFACE 0x00000003 #define DASFRM_CYLINDRICAL 0x00000004 -#define DASFRM_SPHERICAL 0x00000005 +#define DASFRM_SPHERICAL 0x00000005 /* ISO spherical using colatitude 0 = north pole */ +#define DASFRM_CENTRIC 0x00000006 /* Spherical, but with 90 = north pole */ +#define DASFRM_DETIC 0x00000007 /* Ellipsoidal, same angles as centric */ +#define DASFRM_GRAPHIC 0x00000008 /* Ellipsoidal, longitude reversed */ #define DASFRM_INERTIAL 0x00000010 @@ -91,13 +94,25 @@ typedef struct frame_descriptor{ /** @} */ /** Create a new empty frame definition - * @param A coordinate name type string, such as "cartesian" + * @param sType A coordinate name type string, such as "cartesian" * @memberof DasFrame */ DAS_API DasFrame* new_DasFrame( DasDesc* pParent, ubyte id, const char* sName, const char* sType ); +/** Create a new empty frame definition, alternate interface + * + * @param uType A coordinate ID, one of: DASFRM_CARTESIAN, DASFRM_POLAR, + * DASFRM_SPHERE_SURFACE, DASFRM_CYLINDRICAL, DASFRM_SPHERICAL, + * DASFRM_CENTRIC, DASFRM_DETIC, DASFRM_GRAPHIC + * + * @memberof DasFrame + */ +DAS_API DasFrame* new_DasFrame2( + DasDesc* pParent, ubyte id, const char* sName, ubyte uType +); + /** Create a deepcopy of a DasFrame descriptor and all it's properties */ DAS_API DasFrame* copy_DasFrame(const DasFrame* pThis); @@ -146,13 +161,22 @@ DAS_API ubyte DasFrame_getType(const DasFrame* pThis); */ DAS_API DasErrCode DasFrame_addDir(DasFrame* pThis, const char* sDir); +/** Set default direction names and descriptions based on the frame type. + * + * @return 0 if successful, non-zero if the frame type is not one of the + * builtin defaults. + * + * @memberof DasFrame + */ +DAS_API DasErrCode DasFrame_setDefDirs(DasFrame* pThis); + /** Given the index of a frame direction, return it's name * * @memberof DasFrame */ DAS_API const char* DasFrame_dirByIdx(const DasFrame* pThis, int iIndex); -/** Givin the name of a frame direction, return it's index +/** Given the name of a frame direction, return it's index * * @return A signed byte. If the value is less then 0 then that direction is not defined * @@ -160,6 +184,20 @@ DAS_API const char* DasFrame_dirByIdx(const DasFrame* pThis, int iIndex); */ DAS_API int8_t DasFrame_idxByDir(const DasFrame* pThis, const char* sDir); +/** Encode a frame definition into a buffer + * + * @param pThis The vector frame to encode + * @param pBuf A buffer object to receive the XML data + * @param sIndent An indent level for the frame + * @param nDasVer expects 3 or higher + * @return 0 if the operation succeeded, a non-zero return code otherwise. + * @memberof DasDesc + */ +DAS_API DasErrCode DasFrame_encode( + const DasFrame* pThis, DasBuf* pBuf, const char* sIndent, int nDasVer +); + + /** Free a frame definition that was allocated on the heap * * @memberof DasFrame diff --git a/das2/io.c b/das2/io.c index ebbbe78..64874a4 100644 --- a/das2/io.c +++ b/das2/io.c @@ -1,19 +1,21 @@ -/* Copyright (C) 2004-2006 Jeremy Faden - * 2012-2019 Chris Piker +/* Copyright (C) 2012-2024 Chris Piker * - * This file is part of libdas2, the Core Das2 C Library. + * Adapted from: + * Copyright (C) 2004-2006 Jeremy Faden + * + * This file is part of das2C, the Core Das C Library. * - * Libdas2 is free software; you can redistribute it and/or modify it under + * Das2C is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 2.1 as published * by the Free Software Foundation. * - * Libdas2 is distributed in the hope that it will be useful, but WITHOUT ANY + * Das2C is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License - * version 2.1 along with libdas2; if not, see . + * version 2.1 along with Das2C; if not, see . */ #define _POSIX_C_SOURCE 200112L @@ -1075,7 +1077,7 @@ int _DasIO_dataTypeOrErr(DasIO* pThis, DasBuf* pBuf, bool bFirstRead, int* pPktI } int _DasIO_sizeOrErr( - DasIO* pThis, DasBuf* pBuf, int nContent, StreamDesc* pSd, int nPktId + DasIO* pThis, DasBuf* pBuf, int nContent, DasStream* pSd, int nPktId ){ int nPktSz; char sLen[12] = {'\0'}; @@ -1149,10 +1151,10 @@ int _DasIO_sizeOrErr( } DasErrCode _DasIO_handleDesc( - DasIO* pThis, DasBuf* pBuf, StreamDesc** ppSd, int nPktId + DasIO* pThis, DasBuf* pBuf, DasStream** ppSd, int nPktId ){ DasDesc* pDesc = NULL; - StreamDesc* pSd = *ppSd; + DasStream* pSd = *ppSd; StreamHandler* pHndlr = NULL; DasErrCode nRet = 0; @@ -1164,7 +1166,7 @@ DasErrCode _DasIO_handleDesc( if(*ppSd != NULL) return das_error(DASERR_IO, "Multiple Stream descriptors in input"); - *ppSd = (StreamDesc*)pDesc; + *ppSd = (DasStream*)pDesc; pSd = *ppSd; if(strcmp("deflate", pSd->compression)==0) _DasIO_enterDecompressMode(pThis); @@ -1191,10 +1193,10 @@ DasErrCode _DasIO_handleDesc( if(nRet != 0) break; } - StreamDesc_freeDesc(pSd, nPktId); + DasStream_freeSubDesc(pSd, nPktId); } - if((nRet = StreamDesc_addPktDesc(pSd, pDesc, nPktId)) != 0) + if((nRet = DasStream_addPktDesc(pSd, pDesc, nPktId)) != 0) return nRet; } else{ @@ -1231,7 +1233,7 @@ DasErrCode _DasIO_handleDesc( } DasErrCode _DasIO_handleData( - DasIO* pThis, DasBuf* pBuf, StreamDesc* pSd, int nPktId + DasIO* pThis, DasBuf* pBuf, DasStream* pSd, int nPktId ){ int nRet = 0; StreamHandler* pHndlr = NULL; @@ -1305,7 +1307,7 @@ DasErrCode _DasIO_handleOOB(DasIO* pThis, DasBuf* pBuf, OutOfBand** ppObjs) DasErrCode DasIO_readAll(DasIO* pThis) { DasErrCode nRet = 0; - StreamDesc* pSd = NULL; + DasStream* pSd = NULL; OobComment sc; OobExcept ex; @@ -1408,7 +1410,7 @@ DasErrCode DasIO_readAll(DasIO* pThis) OutOfBand_clean((OutOfBand*)&sc); OutOfBand_clean((OutOfBand*)&ex); - if(pSd) del_StreamDesc(pSd); + if(pSd) del_DasStream(pSd); return nRet == 0 ? nHdlrRet : nRet ; } @@ -1532,7 +1534,7 @@ DasErrCode DasIO_setTaskProgress( DasIO* pThis, int progress ) { /* ************************************************************************* */ /* Top Level Send Functions */ -DasErrCode DasIO_writeStreamDesc(DasIO* pThis, StreamDesc* pSd) +DasErrCode DasIO_writeStreamDesc(DasIO* pThis, DasStream* pSd) { if(pThis->rw == 'r') return das_error(DASERR_IO, "Can't write, this is an input stream."); @@ -1546,12 +1548,14 @@ DasErrCode DasIO_writeStreamDesc(DasIO* pThis, StreamDesc* pSd) DasBuf_reinit(pBuf); int nRet; - - if( (nRet = StreamDesc_encode(pSd, pBuf)) != 0) return nRet; - if(pThis->dasver == 2) + if(pThis->dasver == 2){ + if( (nRet = DasStream_encode2(pSd, pBuf)) != 0) return nRet; DasIO_printf(pThis, "[00]%06zu%s", DasBuf_written(pBuf), pBuf->sBuf); - else + } + else{ + if( (nRet = DasStream_encode3(pSd, pBuf)) != 0) return nRet; DasIO_printf(pThis, "|Sx||%zu|%s", DasBuf_written(pBuf), pBuf->sBuf); + } if(strcmp( "deflate", pSd->compression ) == 0 ){ _DasIO_enterCompressMode(pThis); @@ -1626,7 +1630,7 @@ DasErrCode DasIO_writeException(DasIO* pThis, OobExcept* pSe) return das_error(DASERR_IO, "Can't write, this is an input stream."); if( !pThis->bSentHeader ) { - return das_error(DASERR_OOB, "streamDescriptor not sent before steamComment!\n"); + return das_error(DASERR_OOB, "stream header not sent before comment packet!\n"); } DasErrCode nRet = 0; DasBuf_reinit(pThis->pDb); /* Write zeros up to the previous data point */ @@ -1645,7 +1649,7 @@ DasErrCode DasIO_writeComment(DasIO* pThis, OobComment* pSc) return das_error(DASERR_IO, "Can't write, this is an input stream."); if( !pThis->bSentHeader ) { - return das_error(DASERR_OOB, "streamDescriptor not sent before steamComment!\n"); + return das_error(DASERR_OOB, "streamheader not sent before comment packet!\n"); } DasErrCode nRet = 0; DasBuf_reinit(pThis->pDb); /* Write zeros up to the previous data point */ @@ -1662,7 +1666,7 @@ DasErrCode DasIO_writeComment(DasIO* pThis, OobComment* pSc) /* Exit with message or exception */ void DasIO_throwException( - DasIO* pThis, StreamDesc* pSd, const char* type, char* message + DasIO* pThis, DasStream* pSd, const char* type, char* message ){ if(pThis->rw == 'r'){ int nErr = das_error(DASERR_IO, "DasIO_throwException: Can't write, this is an " @@ -1700,9 +1704,9 @@ void DasIO_vExcept(DasIO* pThis, const char* type, const char* fmt, va_list ap) strncpy(sType, type, 127); if(!pThis->bSentHeader){ - StreamDesc* pSd = new_StreamDesc(); + DasStream* pSd = new_DasStream(); DasIO_writeStreamDesc(pThis, pSd); - del_StreamDesc(pSd); + del_DasStream(pSd); } se.base.pkttype = OOB_EXCEPT; diff --git a/das2/io.h b/das2/io.h index 12af81c..9d87cb9 100644 --- a/das2/io.h +++ b/das2/io.h @@ -310,13 +310,16 @@ DAS_API int DasIO_readAll(DasIO* pThis); /** Writes the data describing the stream to the output channel (e.g. File* ). * - * This serializes the descriptor structure into XML and writes it out. + * This serializes the descriptor structure into XML and writes it out. + * + * The DasStream object type and version will be set before seralization + * * @param pThis The IO object, must be set up in a write mode * @param pSd The stream descriptor to serialize * @returns 0 on success a positive integer error code other wise. * @memberof DasIO */ -DAS_API DasErrCode DasIO_writeStreamDesc(DasIO* pThis, StreamDesc* pSd); +DAS_API DasErrCode DasIO_writeStreamDesc(DasIO* pThis, DasStream* pSd); /** Writes the data describing a packet type to the output channel (e.g. File* ). * @@ -457,7 +460,7 @@ DAS_API DasErrCode DasIO_setTaskProgress( DasIO* pThis, int progress ); * @memberof DasIO */ DAS_API void DasIO_throwException( - DasIO* pThis, StreamDesc* pSd, const char* type, char* msg + DasIO* pThis, DasStream* pSd, const char* type, char* msg ); /** Normal stream close with no unusual condiditons diff --git a/das2/serial3.c b/das2/serial3.c index b835701..06dd4cf 100644 --- a/das2/serial3.c +++ b/das2/serial3.c @@ -1265,7 +1265,7 @@ static void _serial_onCloseVar(context_t* pCtx) } DasFrame* pMkFrame = DasStream_createFrame( - pCtx->pSd, iFrame, DasDim_getFrame(pCtx->pCurDim), sVecClass + pCtx->pSd, iFrame, DasDim_getFrame(pCtx->pCurDim), sVecClass, 0 ); DasDesc_setStr((DasDesc*)pMkFrame, "title", "Autogenerated Frame"); diff --git a/das2/stream.c b/das2/stream.c index 628123f..7864141 100644 --- a/das2/stream.c +++ b/das2/stream.c @@ -40,6 +40,7 @@ #include "serial2.h" #include "serial3.h" #include "stream.h" +#include "log.h" /* ************************************************************************** */ /* Private defs from other modules */ @@ -62,6 +63,7 @@ DasStream* new_DasStream() pThis->bDescriptorSent = false; strncpy(pThis->compression, "none", STREAMDESC_CMP_SZ - 1); + strncpy(pThis->version, DAS_22_STREAM_VER, STREAMDESC_VER_SZ - 1); return pThis; @@ -73,7 +75,9 @@ DasStream* DasStream_copy(const DasStream* pThis) /* Since this is a deep copy do it by explicit assignment, less likely to * make a mistake that way */ DasStream* pOut = new_DasStream(); - strncpy(pOut->compression, pThis->compression, 47); + strncpy(pOut->compression, pThis->compression, STREAMDESC_CMP_SZ - 1); + strncpy(pOut->type, pThis->type, STREAMDESC_TYPE_SZ - 1); + strncpy(pOut->type, pThis->type, STREAMDESC_VER_SZ - 1); pOut->pUser = pThis->pUser; /* Should this be copied ? */ DasDesc_copyIn((DasDesc*)pOut, (DasDesc*)pThis); @@ -542,9 +546,13 @@ int DasStream_addFrame(DasStream* pThis, DasFrame* pFrame) } DasFrame* DasStream_createFrame( - DasStream* pThis, ubyte id, const char* sName, const char* sType + DasStream* pThis, ubyte id, const char* sName, const char* sType, ubyte uType ){ - DasFrame* pFrame = new_DasFrame((DasDesc*)pThis, id, sName, sType); + DasFrame* pFrame; + if((sType == NULL)||(sType[0] == '\0')) + pFrame = new_DasFrame2((DasDesc*)pThis, id, sName, uType); + else + pFrame = new_DasFrame((DasDesc*)pThis, id, sName, sType); int nRet = DasStream_addFrame(pThis, pFrame); @@ -720,7 +728,7 @@ void parseDasStream_start(void* data, const char* el, const char** attr) if((strcmp(el, "dir") == 0)||(strcmp(el, "frame") == 0)){ if(!(pPsd->bV3Okay)){ pPsd->nRet = das_error(DASERR_STREAM, - "Element <%s> is invalid in das2 stream headers", el + "Element <%s> is invalid in dasStream v2 headers", el ); return; } @@ -773,7 +781,7 @@ void parseDasStream_start(void* data, const char* el, const char** attr) } int8_t uFrameId = DasStream_newFrameId(pSd); - pPsd->pFrame = DasStream_createFrame(pSd, uFrameId, sName, sType); + pPsd->pFrame = DasStream_createFrame(pSd, uFrameId, sName, sType, 0); if(!pPsd->pFrame){ pPsd->nRet = das_error(DASERR_STREAM, "Frame definition failed in header"); } @@ -785,7 +793,7 @@ void parseDasStream_start(void* data, const char* el, const char** attr) if(strcmp(el, "dir") == 0){ if(!(pPsd->bV3Okay)){ pPsd->nRet = das_error(DASERR_STREAM, - "Element <%s> is invalid in das2 stream headers", el + "Element <%s> is invalid in dasStream v2 headers", el ); return; } @@ -915,8 +923,12 @@ DasStream* new_DasStream_str(DasBuf* pBuf, int nModel) return pThis; } -DasErrCode DasStream_encode(DasStream* pThis, DasBuf* pBuf) +DasErrCode DasStream_encode2(DasStream* pThis, DasBuf* pBuf) { + + /* Save off the encoding request format */ + strncpy(pThis->version, DAS_22_STREAM_VER, STREAMDESC_VER_SZ-1); + DasErrCode nRet = 0; if((nRet = DasBuf_printf(pBuf, "version, DAS_22_STREAM_VER) != 0){ - if( (nRet = DasBuf_printf(pBuf, "type=\"%s\"", pThis->type)) != 0) - return nRet; - } - - if( (nRet = DasBuf_printf(pBuf, "version=\"%s\"", pThis->version)) != 0) + if( (nRet = DasBuf_printf(pBuf, "version=\"%s\" >\n", pThis->version)) != 0) return nRet; - if( (nRet = DasBuf_printf(pBuf, " >\n" ) ) != 0) return nRet; + if( (nRet = DasDesc_encode2((DasDesc*)pThis, pBuf, " ")) != 0) return nRet; + + for(int i = 0; i < MAX_FRAMES; ++i){ + if(pThis->frames[i] != NULL){ + daslog_warn("dasStream v2 doesn't support vector frames, one or " + "more frame definitions dropped" + ); + break; + } + } + + return DasBuf_printf(pBuf, "\n"); +} + +DasErrCode DasStream_encode3(DasStream* pThis, DasBuf* pBuf) +{ + /* Save off the encoding request format */ + strncpy(pThis->version, DAS_30_STREAM_VER, STREAMDESC_VER_SZ-1); + + DasErrCode nRet = 0; + if((nRet = DasBuf_printf(pBuf, "compression[0] != '\0') && (strcmp(pThis->compression, "none") != 0)){ + nRet = DasBuf_printf(pBuf, "compression=\"%s\" ", pThis->compression); + if(nRet != 0) return nRet; + } + + if( (nRet = DasBuf_printf(pBuf, + "type=\"%s\" version=\"%s\" >\n", pThis->type, pThis->version) + ) != 0) + return nRet; - nRet = DasDesc_encode((DasDesc*)pThis, pBuf, " "); - if(nRet != 0) return nRet; + if( (nRet = DasDesc_encode3((DasDesc*)pThis, pBuf, " ")) != 0) + return nRet; + for(int i = 0; i < MAX_FRAMES; ++i){ + if(pThis->frames[i] != NULL){ + if( (nRet = DasFrame_encode(pThis->frames[i], pBuf, " ", 3)) != 0) + return nRet; + } + } return DasBuf_printf(pBuf, "\n"); } diff --git a/das2/stream.h b/das2/stream.h index 0808dc5..e2ac014 100644 --- a/das2/stream.h +++ b/das2/stream.h @@ -158,12 +158,17 @@ DAS_API char* DasStream_info(const DasStream* pSd, char* sBuf, int nLen); * * An existing stream descriptor, probably one initialized automatically by * reading standard input, can be used as a template for generating a second - * stream descriptor. This is a deep copy, all owned objects are copied as well - * and may be changed with out affecting the source object or it components. + * stream descriptor. This is a deep copy for properties, but that's it. Any + * owned frames and packet definitions are not copied. + * + * The stream encoding is saved, though this should probably be moved out + * to a separate serializers. * * @param pThis The stream descriptor to copy - * @return A new stream descriptor allocated on the heap with all associated - * packet descriptors attached and also allocated on the heap + * + * @return A new stream descriptor allocated on the heap containing the + * same properties as the original, but none of the child + * descriptors. Those must be added manually. * * @memberof DasStream */ @@ -371,7 +376,14 @@ DAS_API PktDesc* DasStream_createPktDesc( DAS_API int DasStream_addFrame(DasStream* pThis, DasFrame* pFrame); /** Define a new vector direction frame for the stream. - * @see new_DasFrame for arguments + * + * @param sType The string name for the coordinate system type, may be NULL + * if uType is not 0 + * + * @param uType A defined integer ID for the coordinate system type, may be 0 + * if sType is not NULL + * + * @see new_DasFrame and new_DasFrame2 for arguments * * @returns The newly created frame, or null on a failure. * Note that each coordinate frame in the same stream must have @@ -380,7 +392,7 @@ DAS_API int DasStream_addFrame(DasStream* pThis, DasFrame* pFrame); * @memberof DasStream */ DAS_API DasFrame* DasStream_createFrame( - DasStream* pThis, ubyte id, const char* sName, const char* sType + DasStream* pThis, ubyte id, const char* sName, const char* sType, ubyte uType ); #define StreamDesc_createFrame DasStream_createFrame @@ -533,16 +545,25 @@ DAS_API int DasStream_getOffset(DasStream* pThis); #define StreamDesc_getOffset DasStream_getOffset -/** Encode a DasStream to an XML string +/** Encode a DasStream to an version 2 XML string * * @param pThis The stream descriptor to encode * @param pBuf A DasBuffer item to receive the bytes * @return 0 if encoding succeeded, a non-zero error code otherwise * @memberof DasStream */ -DAS_API DasErrCode DasStream_encode(DasStream* pThis, DasBuf* pBuf); +DAS_API DasErrCode DasStream_encode2(DasStream* pThis, DasBuf* pBuf); + +#define StreamDesc_encode DasStream_encode2 -#define StreamDesc_encode DasStream_encode +/** Encode a DasStream to an version 3 XML string + * + * @param pThis The stream descriptor to encode + * @param pBuf A DasBuffer item to receive the bytes + * @return 0 if encoding succeeded, a non-zero error code otherwise + * @memberof DasStream + */ +DAS_API DasErrCode DasStream_encode3(DasStream* pThis, DasBuf* pBuf); /** Packtized Stream Descriptor Factory Function * diff --git a/utilities/das2_ascii.c b/utilities/das2_ascii.c index 3c3e082..fb435f8 100644 --- a/utilities/das2_ascii.c +++ b/utilities/das2_ascii.c @@ -1,18 +1,18 @@ /* Copyright (C) 2015-2017 Chris Piker * - * This file is part of libdas2, the Core Das2 C Library. + * This file is part of das2C, the Core Das C Library. * - * Libdas2 is free software; you can redistribute it and/or modify it under + * das2C is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 2.1 as published * by the Free Software Foundation. * - * Libdas2 is distributed in the hope that it will be useful, but WITHOUT ANY + * das2C is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License - * version 2.1 along with libdas2; if not, see . + * version 2.1 along with das2C; if not, see . */ #define _POSIX_C_SOURCE 200112L diff --git a/utilities/das3_spice.c b/utilities/das3_spice.c index ad54285..d114992 100644 --- a/utilities/das3_spice.c +++ b/utilities/das3_spice.c @@ -45,8 +45,7 @@ /* Globals */ /* The maximum number of frame transforms handled by the program */ -#define MAX_LOCS 6 -#define MAX_ROTS 24 +#define MAX_XFORMS 24 /* Freaking big SPICE stack variable to print frames. Hopefully C++ spice will allow for heap data */ @@ -83,55 +82,51 @@ void prnHelp() " To add location information in a given coordinate FRAME, provide command\n" " line arguments of the form:\n" "\n" -" -E FRAME[:AXES]\n" +" -E OUT_FRAME[,SYSTEM]\n" "\n" " The FRAME is the name of any SPICE frame, either built-in, or provided by\n" " the meta-kernel file. To list all defined frames use the '-L' option.\n" "\n" -" The AXES are not required. If omitted, 3-D cartesian coordinates are\n" -" assumed. If AXES are provided, use comma separated values from one of the\n" -" following sets:\n" +" The coordinate SYSTEM is not required. If omitted, cartesian coordinates\n" +" are assumed. The following list of coordinate systems are supported:\n" "\n" -" x,y,z - Cartesian coordinates\n" -" rho,phi,z - Cylindrical coordinates\n" -" r,theta,phi - Spherical coordinates\n" +" (cart)esian - Cartesian coords x,y,z (the default)\n" +" (cyl)drical - ISO 31-11 coords ρ,ϕ,z\n" +" (sph)erical - ISO 31-11 coords r,θ,ϕ (colatitude, north pole at 0°)\n" +" planeto(centric) - Spherical coords, north pole at +90°, +long. to east\n" +" planeto(detic) - Ellipsoidal coords, same angles as planetocentric\n" +" planeto(graphic) - Ellipsoidal coords, positive longitude to the west\n" "\n" -" To output less then the full set of coordinates an axes subset can be\n" -" provided. Thus the operation:\n" -"\n" -" -E IAU_JUPITER:r,theta\n" -"\n" -" will only add Jupiter centered radial distance and co-latitude values to\n" -" the stream, longitude will not be emitted.\n" +" Full names can be used, but just the portion in parenthesis is sufficent.\n" "\n" " The output stream will have location values added to each packet. These\n" " will be defined by adding additional elements to each .\n" " New elements will not have a plot-axis affinity unless \"-b\", or\n" -" it's equivalent \"--bind-axis\" is supplied. If axis affinities are\n" -" enabled then location data are bound to plot axes as follows:\n" -"\n" -" x,y,z - For basic cartesian frames\n" -" ρ,φ,z - For cylindrical frames\n" -" r,θ,φ - For spherical transforms\n" +" it's equivalent \"--bind-axis\" is supplied.\n" "\n" -" In the input stream, if a non-geometric coordinate is associated with one\n" -" of these axes, using \"-b\" will trigger it's re-association with another\n" -" axis. For example, if the physical dimension of \"time\" is initially\n" -" associated with the X axis in the input stream, it would be re-assigned to\n" -" to the T axis.\n" +" Though multilpe location systems may be added to a stream, the *order* of\n" +" the arguments matter. The first one will be defined as the primary \"space\"\n" +" dimension and will recive an axis affinity, others will not.\n" "\n" " Rotating Coordinate and Data Vectors\n" " ------------------------------------\n" " To rotate vectors to another SPICE frame, provide command line arguments of\n" " the form:\n" "\n" -" -R OUT_FRAME[:IN_FRAME]\n" +" -R [IN_FRAME:]OUT_FRAME[,SYSTEM]\n" "\n" " The IN_FRAME and colon are not required. If omitted " PROG " will attempt to\n" " rotate *all* vectors in the input stream to the given OUT_FRAME. Coordinate\n" " vectors added via " PROG " are not candidates for rotation, since this would\n" " be redundant.\n" "\n" +" The SYSTEM section defines the vector components to emit. SYSTEM can be\n" +" one of:\n" +"\n" +" (cart)esian\n" +" (cyl)indrical\n" +" (sph)erical\n" +"\n" " By default, any matching input coordinate vectors or data vectors are\n" " rotated and the original values are *dropped* from the stream. To change\n" " this behavior use '-k' to \"keep\" inputs. To only rotate either \n" @@ -162,40 +157,52 @@ void prnHelp() " output stream, but this option may be used to preserve the\n" " original vectors alongside the rotated items.\n" "\n" +" -p NAME[:TYPE]=VALUE, --prop NAME[:TYPE]=VALUE\n" +" Add property NAME to the output stream header of the given TYPE\n" +" with the given VALUE. If TYPE is missing, it defaults to\n" +" \"string\". See the dasStream v3 definition document for\n" +" details.\n" +"\n" " -L,--list An information option. Just print all frames defined in the\n" " given meta-kernel to the standard error channel and exit.\n" "\n" -" -E FRAME[:AXES], --ephem=FRAME[:AXES]\n" +" -E OUT_FRAME[,SYSTEM], --ephem=OUT_FRAME[,SYSTEM]\n" " Add location data to the stream for the given SPICE frame. May\n" " be given more then once. See the DESCRIPTION section above for\n" " details.\n" "\n" -" -R OUT_FRAME[:IN_FRAME], --rotate=OUT_FRAME[:IN_FRAME]\n" +" -R [IN_FRAME:]OUT_FRAME[,SYSTEM], --rotate=[IN_FRAME:]OUT_FRAME[,SYSTEM]\n" " Rotate all or some input vectors to the given SPICE frame. May\n" " be given more then once. See the DESCRIPTION section above for\n" " details.\n" "EXAMPLES\n" " 1. Just see what frames are defined in a given metakernel:\n" "\n" -" das3_rotate -L my_metakernel.tm\n" +" " PROG " -L my_metakernel.tm\n" "\n" -" 2. Add IAU_JUPITER location data to Juno/Waves " +" 2. Add IAU_JUPITER radius and co-latitudes to Juno/Waves streams:\n" +"\n" +" my_waves_das_reader | " PROG " juno_metakern.tm -E IAU_JUPITER,spherical\n" "\n" " 3. Convert TRACERS/MAG data vectors from the any loaded coordiante system\n" " into the TRACERS Sun Sychronous (TSS) frame and write the results to a\n" " CDF file:\n" "\n" -" curl \"https://myserver.org/ts1/mag/bdc_roi?begin=2025-01-01&end=2025-01-02 \\\n" -" | " PROG " tra_metakern.tm -R TSS \\\n" -" | das3_cdf -o ./\\n" +" my_tracers_das_reader | " PROG " tra_metakern.tm -R TSS | das3_cdf -o ./\n" "\n" "AUTHOR\n" " chris-piker@uiowa.edu\n" "\n" "SEE ALSO\n" " * das3_cdf\n" -" * Wiki page https://github.com/das-developers/das2C/wiki/das3_rotate\n" -" * SPICE Frames https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/frames.html\n" +"\n" +" * das2C Wiki page: https://github.com/das-developers/das2C/wiki/das3_spice\n" +"\n" +" * SPICE Frames Overview:\n" +" https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/Tutorials/pdf/individual_docs/17_frames_and_coordinate_systems.pdf" +"\n" +" * SPICE Frames required reading:\n" +" https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/frames.html\n" "\n" ); } @@ -203,36 +210,35 @@ void prnHelp() /* ************************************************************************* */ /* Argument parsing. More details then usual */ -#define SYSTEM_INVALID -1 -#define SYSTEM_CAR 0 /* If theses defines change, the logic in */ -#define SYSTEM_CYL 1 /* addEphemOp() needs to be updated to match */ -#define SYSTEM_SPH 2 - #define CAR_X 0 /* If theses defines change, the logic in */ #define CAR_Y 1 /* addEphemOp() needs to be updated to match */ #define CAR_Z 2 /* Coordinate names below follow ISO 31-11:1992 std */ #define CYL_RHO 0 /* Normal from axis for cylinders */ -#define CYL_PHI 1 /* Angle for cylinders */ +#define CYL_PHI 1 /* longitude angle */ #define CYL_Z 2 /* Along axis for cyliders */ #define SPH_R 0 /* Radial from center point for spheres */ -#define SPH_THETA 1 /* Co-latitude for spheres */ -#define SPH_PHI 2 /* Same usage as cylindrical, means longitude here */ - -#define FRAME_NAME_SZ 64 - -struct frame_add { - char sFrame[FRAME_NAME_SZ]; /* If not null, output a frame */ - int iSystem; /* Which coordinate block to output */ - bool aCoords[3][3]; /* 1st index is Vector type, 2nd is coordinate */ -}; - -/* Assumes any components not present are 0 */ -struct frame_rot { - const char* sOutFrame; /* May not be NULL */ - const char* sInFrame; /* May be NULL!, means try to match any */ -}; +#define SPH_THETA 1 /* latitude angle, direction changes */ +#define SPH_PHI 2 /* longitude angle, direction changes */ + +#define XFORM_NAME_SZ 64 +#define XFORM_ADD 0x01 +#define XFORM_ROT 0x02 +#define XFORM_VALID 0x10 +#define XFORM_IN_HDR 0x20 + +typedef struct frame_xform { + uint32_t uFlags; + ubyte uOutSystem; /* See definitions in DasFrame.h */ + char sOutFrame[DASFRM_NAME_SZ]; + /* The coordinates to output. The order is: + x,y,z - For cartesian coords + ρ,φ,z - For cylindrical cords + r,θ,φ - For spherical coords */ + bool aOutCoords[3]; /* Default to all three for now */ + char sInFrame[DASFRM_NAME_SZ]; /* Only used for rotations */ +} frame_xform_s; typedef struct context{ bool bListFrames; @@ -242,142 +248,90 @@ typedef struct context{ char aLevel[32]; /* Log level */ char aMetaKern[256]; /* The metakernel file name */ char aAnonFrame[32]; - struct frame_add aLocs[MAX_LOCS + 1]; /* Always terminating null struct */ - struct frame_rot aRots[MAX_ROTS + 1]; /* ditto */ DasIO* pOut; /* Output IO object */ DasStream* pSdOut; /* Output Stream holder */ -} context; - + frame_xform_s aXForm[MAX_XFORMS + 1]; /* Always terminating null struct */ +} context_s; /* Parsing helpers for complicated arguments */ /* This is meandering, try to find a shorter method -cwp */ -int _addEphemOp(struct frame_add* pAdd, const char* sOp){ +#define SYSTEM_INVALID -1 +#define SYSTEM_CAR 0 /* If theses defines change, the logic in */ +#define SYSTEM_CYL 1 /* addEphemOp() needs to be updated to match */ +#define SYSTEM_SPH 2 + +/* Parse strings of the form [input:]output[,system] */ + +int _addOp(uint32_t uOp, frame_xform_s* pXForm, const char* sOp){ char sBuf[64] = {'\0'}; strncpy(sBuf, sOp, 63); - + char* pRead = sBuf; char* pSep = NULL; - char* sFrame; - char* sCoords; - if( (pSep = strchr(sBuf, ':')) != NULL){ - *pSep = '\0'; - sFrame = sBuf; - sCoords = pSep + 1; - } - else{ - sFrame = sBuf; - sCoords = "x,y,z"; - } - - if(sOp[0] == '\0') /* Check frame is not null */ - goto EPHEM_PARSE_ERR; - strncpy(pAdd->sFrame, sFrame, FRAME_NAME_SZ - 1); + pXForm->uFlags = (uOp & XFORM_ROT) ? XFORM_ROT : XFORM_ADD; - /* Read till hitting a separator, then store the result */ - char* pRead = sCoords; - bool bBreakAfter = false; - while(true){ - - /* Read axis on encountering a terminator */ - if((*pRead == ',')||(*pRead == '\0')){ - if(*pRead == '\0') - bBreakAfter = true; - *pRead = '\0'; - - /* The match and fill. After this Z and PHI may be in the wrong place, - * check after the fact.*/ - if(strcasecmp(sCoords, "x") == 0) - pAdd->aCoords[SYSTEM_CAR][CAR_X] = true; - else if(strcasecmp(sCoords, "y") == 0) - pAdd->aCoords[SYSTEM_CAR][CAR_Y] = true; - else if(strcasecmp(sCoords, "z") == 0) - pAdd->aCoords[SYSTEM_CAR][CAR_Z] = true; /* <- or cyl if other cyl stuff */ - else if(strcasecmp(sCoords, "rho") == 0) - pAdd->aCoords[SYSTEM_CYL][CYL_RHO] = true; - else if(strcasecmp(sCoords, "phi") == 0) - pAdd->aCoords[SYSTEM_CYL][CYL_PHI] = true; /* <- or sphere if other sphere stuff */ - else if(strcasecmp(sCoords, "r") == 0) - pAdd->aCoords[SYSTEM_SPH][SPH_R] = true; - else if(strcasecmp(sCoords, "theta") == 0) - pAdd->aCoords[SYSTEM_SPH][SPH_THETA] = true; - else - goto EPHEM_PARSE_ERR; - - if(bBreakAfter) break; - - ++pRead; - sCoords = pRead; - } - ++pRead; - } - - /* Resolve ambiguity in Z */ - if(pAdd->aCoords[SYSTEM_CAR][CAR_Z] && ( - pAdd->aCoords[SYSTEM_CYL][CYL_RHO] || pAdd->aCoords[SYSTEM_CYL][CYL_PHI] - )){ - pAdd->aCoords[SYSTEM_CAR][CAR_Z] = false; - pAdd->aCoords[SYSTEM_CYL][CYL_Z] = true; - } - - /* Resolve ambiguity in Phi */ - if(pAdd->aCoords[SYSTEM_CYL][CYL_PHI] && ( - pAdd->aCoords[SYSTEM_SPH][SPH_R] || pAdd->aCoords[SYSTEM_SPH][SPH_THETA] - )){ - pAdd->aCoords[SYSTEM_CYL][CYL_PHI] = false; - pAdd->aCoords[SYSTEM_SPH][SPH_PHI] = true; - } - - /* At this point, only one should ring up */ - pAdd->iSystem = SYSTEM_INVALID; - for(int i = 0; i < 3; ++i){ - for(int j = 0; j < 3; ++j){ - if(pAdd->aCoords[i][j]){ - if(pAdd->iSystem == SYSTEM_INVALID) - pAdd->iSystem = i; - else - goto EPHEM_PARSE_ERR; - } + /* Input frame if defined */ + if((pSep = strchr(pRead, ':')) != NULL){ + if( (uOp & XFORM_ROT) == 0){ + return das_error(PERR, + "Operation requires no input coordinates, '%s', so ':' is not needed.", + sOp + ); } + *pSep = '\0'; + if(pRead[0] == '\0') goto ADDOP_ERR; /* nothing before the colon */ + strncpy(pXForm->sInFrame, pRead, DASFRM_NAME_SZ - 1); + pRead = pSep + 1; } - return DAS_OKAY; - -EPHEM_PARSE_ERR: - return das_error(PERR, "Error determining requested ephemeris from '%s'", sOp); -} - -/* Parsing for rotation arguments */ - -int _addRotateOp(struct frame_rot* pRot, char* sOp){ - - if(sOp[0] == '\0') - return das_error(PERR, "Missing frame name in rotation request"); - - pRot->sOutFrame = sOp; + if(pRead[0] == '\0') goto ADDOP_ERR; /* No output frame */ - char* pSep = NULL; - if( (pSep = strchr(sOp, ':')) != NULL){ + /* Output coord system if defined */ + if((pSep = strchr(pRead, ',')) != NULL){ *pSep = '\0'; - if(*(pSep + 1) == '\0') - return das_error(PERR, "Input frame missing after '%s:'", sOp); - pRot->sInFrame = pSep + 1; + ++pSep; + if(*pSep == '\0') goto ADDOP_ERR; /* Nothing after the comma */ + if(*pRead == '\0') goto ADDOP_ERR; /* Nothing before the comma */ + + /* These are allowed outputs for both coords and rotations */ + /* NOTE: The coord systems: Polar, Surface, etc. are just other coordinte + systems with some components locked to 0 */ + if(strstr(pSep, "cart")) pXForm->uOutSystem = DASFRM_CARTESIAN; + else if (strstr(pSep, "cyl")) pXForm->uOutSystem = DASFRM_CYLINDRICAL; + else if (strstr(pSep, "sph")) pXForm->uOutSystem = DASFRM_SPHERICAL; + else if (strstr(pSep, "cent")) pXForm->uOutSystem = DASFRM_CENTRIC; + else if (strstr(pSep, "detic")) pXForm->uOutSystem = DASFRM_DETIC; + else if (strstr(pSep, "graph")) pXForm->uOutSystem = DASFRM_GRAPHIC; + else goto ADDOP_ERR; + + /* Check for valid out coord system, not sure what rotating vectors into + * an ellipsoidal system even means, would right angles not apply anymore + * between vector components ? */ + if((pXForm->uFlags & XFORM_ROT)&&((pXForm->uOutSystem == DASFRM_CENTRIC) || + (pXForm->uOutSystem == DASFRM_DETIC) || (pXForm->uOutSystem = DASFRM_GRAPHIC) + )) + return das_error(PERR, "Vector rotations to '%s' coordinates not supported", pSep); } else{ - pRot->sInFrame = NULL; + pXForm->uOutSystem = DASFRM_CARTESIAN; } + strncpy(pXForm->sOutFrame, pRead, DASFRM_NAME_SZ - 1); return DAS_OKAY; + +ADDOP_ERR: + return das_error(PERR, "Error parsing operation directive '%s'. Use -h for help.", sOp); } + /* Main Arg parser */ -int parseArgs(int argc, char** argv, context* pOpts) +int parseArgs(int argc, char** argv, context_s* pCtx) { - memset(pOpts, 0, sizeof(context)); /* <- Defaults struct values to 0 */ + memset(pCtx, 0, sizeof(context_s)); /* <- Defaults all context values to 0 */ - strncpy(pOpts->aLevel, "info", DAS_FIELD_SZ(context,aLevel) - 1); - int nLocs = 0; - int nRots = 0; + strncpy(pCtx->aLevel, "info", DAS_FIELD_SZ(context_s,aLevel) - 1); + int nXForms = 0; char aOpBuf[64] = {'\0'}; int i = 0; int nRet = 0; @@ -390,33 +344,28 @@ int parseArgs(int argc, char** argv, context* pOpts) exit(0); } if(dascmd_isArg(argv[i], "-c", "--coords", NULL)){ - pOpts->bCoordsOnly = true; + pCtx->bCoordsOnly = true; continue; } if(dascmd_isArg(argv[i], "-d", "--data", NULL)){ - pOpts->bDataOnly = true; + pCtx->bDataOnly = true; continue; } if(dascmd_isArg(argv[i], "-k", "--keep", NULL)){ - pOpts->bKeepOrig = true; + pCtx->bKeepOrig = true; continue; } if(dascmd_isArg(argv[i], "-L", "--list", NULL)){ - pOpts->bListFrames = true; + pCtx->bListFrames = true; continue; } if(dascmd_getArgVal( - pOpts->aLevel, DAS_FIELD_SZ(context,aLevel), argv, argc, &i, + pCtx->aLevel, DAS_FIELD_SZ(context_s,aLevel), argv, argc, &i, "-l", "--log=" )) continue; if(dascmd_getArgVal( - pOpts->aAnonFrame, DAS_FIELD_SZ(context,aAnonFrame), argv, argc, &i, - "-a", "--anonymous=" - )) - continue; - if(dascmd_getArgVal( - pOpts->aAnonFrame, DAS_FIELD_SZ(context,aAnonFrame), argv, argc, &i, + pCtx->aAnonFrame, DAS_FIELD_SZ(context_s,aAnonFrame), argv, argc, &i, "-a", "--anonymous=" )) continue; @@ -424,23 +373,23 @@ int parseArgs(int argc, char** argv, context* pOpts) memset(aOpBuf, 0, 64); if(dascmd_getArgVal(aOpBuf, 64, argv, argc, &i, "-E", "--ephem=")){ - if(nLocs >= MAX_LOCS) + if(nXForms >= MAX_XFORMS) return das_error(PERR, - "Recompile if you want to add more then %d ephemeris sets", MAX_LOCS + "Recompile if you want to preform more than %d spice operations", MAX_XFORMS ); - if((nRet = _addEphemOp(pOpts->aLocs + nLocs, aOpBuf)) != DAS_OKAY) + if((nRet = _addOp(XFORM_ADD, pCtx->aXForm + nXForms, aOpBuf)) != DAS_OKAY) return nRet; - ++nLocs; + ++nXForms; continue; } if(dascmd_getArgVal(aOpBuf, 64, argv, argc, &i, "-R", "--rotate=")){ - if(nRots >= MAX_ROTS) + if(nXForms >= MAX_XFORMS) return das_error(PERR, - "Recompile if you want more then %d rotation operations", MAX_ROTS + "Recompile if you want to preform more than %d spice operations", MAX_XFORMS ); - if((nRet = _addRotateOp(pOpts->aRots + nRots, aOpBuf) != DAS_OKAY)) + if((nRet = _addOp(XFORM_ROT, pCtx->aXForm + nXForms, aOpBuf) != DAS_OKAY)) return nRet; - ++nRots; + ++nXForms; continue; } @@ -449,18 +398,18 @@ int parseArgs(int argc, char** argv, context* pOpts) else{ /* save the meta-kernel name */ - if(pOpts->aMetaKern[0] == '\0') - strncpy(pOpts->aMetaKern, argv[i], 255); + if(pCtx->aMetaKern[0] == '\0') + strncpy(pCtx->aMetaKern, argv[i], 255); else return das_error(PERR, "Unknown extra fixed parameter: '%s'", argv[i]); } } /* end arg loop */ /* Check args */ - if(pOpts->aMetaKern[0] == '\0') + if(pCtx->aMetaKern[0] == '\0') return das_error(PERR, "Meta-kernel file was not provided"); - if((nLocs == 0)&&(nRots == 0)&&(!pOpts->bListFrames)) + if((nXForms == 0)&&(!pCtx->bListFrames)) return das_error(PERR, "No operations were requested, use -h for help."); return DAS_OKAY; @@ -501,20 +450,61 @@ void prnFrames(){ /* ************************************************************************* */ DasErrCode onStream(DasStream* pSdIn, void* pUser){ - context* pCtx = (context*)pUser; + context_s* pCtx = (context_s*)pUser; /* Make the output stream by just copying over all the top properties plus any frames retained in the output */ - pCtx->pSdOut = DasStream_copy(pSdIn); - - /* Now loop over frames determining what stays */ + DasStream* pSdOut = DasStream_copy(pSdIn); + int nRet = DAS_OKAY; + + /* Now loop over frames copying over anything that stays */ + int nFrames = DasStream_getNumFrames(pSdIn); + bool bKeep = false; + frame_xform_s* pXForm = NULL; + + for(int i = 0; i < nFrames; ++i){ + const DasFrame* pFrame = DasStream_getFrame(pSdIn, i); + + bKeep = pCtx->bKeepOrig; + if(!bKeep){ + /* Is this one of the frames we add? Could already be defined I guess */ + for(pXForm = &(pCtx->aXForm[0]); pXForm->sOutFrame[0] != '\0'; ++pXForm){ + if(strcmp(DasFrame_getName(pFrame), pXForm->sOutFrame) == 0){ + bKeep = true; + pXForm->uFlags |= XFORM_IN_HDR; + } + } + } + if(bKeep) + DasStream_addFrame(pSdOut, copy_DasFrame(pFrame)); + } /* Create our new frames */ + for(pXForm = &(pCtx->aXForm[0]); pXForm->sOutFrame[0] != '\0'; ++pXForm){ + + if(pXForm->uFlags & XFORM_IN_HDR) continue; + int iFrame = DasStream_newFrameId(pSdOut); + if(iFrame < 0) + return das_error(PERR, + "Out of coord-frame definition space, recompile with MAX_FRAMES > %d", MAX_FRAMES + ); + DasFrame* pNewFrame = DasStream_createFrame( + pSdOut, iFrame, pXForm->sOutFrame, NULL, pXForm->uOutSystem + ); + if(pNewFrame == NULL) + return das_error(PERR, "Couldn't create frame definition for %s", pXForm->sOutFrame); + + /* Just use default directions for this app */ + if( (nRet = DasFrame_setDefDirs(pNewFrame)) != DAS_OKAY) return nRet; + + pXForm->uFlags |= XFORM_IN_HDR; + } /* Send it */ - return DasIO_writeStreamDesc(pCtx->pOut, pCtx->pSdOut); + pCtx->pSdOut = pSdOut; + return DasIO_writeStreamDesc(pCtx->pOut, pCtx->pSdOut); } @@ -559,8 +549,7 @@ int main(int argc, char** argv) /* Exit on errors, log info messages and above */ das_init(argv[0], DASERR_DIS_EXIT, 0, DASLOG_INFO, NULL); - - context ctx; + context_s ctx; /* The "what am I doing" common block */ if(parseArgs(argc, argv, &ctx) != DAS_OKAY) return 13; @@ -587,7 +576,7 @@ int main(int argc, char** argv) DasIO_model(pIn, 3); /* <-- Read s but model s */ /* Output writer */ - ctx.pOut = new_DasIO_cfile(PROG, stdout, "w"); + ctx.pOut = new_DasIO_cfile(PROG, stdout, "w3"); /* 3 = das3 */ /* Stream processor */ StreamHandler handler;