From 27f4919ef335700baff85127cf3fbaf9f2942d29 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Mon, 29 Sep 2025 21:25:54 +0200 Subject: [PATCH] improved tick handling, added data transformation lib --- src/lib/aqdiagram/0BUILD | 2 + src/lib/aqdiagram/data/0BUILD | 97 +++++++++++++++++++ src/lib/aqdiagram/data/accumulate.c | 42 ++++++++ src/lib/aqdiagram/data/accumulate.h | 22 +++++ src/lib/aqdiagram/data/average.c | 36 +++++++ src/lib/aqdiagram/data/average.h | 22 +++++ src/lib/aqdiagram/data/date.c | 138 +++++++++++++++++++++++++++ src/lib/aqdiagram/data/date.h | 23 +++++ src/lib/aqdiagram/data/diff.c | 86 +++++++++++++++++ src/lib/aqdiagram/data/diff.h | 23 +++++ src/lib/aqdiagram/data/floatingavg.c | 75 +++++++++++++++ src/lib/aqdiagram/data/floatingavg.h | 23 +++++ src/lib/aqdiagram/graph/axis.t2d | 76 +++++++-------- src/lib/aqdiagram/graph/tick.t2d | 40 ++++++++ src/lib/aqdiagram/graph/timegraph.c | 13 ++- src/lib/aqdiagram/graph/w_viewport.c | 52 +++++++++- src/lib/aqdiagram/graph/w_xaxis.c | 25 ++++- src/lib/aqdiagram/graph/w_yaxis.c | 27 +++++- src/lib/aqdiagram/libtest.c | 46 ++++++++- 19 files changed, 815 insertions(+), 53 deletions(-) create mode 100644 src/lib/aqdiagram/data/0BUILD create mode 100644 src/lib/aqdiagram/data/accumulate.c create mode 100644 src/lib/aqdiagram/data/accumulate.h create mode 100644 src/lib/aqdiagram/data/average.c create mode 100644 src/lib/aqdiagram/data/average.h create mode 100644 src/lib/aqdiagram/data/date.c create mode 100644 src/lib/aqdiagram/data/date.h create mode 100644 src/lib/aqdiagram/data/diff.c create mode 100644 src/lib/aqdiagram/data/diff.h create mode 100644 src/lib/aqdiagram/data/floatingavg.c create mode 100644 src/lib/aqdiagram/data/floatingavg.h diff --git a/src/lib/aqdiagram/0BUILD b/src/lib/aqdiagram/0BUILD index b96f728..7e1d857 100644 --- a/src/lib/aqdiagram/0BUILD +++ b/src/lib/aqdiagram/0BUILD @@ -58,6 +58,7 @@ aqdg_graph aqdg_draw aqdg_place + aqdg_data @@ -73,6 +74,7 @@ placement draw graph + data diff --git a/src/lib/aqdiagram/data/0BUILD b/src/lib/aqdiagram/data/0BUILD new file mode 100644 index 0000000..232d02a --- /dev/null +++ b/src/lib/aqdiagram/data/0BUILD @@ -0,0 +1,97 @@ + + + + + + + + + + $(gwenhywfar_cflags) + $(cairo_cflags) + -I$(topsrcdir)/src/lib + -I$(topbuilddir)/src/lib + -I$(topbuilddir) + -I$(topsrcdir) + -I$(srcdir) + + + + --include=$(builddir) + --include=$(srcdir) + --include=$(builddir)/../types + --include=$(topsrcdir)/src/lib/typemaker2/c + --include=$(topbuilddir)/src/lib/typemaker2/c + + + + $(visibility_cflags) + + + + --api=AQDG_API + + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + $(local/built_headers_priv) + + + + + average.h + accumulate.h + floatingavg.h + date.h + diff.h + + + + + + + + $(local/typefiles) + average.c + accumulate.c + floatingavg.c + date.c + diff.c + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/aqdiagram/data/accumulate.c b/src/lib/aqdiagram/data/accumulate.c new file mode 100644 index 0000000..f9b83f3 --- /dev/null +++ b/src/lib/aqdiagram/data/accumulate.c @@ -0,0 +1,42 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./accumulate.h" + + + +AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_Accumulate(const AQDG_GRAPH_DATAPAIR_LIST *dpList) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + AQDG_GRAPH_DATAPAIR_LIST *newList; + const AQDG_GRAPH_DATAPAIR *dp; + double v=0.0; + + newList=AQDG_Graph_DataPair_List_new(); + dp=AQDG_Graph_DataPair_List_First(dpList); + while(dp) { + AQDG_GRAPH_DATAPAIR *newDp; + + v+=AQDG_Graph_DataPair_GetValueY(dp); + newDp=AQDG_Graph_DataPair_dup(dp); + AQDG_Graph_DataPair_SetValueY(newDp, v); + AQDG_Graph_DataPair_List_Add(newDp, newList); + + dp=AQDG_Graph_DataPair_List_Next(dp); + } + return newList; + } + return NULL; +} + + + diff --git a/src/lib/aqdiagram/data/accumulate.h b/src/lib/aqdiagram/data/accumulate.h new file mode 100644 index 0000000..30817c8 --- /dev/null +++ b/src/lib/aqdiagram/data/accumulate.h @@ -0,0 +1,22 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQDG_DATA_ACCUMULATE_H +#define AQDG_DATA_ACCUMULATE_H + +#include + + + +AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_Accumulate(const AQDG_GRAPH_DATAPAIR_LIST *dpList); + + + + +#endif + diff --git a/src/lib/aqdiagram/data/average.c b/src/lib/aqdiagram/data/average.c new file mode 100644 index 0000000..2931ac1 --- /dev/null +++ b/src/lib/aqdiagram/data/average.c @@ -0,0 +1,36 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./average.h" + + + +double AQDG_Data_Average(const AQDG_GRAPH_DATAPAIR_LIST *dpList) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + const AQDG_GRAPH_DATAPAIR *dp; + double v=0.0; + + dp=AQDG_Graph_DataPair_List_First(dpList); + v=0.0; + while(dp) { + v+=AQDG_Graph_DataPair_GetValueY(dp); + dp=AQDG_Graph_DataPair_List_Next(dp); + } + v/=(double) AQDG_Graph_DataPair_List_GetCount(dpList); + return v; + } + return 0.0; +} + + + diff --git a/src/lib/aqdiagram/data/average.h b/src/lib/aqdiagram/data/average.h new file mode 100644 index 0000000..3f9e2a2 --- /dev/null +++ b/src/lib/aqdiagram/data/average.h @@ -0,0 +1,22 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQDG_DATA_AVERAGE_H +#define AQDG_DATA_AVERAGE_H + +#include + + + +AQDG_API double AQDG_Data_Average(const AQDG_GRAPH_DATAPAIR_LIST *dpList); + + + + +#endif + diff --git a/src/lib/aqdiagram/data/date.c b/src/lib/aqdiagram/data/date.c new file mode 100644 index 0000000..8684ed6 --- /dev/null +++ b/src/lib/aqdiagram/data/date.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./date.h" + +#include +#include + + + +AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DaySums(const AQDG_GRAPH_DATAPAIR_LIST *dpList) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + AQDG_GRAPH_DATAPAIR_LIST *newList; + const AQDG_GRAPH_DATAPAIR *dp; + GWEN_DATE *lastDate=NULL; + AQDG_GRAPH_DATAPAIR *newDp=NULL; + + newList=AQDG_Graph_DataPair_List_new(); + dp=AQDG_Graph_DataPair_List_First(dpList); + while(dp) { + double v; + + v=AQDG_Graph_DataPair_GetValueX(dp); + if (lastDate==NULL) { + /* first value */ + lastDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp)); + newDp=AQDG_Graph_DataPair_new(); + AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate)); + AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp)); + AQDG_Graph_DataPair_List_Add(newDp, newList); + } + else { + GWEN_DATE *newDate; + + newDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp)); + if (GWEN_Date_Compare(newDate, lastDate)!=0) { + /* new date */ + GWEN_Date_free(lastDate); + lastDate=newDate; + newDp=AQDG_Graph_DataPair_new(); + AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate)); + AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp)); + AQDG_Graph_DataPair_List_Add(newDp, newList); + } + else { + double v2; + + /* add to existing date value */ + v2=AQDG_Graph_DataPair_GetValueY(newDp); + v2+=v; + AQDG_Graph_DataPair_SetValueY(newDp, v2); + GWEN_Date_free(newDate); + } + } + dp=AQDG_Graph_DataPair_List_Next(dp); + } + GWEN_Date_free(lastDate); + return newList; + } + return NULL; +} + + + +AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MonthSums(const AQDG_GRAPH_DATAPAIR_LIST *dpList) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + AQDG_GRAPH_DATAPAIR_LIST *newList; + const AQDG_GRAPH_DATAPAIR *dp; + GWEN_DATE *lastDate=NULL; + AQDG_GRAPH_DATAPAIR *newDp=NULL; + + newList=AQDG_Graph_DataPair_List_new(); + dp=AQDG_Graph_DataPair_List_First(dpList); + while(dp) { + double v; + + v=AQDG_Graph_DataPair_GetValueY(dp); + if (lastDate==NULL) { + GWEN_DATE *dt; + + /* first value */ + dt=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp)); + lastDate=GWEN_Date_GetThisMonthStart(dt); + GWEN_Date_free(dt); + newDp=AQDG_Graph_DataPair_new(); + AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate)); + AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp)); + AQDG_Graph_DataPair_List_Add(newDp, newList); + DBG_ERROR(NULL, "Added first value: %.2f", AQDG_Graph_DataPair_GetValueY(dp)); + } + else { + GWEN_DATE *dt; + GWEN_DATE *newDate; + + dt=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp)); + newDate=GWEN_Date_GetThisMonthStart(dt); + GWEN_Date_free(dt); + if (GWEN_Date_Compare(newDate, lastDate)!=0) { + /* new date */ + GWEN_Date_free(lastDate); + lastDate=newDate; + newDp=AQDG_Graph_DataPair_new(); + AQDG_Graph_DataPair_SetValueX(newDp, GWEN_Date_toLocalTime(lastDate)); + AQDG_Graph_DataPair_SetValueY(newDp, AQDG_Graph_DataPair_GetValueY(dp)); + AQDG_Graph_DataPair_List_Add(newDp, newList); + DBG_ERROR(NULL, "Added value: %.2f", AQDG_Graph_DataPair_GetValueY(dp)); + } + else { + double v2; + + /* add to existing date value */ + v2=AQDG_Graph_DataPair_GetValueY(newDp); + AQDG_Graph_DataPair_SetValueY(newDp, v2+v); + DBG_ERROR(NULL, "Added %.2f to existing value: %.2f", v, v2); + GWEN_Date_free(newDate); + } + } + dp=AQDG_Graph_DataPair_List_Next(dp); + } + GWEN_Date_free(lastDate); + return newList; + } + return NULL; +} + + + diff --git a/src/lib/aqdiagram/data/date.h b/src/lib/aqdiagram/data/date.h new file mode 100644 index 0000000..5a66d17 --- /dev/null +++ b/src/lib/aqdiagram/data/date.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQDG_DATA_DATE_H +#define AQDG_DATA_DATE_H + +#include + + + +AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DaySums(const AQDG_GRAPH_DATAPAIR_LIST *dpList); +AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_MonthSums(const AQDG_GRAPH_DATAPAIR_LIST *dpList); + + + + +#endif + diff --git a/src/lib/aqdiagram/data/diff.c b/src/lib/aqdiagram/data/diff.c new file mode 100644 index 0000000..99f158a --- /dev/null +++ b/src/lib/aqdiagram/data/diff.c @@ -0,0 +1,86 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./average.h" + + + +double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + const AQDG_GRAPH_DATAPAIR *dp; + double minDist=0.0; + double lastValue=0.0; + int cnt=0; + + dp=AQDG_Graph_DataPair_List_First(dpList); + while(dp) { + double d; + + d=AQDG_Graph_DataPair_GetValueX(dp); + if (cnt) { + double dist; + + dist=abs(d-lastValue); + if (cnt>1) { + if (dist1) { + if (dist + + + +AQDG_API double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList); + + + + + +#endif + diff --git a/src/lib/aqdiagram/data/floatingavg.c b/src/lib/aqdiagram/data/floatingavg.c new file mode 100644 index 0000000..8cefae4 --- /dev/null +++ b/src/lib/aqdiagram/data/floatingavg.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * This file is part of the project AqDiagram. + * AqDiagram (c) by 2025 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./floatingavg.h" + + + +AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int num) +{ + if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) { + AQDG_GRAPH_DATAPAIR_LIST *newList; + const AQDG_GRAPH_DATAPAIR *dp; + double lastValues[num]; + int cnt=0; + int idx=0; + + newList=AQDG_Graph_DataPair_List_new(); + dp=AQDG_Graph_DataPair_List_First(dpList); + while(dp) { + AQDG_GRAPH_DATAPAIR *newDp; + double v; + int i; + + v=AQDG_Graph_DataPair_GetValueY(dp); + if (idx>=num) + idx=0; + lastValues[idx]=v; + idx++; + cnt++; + + if (cnt + + + +AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int num); + + + + + +#endif + diff --git a/src/lib/aqdiagram/graph/axis.t2d b/src/lib/aqdiagram/graph/axis.t2d index 5d84139..833ef6d 100644 --- a/src/lib/aqdiagram/graph/axis.t2d +++ b/src/lib/aqdiagram/graph/axis.t2d @@ -22,6 +22,7 @@
gwenhywfar/buffer.h
gwenhywfar/timestamp.h
gwenhywfar/gwendate.h
+
gwenhywfar/debug.h
math.h
@@ -46,6 +47,7 @@ if (st->tickList==NULL) \n st->tickList=AQDG_Graph_Tick_List_new(); \n AQDG_Graph_Tick_List_Add(tick, st->tickList); \n + DBG_ERROR(NULL, "Added tick: %s (%.2f) [%d]", label, v, lvl); } \n @@ -198,39 +200,36 @@ double maxValue; \n double endTime; \n GWEN_BUFFER *dbuf; \n - GWEN_TIMESTAMP *ts; \n + GWEN_DATE *dt; \n \n maxValue=st->maxValue; \n - ts=GWEN_Timestamp_fromLocalTime(maxValue); \n - GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n - GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n - endTime=GWEN_Timestamp_toTimeT(ts); \n - GWEN_Timestamp_free(ts); \n + dt=GWEN_Date_fromLocalTime(maxValue); \n + endTime=GWEN_Date_toLocalTime(dt); \n + GWEN_Date_free(dt); \n \n minValue=st->minValue; \n - ts=GWEN_Timestamp_fromLocalTime(minValue); \n - GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n + dt=GWEN_Date_fromLocalTime(minValue); \n \n dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n while(1) { \n double v; \n \n - v=GWEN_Timestamp_toTimeT(ts); \n + v=GWEN_Date_toLocalTime(dt); \n if (v>=minValue && v<endTime) { \n GWEN_Buffer_AppendArgs(dbuf, \n "%04d/%02d/%02d", \n - GWEN_Timestamp_GetYear(ts), \n - GWEN_Timestamp_GetMonth(ts), \n - GWEN_Timestamp_GetDay(ts)); \n + GWEN_Date_GetYear(dt), \n + GWEN_Date_GetMonth(dt), \n + GWEN_Date_GetDay(dt)); \n $(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n GWEN_Buffer_Reset(dbuf); \n } \n - GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n + GWEN_Date_AddDays(dt, 1); \n if (v>=endTime) \n break; \n } \n GWEN_Buffer_free(dbuf); \n - GWEN_Timestamp_free(ts); \n + GWEN_Date_free(dt); \n } \n @@ -249,42 +248,40 @@ { \n double minValue; \n double maxValue; \n - double endTime; \n GWEN_BUFFER *dbuf; \n - GWEN_TIMESTAMP *ts; \n + GWEN_DATE *dt; \n \n maxValue=st->maxValue; \n - ts=GWEN_Timestamp_fromLocalTime(maxValue); \n - GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n - GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n - endTime=GWEN_Timestamp_toTimeT(ts); \n - GWEN_Timestamp_free(ts); \n + dt=GWEN_Date_fromLocalTime(maxValue); \n + GWEN_Date_free(dt); \n \n minValue=st->minValue; \n - ts=GWEN_Timestamp_fromLocalTime(minValue); \n - GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n - GWEN_Timestamp_AddSeconds(ts, -GWEN_Timestamp_GetWeekDay(ts)*24*60*60); \n + dt=GWEN_Date_fromLocalTime(minValue); \n \n dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n while(1) { \n double v; \n + GWEN_DATE *dtCurrent; \n \n - v=GWEN_Timestamp_toTimeT(ts); \n - if (v>=minValue && v<endTime) { \n + dtCurrent=GWEN_Date_GetThisWeekStartFromMonday(dt); \n + v=GWEN_Date_toLocalTime(dtCurrent); \n + if (v>=minValue && v<maxValue) { \n GWEN_Buffer_AppendArgs(dbuf, \n "%04d/%02d/%02d", \n - GWEN_Timestamp_GetYear(ts), \n - GWEN_Timestamp_GetMonth(ts), \n - GWEN_Timestamp_GetDay(ts)); \n + GWEN_Date_GetYear(dtCurrent), \n + GWEN_Date_GetMonth(dtCurrent), \n + GWEN_Date_GetDay(dtCurrent)); \n $(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n GWEN_Buffer_Reset(dbuf); \n } \n - GWEN_Timestamp_AddSeconds(ts, 7*24*60*60); \n - if (v>=endTime) \n + GWEN_Date_free(dt); \n + dt=dtCurrent; \n + GWEN_Date_AddDays(dt, 7); \n + if (v>=maxValue) \n break; \n } \n GWEN_Buffer_free(dbuf); \n - GWEN_Timestamp_free(ts); \n + GWEN_Date_free(dt); \n } \n @@ -302,13 +299,11 @@ { \n double minValue; \n double maxValue; \n - double endTime; \n GWEN_BUFFER *dbuf; \n GWEN_DATE *dt; \n \n maxValue=st->maxValue; \n dt=GWEN_Date_fromLocalTime(maxValue); \n - endTime=GWEN_Date_toLocalTime(dt); \n GWEN_Date_free(dt); \n \n minValue=st->minValue; \n @@ -320,18 +315,19 @@ GWEN_DATE *dtCurrent; \n \n dtCurrent=GWEN_Date_GetThisMonthStart(dt); \n - v=GWEN_Date_toLocalTime(dt); \n - if (v>=minValue && v<endTime) { \n + v=GWEN_Date_toLocalTime(dtCurrent); \n + if (v>=minValue && v<maxValue) { \n GWEN_Buffer_AppendArgs(dbuf, \n "%04d/%02d", \n - GWEN_Date_GetYear(dt), \n - GWEN_Date_GetMonth(dt)); \n + GWEN_Date_GetYear(dtCurrent), \n + GWEN_Date_GetMonth(dtCurrent)); \n $(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n - GWEN_Date_free(dtCurrent); \n GWEN_Buffer_Reset(dbuf); \n } \n + GWEN_Date_free(dt); \n + dt=dtCurrent; \n GWEN_Date_AddDays(dt, 32); \n - if (v>=endTime) \n + if (v>=maxValue) \n break; \n } \n GWEN_Buffer_free(dbuf); \n diff --git a/src/lib/aqdiagram/graph/tick.t2d b/src/lib/aqdiagram/graph/tick.t2d index 7c1e9f4..8199c25 100644 --- a/src/lib/aqdiagram/graph/tick.t2d +++ b/src/lib/aqdiagram/graph/tick.t2d @@ -18,8 +18,48 @@
aqdiagram/aqdg_api.h
+
gwenhywfar/debug.h
+ + + + + $(api) double $(struct_prefix)_List_DistanceBetweenTicks(const $(struct_type)_LIST *tickList, int lvl); + + + + + + double $(struct_prefix)_List_DistanceBetweenTicks(const $(struct_type)_LIST *tickList, int lvl) \n + { \n + int haveFirstValue=0; \n + double v0; \n + const $(struct_type) *tick; \n + \n + tick=$(struct_prefix)_List_First(tickList); \n + while(tick) { \n + if ($(struct_prefix)_GetLevel(tick)==lvl) { \n + if (!haveFirstValue) { \n + v0=$(struct_prefix)_GetValue(tick); \n + haveFirstValue=1; \n + } \n + else { \n + DBG_ERROR(NULL, "v1=%.2f, v0=%.2f", $(struct_prefix)_GetValue(tick), v0); \n + return $(struct_prefix)_GetValue(tick)-v0; \n + } \n + } \n + \n + tick=$(struct_prefix)_List_Next(tick); \n + } \n + return 0; \n + } \n + + + + + + diff --git a/src/lib/aqdiagram/graph/timegraph.c b/src/lib/aqdiagram/graph/timegraph.c index 5830525..eddf0f6 100644 --- a/src/lib/aqdiagram/graph/timegraph.c +++ b/src/lib/aqdiagram/graph/timegraph.c @@ -91,19 +91,23 @@ void AQDG_TimeGraph_SetupTicks(AQDG_GRAPH *g) { AQDG_GRAPH_AXIS *axis; + DBG_ERROR(NULL, "Calc min/max values"); AQDG_Graph_CalcMinMaxValues(g); /* create ticks for X axis */ + DBG_ERROR(NULL, "Create ticks for X axis"); axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_BOTTOM); if (axis) { _setupTicksForTimeAxis(axis); } /* create ticks for Y axis */ + DBG_ERROR(NULL, "Create ticks for Y axis"); axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_LEFT); if (axis) { _setupTicksForDataAxis(axis); } + DBG_ERROR(NULL, "Ticks done"); } @@ -134,11 +138,16 @@ void _setupTicksForTimeAxis(AQDG_GRAPH_AXIS *axis) else { DBG_ERROR(NULL, "Gen month ticks"); AQDG_Graph_Axis_GenMonthTicks(axis, 0); - if (diffInDays<100) + if (diffInDays<100) { + DBG_ERROR(NULL, "Gen day ticks"); AQDG_Graph_Axis_GenDayTicks(axis, 1); - else if (diffInDays<400) + } + else if (diffInDays<400) { + DBG_ERROR(NULL, "Gen week ticks"); AQDG_Graph_Axis_GenWeekTicks(axis, 1); + } } + DBG_ERROR(NULL, "Ticks done"); } diff --git a/src/lib/aqdiagram/graph/w_viewport.c b/src/lib/aqdiagram/graph/w_viewport.c index 4b3396d..8db3410 100644 --- a/src/lib/aqdiagram/graph/w_viewport.c +++ b/src/lib/aqdiagram/graph/w_viewport.c @@ -37,6 +37,10 @@ static void _drawCurvePoints(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_G int pen); static void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc); static void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc); +static int _screenDistBetweenLevelTicksX(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue); +static int _screenDistBetweenLevelTicksY(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue); @@ -123,6 +127,7 @@ void _drawCurves(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) const AQDG_GRAPH_SUBGRAPH *subGraph; int penIdx=AQDG_GRAPHWIDGET_PEN_IDX_CURVE0; + DBG_ERROR(NULL, "Draw curves"); xo=GWEN_INHERIT_GETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o); graph=AQDG_GraphWidget_GetGraph(xo->graphObject); @@ -165,6 +170,7 @@ void _drawCurve(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *c double minValueX, double maxValueX, double minValueY, double maxValueY, int pen) { + DBG_ERROR(NULL, "Draw curve"); switch(AQDG_Graph_Curve_GetGraphType(curve)) { case AQDG_GRAPH_TYPE_LINE: _drawCurveLines(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen); @@ -286,6 +292,7 @@ void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) int pen2; int y1; int y2; + int showLevel1; y1=AQDG_Object_GetAbsoluteY(o)+AQDG_Object_GetBorderTop(o); y2=AQDG_Object_GetAbsoluteY(o)+AQDG_Object_GetHeight(o)-AQDG_Object_GetBorderBottom(o); @@ -295,6 +302,7 @@ void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) maxValue=AQDG_Graph_Axis_GetMaxValue(axis); pen1=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID1); pen2=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID2); + showLevel1=(_screenDistBetweenLevelTicksX(tickList, 1, contentSize, minValue, maxValue)>15)?1:0; tick=AQDG_Graph_Tick_List_First(tickList); while(tick) { @@ -306,8 +314,10 @@ void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) xpos+=AQDG_Object_GetBorderLeft(o); if (AQDG_Graph_Tick_GetLevel(tick)==0) AQDG_Draw_Context_DrawLine(dc, pen1, absX+xpos, y1, absX+xpos, y2); - else if (AQDG_Graph_Tick_GetLevel(tick)==1) - AQDG_Draw_Context_DrawLine(dc, pen2, absX+xpos, y1, absX+xpos, y2); + else { + if (showLevel1) + AQDG_Draw_Context_DrawLine(dc, pen2, absX+xpos, y1, absX+xpos, y2); + } tick=AQDG_Graph_Tick_List_Next(tick); } } @@ -341,6 +351,7 @@ void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) int pen2; int x1; int x2; + int showLevel1; x1=AQDG_Object_GetAbsoluteX(o)+AQDG_Object_GetBorderLeft(o); x2=AQDG_Object_GetAbsoluteX(o)+AQDG_Object_GetWidth(o)-AQDG_Object_GetBorderLeft(o)-AQDG_Object_GetBorderRight(o); @@ -350,6 +361,7 @@ void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) maxValue=AQDG_Graph_Axis_GetMaxValue(axis); pen1=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID1); pen2=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID2); + showLevel1=(_screenDistBetweenLevelTicksY(tickList, 1, contentSize, minValue, maxValue)>15)?1:0; tick=AQDG_Graph_Tick_List_First(tickList); while(tick) { @@ -361,8 +373,10 @@ void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) ypos+=AQDG_Object_GetBorderTop(o); if (AQDG_Graph_Tick_GetLevel(tick)==0) AQDG_Draw_Context_DrawLine(dc, pen1, x1, absY+ypos, x2, absY+ypos); - else - AQDG_Draw_Context_DrawLine(dc, pen2, x1, absY+ypos, x2, absY+ypos); + else { + if (showLevel1) + AQDG_Draw_Context_DrawLine(dc, pen2, x1, absY+ypos, x2, absY+ypos); + } tick=AQDG_Graph_Tick_List_Next(tick); } } @@ -371,3 +385,33 @@ void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc) +int _screenDistBetweenLevelTicksX(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue) +{ + double v; + int pts; + + v=AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl); + DBG_ERROR(NULL, "Value diff: %.2f", v); + pts=(v*(contentSize/(maxValue-minValue))); + DBG_ERROR(NULL, "Point diff: %d", pts); + return pts; +} + + + +int _screenDistBetweenLevelTicksY(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue) +{ + double v; + int pts; + + v=AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl); + DBG_ERROR(NULL, "Value diff: %.2f", v); + pts=(v*(contentSize/(maxValue-minValue))); + DBG_ERROR(NULL, "Point diff: %d", pts); + return pts; +} + + + diff --git a/src/lib/aqdiagram/graph/w_xaxis.c b/src/lib/aqdiagram/graph/w_xaxis.c index bfe2b10..9abe676 100644 --- a/src/lib/aqdiagram/graph/w_xaxis.c +++ b/src/lib/aqdiagram/graph/w_xaxis.c @@ -34,6 +34,8 @@ static int _calcHorizontalPos(double value, int contentSize, double minValue, do static void _setChildrenRelXFromValue(AQDG_OBJECT *o); static void _setChildrenRelY(AQDG_OBJECT *o); static void _setChildrenSizes(AQDG_OBJECT *o); +static int _screenDistBetweenLevelTicks(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue); @@ -121,6 +123,7 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absY) double maxValue; int absX; int pen; + int showLevel1; contentSize=AQDG_Object_GetWidth(o)-AQDG_Object_GetBorderLeft(o)-AQDG_Object_GetBorderRight(o); scaleSize=AQDG_AxisWidget_GetScaleSize(o); @@ -128,6 +131,7 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absY) minValue=AQDG_AxisWidget_GetMinValue(o); maxValue=AQDG_AxisWidget_GetMaxValue(o); pen=AQDG_DrawableWidget_GetForegroundPenId(o); + showLevel1=(_screenDistBetweenLevelTicks(tickList, 1, contentSize, minValue, maxValue)>15)?1:0; tick=AQDG_Graph_Tick_List_First(tickList); while(tick) { @@ -139,8 +143,10 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absY) xpos+=AQDG_Object_GetBorderLeft(o); if (AQDG_Graph_Tick_GetLevel(tick)==0) AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/2), absX+xpos, absY+(scaleSize/2)); - else if (AQDG_Graph_Tick_GetLevel(tick)==1) - AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/4), absX+xpos, absY+(scaleSize/4)); + else if (AQDG_Graph_Tick_GetLevel(tick)==1) { + if (showLevel1) + AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/4), absX+xpos, absY+(scaleSize/4)); + } tick=AQDG_Graph_Tick_List_Next(tick); } } @@ -149,6 +155,21 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absY) +int _screenDistBetweenLevelTicks(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue) +{ + double v; + int pts; + + v=AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl); + DBG_ERROR(NULL, "Value diff: %.2f", v); + pts=v*(contentSize/(maxValue-minValue)); + DBG_ERROR(NULL, "Point diff: %d", pts); + return pts; +} + + + int _getDefaultWidth(AQDG_OBJECT *o) { return 1; diff --git a/src/lib/aqdiagram/graph/w_yaxis.c b/src/lib/aqdiagram/graph/w_yaxis.c index 42519f0..2bad21a 100644 --- a/src/lib/aqdiagram/graph/w_yaxis.c +++ b/src/lib/aqdiagram/graph/w_yaxis.c @@ -29,6 +29,8 @@ static int _getDefaultHeight(AQDG_OBJECT *o); static int _layout(AQDG_OBJECT *object); static int _draw(AQDG_OBJECT *object); static void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int x); +static int _screenDistBetweenLevelTicks(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue); static void _setChildrenRelX(AQDG_OBJECT *o); static void _setChildrenRelYFromValue(AQDG_OBJECT *o); static void _setChildrenSizes(AQDG_OBJECT *o); @@ -148,13 +150,15 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absX) double maxValue; int absY; int pen; - + int showLevel1; + contentSize=AQDG_Object_GetHeight(o)-AQDG_Object_GetBorderTop(o)-AQDG_Object_GetBorderBottom(o); scaleSize=AQDG_AxisWidget_GetScaleSize(o); absY=AQDG_Object_GetAbsoluteY(o); minValue=AQDG_AxisWidget_GetMinValue(o); maxValue=AQDG_AxisWidget_GetMaxValue(o); pen=AQDG_DrawableWidget_GetForegroundPenId(o); + showLevel1=(_screenDistBetweenLevelTicks(tickList, 1, contentSize, minValue, maxValue)>15)?1:0; tick=AQDG_Graph_Tick_List_First(tickList); while(tick) { @@ -166,8 +170,10 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absX) ypos+=AQDG_Object_GetBorderTop(o); if (AQDG_Graph_Tick_GetLevel(tick)==0) AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/2), absY+ypos, absX+(scaleSize/2), absY+ypos); - else - AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/4), absY+ypos, absX+(scaleSize/4), absY+ypos); + else { + if (showLevel1) + AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/4), absY+ypos, absX+(scaleSize/4), absY+ypos); + } tick=AQDG_Graph_Tick_List_Next(tick); } } @@ -176,6 +182,21 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absX) +int _screenDistBetweenLevelTicks(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, + int contentSize, double minValue, double maxValue) +{ + double v; + int pts; + + v=AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl); + DBG_ERROR(NULL, "Value diff: %.2f", v); + pts=(v*(contentSize/(maxValue-minValue))); + DBG_ERROR(NULL, "Point diff: %d", pts); + return pts; +} + + + void _setChildrenRelX(AQDG_OBJECT *o) { int contentSize; diff --git a/src/lib/aqdiagram/libtest.c b/src/lib/aqdiagram/libtest.c index 36808cc..9f5fe3f 100644 --- a/src/lib/aqdiagram/libtest.c +++ b/src/lib/aqdiagram/libtest.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -208,6 +210,46 @@ int test4() +int test5() +{ + AQDG_GRAPH *g; + AQDG_GRAPH_DATAPAIR_LIST *dpList; + AQDG_GRAPH_DATAPAIR_LIST *derivedDpList; + AQDG_DRAW_CONTEXT *dc; + AQDG_OBJECT *graphObject; + + g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0); + dpList=_mkTestData1(); + AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_LINE, dpList); + + derivedDpList=AQDG_Data_Accumulate(dpList); + AQDG_TimeGraph_AddCurve(g, "Accumulated", AQDG_GRAPH_TYPE_LINE, derivedDpList); + AQDG_TimeGraph_SetupTicks(g); + + dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600); + graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc); + AQDG_Object_SetWidth(graphObject, 800); + AQDG_Object_SetHeight(graphObject, 600); + + AQDG_GraphWidget_SetupDefaultPens(graphObject); + AQDG_GraphWidget_SetupDefaultFonts(graphObject); + + AQDG_GraphWidget_SetupForGraph(graphObject, g); + + AQDG_Object_ModifyBranchFlagsDown(graphObject, AQDG_OBJECT_FLAGS_RECALC, AQDG_OBJECT_FLAGS_RECALC); + AQDG_Object_ModifyBranchFlagsDown(graphObject, AQDG_OBJECT_FLAGS_LAYOUT, AQDG_OBJECT_FLAGS_LAYOUT); + AQDG_Object_Layout(graphObject); + AQDG_Object_Tree2_CalculateAbsPositions(graphObject); + AQDG_Object_Dump(graphObject, 2); + + AQDG_DrawableWidget_Draw(graphObject); + AQDG_Draw_Context_Finish(dc); + + return 0; +} + + + AQDG_GRAPH *_mkTestGraph() { AQDG_GRAPH *g; @@ -257,7 +299,7 @@ AQDG_GRAPH_DATAPAIR_LIST *_mkTestData1() int i; dpList=AQDG_Graph_DataPair_List_new(); - ts=GWEN_Timestamp_new(2025, 1, 1, 0, 0, 0); + ts=GWEN_Timestamp_new(2025, 1, 15, 2, 0, 0); for(i=0; i<60; i++) { AQDG_GRAPH_DATAPAIR *dp; double v; @@ -366,7 +408,7 @@ int main(int argc, char **argv) // rv=test1(argc, argv); // rv=test2(argc, argv); - rv=test4(); + rv=test5(); if (rv!=0){ DBG_ERROR(NULL, "here (%d)", rv);