diff --git a/Makefile.am b/Makefile.am index 6bac005..1a30418 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,8 +18,11 @@ cmSRC += src/libcm/cmData.c src/libcm/cmLib.c src/libcm/cmText.c src/libcm/cmTex cmHDR += src/libcm/cmMath.h src/libcm/cmGnuPlot.h src/libcm/cmKeyboard.h src/libcm/cmStrStream.h cmSRC += src/libcm/cmMath.c src/libcm/cmGnuPlot.c src/libcm/cmKeyboard.c src/libcm/cmStrStream.c -cmHDR += src/libcm/cmLinkedHeap.h src/libcm/cmMallocDebug.h src/libcm/cmLex.h src/libcm/cmJson.h src/libcm/cmXml.h src/libcm/cmPrefs.h src/libcm/cmStack.h src/libcm/cmArray.h -cmSRC += src/libcm/cmLinkedHeap.c src/libcm/cmMallocDebug.c src/libcm/cmLex.c src/libcm/cmJson.c src/libcm/cmXml.c src/libcm/cmPrefs.c src/libcm/cmStack.c src/libcm/cmArray.c +cmHDR += src/libcm/cmLinkedHeap.h src/libcm/cmMallocDebug.h src/libcm/cmLex.h src/libcm/cmJson.h src/libcm/cmXml.h +cmSRC += src/libcm/cmLinkedHeap.c src/libcm/cmMallocDebug.c src/libcm/cmLex.c src/libcm/cmJson.c src/libcm/cmXml.c + +cmHDR += src/libcm/cmPrefs.h src/libcm/cmStack.h src/libcm/cmArray.h src/libcm/cmSvgWriter.h +cmSRC += src/libcm/cmPrefs.c src/libcm/cmStack.c src/libcm/cmArray.c src/libcm/cmSvgWriter.c cmHDR += src/libcm/cmUdpPort.h src/libcm/cmUdpNet.h src/libcm/cmVirtNet.h cmSRC += src/libcm/cmUdpPort.c src/libcm/cmUdpNet.c src/libcm/cmVirtNet.c diff --git a/cmSvgWriter.c b/cmSvgWriter.c new file mode 100644 index 0000000..d854932 --- /dev/null +++ b/cmSvgWriter.c @@ -0,0 +1,234 @@ +#include "cmPrefix.h" +#include "cmGlobal.h" +#include "cmFloatTypes.h" +#include "cmRpt.h" +#include "cmErr.h" +#include "cmCtx.h" +#include "cmMem.h" +#include "cmMallocDebug.h" +#include "cmLinkedHeap.h" +#include "cmTime.h" +#include "cmText.h" +#include "cmFile.h" +#include "cmSvgWriter.h" + +enum +{ + kRectSvgId, + kLineSvgId, + kTextSvgId +}; + +typedef struct cmSvgEle_str +{ + unsigned id; + double x0; + double y0; + double x1; + double y1; + cmChar_t* text; + cmChar_t* cssClass; + struct cmSvgEle_str* link; +} cmSvgEle_t; + +typedef struct cmSvg_str +{ + cmErr_t err; + cmLHeapH_t lhH; + cmSvgEle_t* elist; + cmSvgEle_t* eol; +} cmSvg_t; + +cmSvgH_t cmSvgNullHandle = cmSTATIC_NULL_HANDLE; + +cmSvg_t* _cmSvgHandleToPtr( cmSvgH_t h ) +{ + cmSvg_t* p = (cmSvg_t*)h.h; + assert(p != NULL ); + return p; +} + +cmSvgRC_t _cmSvgInsertEle( cmSvg_t* p, unsigned id, double x0, double y0, double x1, double y1, const cmChar_t* text, const cmChar_t* class ) +{ + cmSvgEle_t* e = cmLhAllocZ(p->lhH,cmSvgEle_t,1); + + e->id = id; + e->x0 = x0; + e->y0 = y0; + e->x1 = x1; + e->y1 = y1; + e->text = text==NULL ? "" : cmLhAllocStr(p->lhH,text); + e->cssClass = cmLhAllocStr(p->lhH,class); + + if( p->eol == NULL ) + p->elist = p->eol = e; + else + p->eol->link = e; + + p->eol = e; + + return kOkSvgRC; +} + +cmSvgRC_t _cmSvgWriterFree( cmSvg_t* p ) +{ + cmLHeapDestroy(&p->lhH); + cmMemFree(p); + return kOkSvgRC; +} + +cmSvgRC_t cmSvgWriterAlloc( cmCtx_t* ctx, cmSvgH_t* hp ) +{ + cmSvgRC_t rc; + if((rc = cmSvgWriterFree(hp)) != kOkSvgRC ) + return rc; + + cmSvg_t* p = cmMemAllocZ(cmSvg_t,1); + + cmErrSetup(&p->err,&ctx->rpt,"SVG Writer"); + + // create a local linked heap + if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false ) + { + rc = cmErrMsg(&p->err,kLHeapFailSvgRC,"Lheap create failed."); + goto errLabel; + } + + hp->h = p; + + errLabel: + if( rc != kOkSvgRC ) + _cmSvgWriterFree(p); + + return rc; +} + +cmSvgRC_t cmSvgWriterFree( cmSvgH_t* hp ) +{ + cmSvgRC_t rc = kOkSvgRC; + + if( hp==NULL || cmSvgWriterIsValid(*hp)==false ) + return kOkSvgRC; + + cmSvg_t* p = _cmSvgHandleToPtr(*hp); + + if((rc = _cmSvgWriterFree(p)) != kOkSvgRC ) + return rc; + + hp->h = NULL; + + return rc; +} + +bool cmSvgWriterIsValid( cmSvgH_t h ) +{ return h.h != NULL; } + +cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double x, double y, double ww, double hh, const cmChar_t* cssClassLabel ) +{ + cmSvg_t* p = _cmSvgHandleToPtr(h); + return _cmSvgInsertEle( p, kRectSvgId, x, y, x+ww, y+hh, NULL, cssClassLabel==NULL?"rectclass":cssClassLabel ); +} + +cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel ) +{ + cmSvg_t* p = _cmSvgHandleToPtr(h); + return _cmSvgInsertEle( p, kLineSvgId, x0, y0, x1, y1, NULL, cssClassLabel==NULL?"lineclass":cssClassLabel ); +} + +cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double x, double y, const cmChar_t* text, const cmChar_t* cssClassLabel ) +{ + cmSvg_t* p = _cmSvgHandleToPtr(h); + return _cmSvgInsertEle( p, kTextSvgId, x, y, 0, 0, text==NULL?"":text, cssClassLabel==NULL?"textclass":cssClassLabel ); +} + +void _cmSvgSize( cmSvg_t* p, double* widthRef, double* heightRef ) +{ + *widthRef = 0; + *heightRef = 0; + + if( p->elist == NULL ) + return; + + cmSvgEle_t* e = p->elist; + double min_x = cmMin(e->x0,e->x1); + double max_x = cmMax(e->x0,e->x1); + double min_y = cmMin(e->y0,e->y1); + double max_y = cmMax(e->y0,e->y1); + + for(e=e->link; e!=NULL; e=e->link) + { + min_x = cmMin(cmMin(min_x,e->x0),e->x1); + max_x = cmMax(cmMax(max_x,e->x0),e->x1); + min_y = cmMin(cmMin(min_y,e->y0),e->y1); + max_y = cmMax(cmMax(max_y,e->y0),e->y1); + } + + *widthRef = max_x - min_x; + *heightRef = max_y - min_y; +} + + +cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn ) +{ + cmSvgRC_t rc = kOkSvgRC; + cmSvg_t* p = _cmSvgHandleToPtr(h); + double svgWidth = 0; + double svgHeight = 0; + cmSvgEle_t* e = p->elist; + cmFileH_t fH = cmFileNullHandle; + + _cmSvgSize(p, &svgWidth, &svgHeight ); + + if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC ) + return cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn)); + + if( cmFilePrintf(fH,"\n\n\n\n",svgWidth,svgHeight,cssFn) != kOkFileRC ) + { + rc = cmErrMsg(&p->err,kFileFailSvgRC,"File prefix write failed."); + goto errLabel; + } + + for(; e!=NULL; e=e->link) + { + switch( e->id ) + { + case kRectSvgId: + if( cmFilePrintf(fH,"\n",e->x0,e->y0,e->x1-e->x0,e->y1-e->y0,e->cssClass) != kOkFileRC ) + rc = kFileFailSvgRC; + break; + + case kLineSvgId: + if( cmFilePrintf(fH,"\n",e->x0,e->y0,e->x1,e->y1,e->cssClass) != kOkFileRC ) + rc = kFileFailSvgRC; + break; + + case kTextSvgId: + if( cmFilePrintf(fH,"%s\n",e->x0,e->y0,e->cssClass,e->text) != kOkFileRC ) + rc = kFileFailSvgRC; + break; + + default: + { assert(0); } + + } + + if( rc != kOkSvgRC ) + { + rc = cmErrMsg(&p->err,kFileFailSvgRC,"Element write failed."); + break; + } + } + + if( cmFilePrint(fH,"\n\n\n") != kOkFileRC ) + { + rc = cmErrMsg(&p->err,kFileFailSvgRC,"File suffix write failed."); + goto errLabel; + } + + + errLabel: + cmFileClose(&fH); + + return rc; +} + diff --git a/cmSvgWriter.h b/cmSvgWriter.h new file mode 100644 index 0000000..aca0a43 --- /dev/null +++ b/cmSvgWriter.h @@ -0,0 +1,35 @@ +#ifndef cmSvgWriter_h +#define cmSvgWriter_h + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + kOkSvgRC = cmOkRC, + kFileFailSvgRC, + kLHeapFailSvgRC +}; + + typedef cmRC_t cmSvgRC_t; + typedef cmHandle_t cmSvgH_t; + + extern cmSvgH_t cmSvgNullHandle; + + cmSvgRC_t cmSvgWriterAlloc( cmCtx_t* ctx, cmSvgH_t* hp ); + cmSvgRC_t cmSvgWriterFree( cmSvgH_t* hp ); + bool cmSvgWriterIsValid( cmSvgH_t h ); + + cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double x, double y, double ww, double hh, const cmChar_t* cssClassLabel ); + cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel ); + cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double x, double y, const cmChar_t* text, const cmChar_t* cssClassLabel ); + + cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn ); + +#ifdef __cplusplus +} +#endif + + +#endif