From 7ac4b1aeb99d8fdbab4c350412e6c66981f1dd86 Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Tue, 22 Oct 2024 14:31:26 +0200 Subject: [PATCH 1/8] Implement feature of hit animation. Client can now draw hits with ced_hit_ID_animate() passing time as an additional arguments. If such hits are present, the layer is considered animated. fix merge conflict --- include/ced_cli.h | 3 +++ src/ced.h | 2 ++ src/client/ced_cli.cc | 17 +++++++++++++++++ src/server/ced_srv.cc | 17 +++++++++++++++++ src/server/glced.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/include/ced_cli.h b/include/ced_cli.h index a92164b..69502c1 100644 --- a/include/ced_cli.h +++ b/include/ced_cli.h @@ -129,6 +129,7 @@ typedef enum { typedef struct { CED_Point p; + float time; // allows event animation unsigned type; // point, star, etc unsigned layer; //layer unsigned color; // in ARGB form (so, 0xff0000 is RED) @@ -144,6 +145,8 @@ void ced_hit_ID_old(float x,float y,float z,unsigned type, unsigned size,unsigne void ced_hit_ID(float x,float y,float z,unsigned type,unsigned layer, unsigned size,unsigned color, unsigned lcioID); +void ced_hit_ID_animate(float x,float y,float z,float t, unsigned type,unsigned layer, unsigned size,unsigned color, unsigned lcioID); + /* * Line element */ diff --git a/src/ced.h b/src/ced.h index ccf355c..b2abaf0 100644 --- a/src/ced.h +++ b/src/ced.h @@ -121,6 +121,8 @@ struct CEDsettings{ int autoshot_scale; // If true, generate screencapture in every new event }; +extern int animation_start_time; // in ms +extern int animate_layer; /* //important: // - sum of all layers must be smaler than max_layer! diff --git a/src/client/ced_cli.cc b/src/client/ced_cli.cc index 8c063e1..0e6449a 100644 --- a/src/client/ced_cli.cc +++ b/src/client/ced_cli.cc @@ -34,6 +34,7 @@ void ced_hit_ID(float x,float y,float z,unsigned type,unsigned layer, unsigned s h->p.x=x; h->p.y=y; h->p.z=z; + h->time=0; h->type=type; // if(layer > 255){ //downward compability // h->layer=layer >> CED_LAYER_SHIFT; @@ -45,6 +46,22 @@ void ced_hit_ID(float x,float y,float z,unsigned type,unsigned layer, unsigned s h->lcioID=lcioID; } +void ced_hit_ID_animate(float x,float y,float z,float t, unsigned type,unsigned layer, unsigned size,unsigned color, unsigned lcioID){ + CED_Hit *h=(CED_Hit *)ced_add(HIT_ID); + if(!h) return; + h->p.x=x; + h->p.y=y; + h->p.z=z; + h->time=t; + h->type=type; + h->layer=layer; + h->size=size; + h->color=color; + h->lcioID=lcioID; +} + + + /* * Line element */ diff --git a/src/server/ced_srv.cc b/src/server/ced_srv.cc index abef8a3..59c3ae7 100644 --- a/src/server/ced_srv.cc +++ b/src/server/ced_srv.cc @@ -1290,11 +1290,28 @@ static void ced_draw_hit(CED_Hit *h){ } //printf("hit on layer: %i\n", h->layer); + + // time is passed to the hit data and is expected to be animated + bool to_animate = h->time > 0.f; + if ( to_animate && animate_layer == -1 ) animation_start_time = glutGet(GLUT_ELAPSED_TIME); + if(!IS_VISIBLE(h->layer)){ + if (to_animate && animate_layer == h->layer) animate_layer = -1; return; } // printf("Draw hit at : %f %f %f type = %d and ced_visible_layers = %d \n",h->p.x,h->p.y,h->p.z,h->type,ced_visible_layers); + if (to_animate){ + if ( animate_layer == -1 ) animate_layer = h->layer; + else if ( animate_layer != h->layer ){ + setting.layer[animate_layer] = false; + animate_layer = h->layer; + animation_start_time = glutGet(GLUT_ELAPSED_TIME); + } + float elapsed_time = 0.001*( glutGet(GLUT_ELAPSED_TIME) - animation_start_time); // in seconds + if ( elapsed_time < h->time ) return ; + } + ced_color(h->color); diff --git a/src/server/glced.cc b/src/server/glced.cc index 2323452..40162b0 100644 --- a/src/server/glced.cc +++ b/src/server/glced.cc @@ -96,6 +96,8 @@ int ced_picking(int x,int y,GLfloat *wx,GLfloat *wy,GLfloat *wz); //from ced_srv //*************** global variables ***************************************// +int animation_start_time; +int animate_layer = -1; //for new angles add the new angle to this list and to define in ced_menu.h static int available_cutangles[]={0,30,45,90,100,135,120,150,170,180,190,200,220,240,260,270,280,290,310,330,340}; int last_selected_layer; @@ -560,6 +562,41 @@ std::string formatShortcut(int iLayer, const char key, const char *description, return truncateTo(sstr.str(), max_len); } +void printEventTime(void){ + if( animate_layer < 0 ) return; + + //calculate event time: + float elapsed_time = 0.001*( glutGet(GLUT_ELAPSED_TIME) - animation_start_time); // in seconds, but physicswise should be in ns + char text[42]; + sprintf(text, "Event time: %.3f ns", elapsed_time); + double dark = 1.-(setting.bgcolor[0]+setting.bgcolor[1]+setting.bgcolor[2]) / 3.0; + + //print on screen: + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + GLfloat w=glutGet(GLUT_SCREEN_WIDTH); + GLfloat h=glutGet(GLUT_SCREEN_HEIGHT); + glOrtho(-WORLD_SIZE*w/h,WORLD_SIZE*w/h,-WORLD_SIZE,WORLD_SIZE, -15*WORLD_SIZE,15*WORLD_SIZE); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glColor3f(dark,dark,dark); + drawHelpString(text, -600, -950); + + + glEnd(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + void printShortcuts(void){ @@ -776,6 +813,7 @@ static void display(void){ ced_menu->draw(); popupmenu->draw(); printFPS(); + printEventTime(); if(setting.light==true){ glEnable(GL_LIGHTING); @@ -4524,6 +4562,9 @@ int main(int argc,char *argv[]){ + //future calls give time relative to this. + glutGet(GLUT_ELAPSED_TIME); // time since glutInit() + animation_start_time = glutGet(GLUT_ELAPSED_TIME); // time since first glutGet(GLUT_ELAPSED_TIME) glutMainLoop(); return 0; From 1c7ab7bebad117653f244ca0c5a9ab2a8b3021d0 Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Thu, 15 Jan 2026 13:52:35 +0100 Subject: [PATCH 2/8] initialize animation_start_time --- src/server/glced.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/glced.cc b/src/server/glced.cc index 40162b0..d5733b8 100644 --- a/src/server/glced.cc +++ b/src/server/glced.cc @@ -96,7 +96,7 @@ int ced_picking(int x,int y,GLfloat *wx,GLfloat *wy,GLfloat *wz); //from ced_srv //*************** global variables ***************************************// -int animation_start_time; +int animation_start_time = 0; int animate_layer = -1; //for new angles add the new angle to this list and to define in ced_menu.h static int available_cutangles[]={0,30,45,90,100,135,120,150,170,180,190,200,220,240,260,270,280,290,310,330,340}; From 8c1649155a9cd3886c08a61558cc4e91966d722e Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Fri, 16 Jan 2026 17:53:12 +0100 Subject: [PATCH 3/8] Fix type comparison warnings --- src/server/ced_srv.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/ced_srv.cc b/src/server/ced_srv.cc index 59c3ae7..7a3ba4c 100644 --- a/src/server/ced_srv.cc +++ b/src/server/ced_srv.cc @@ -1296,14 +1296,14 @@ static void ced_draw_hit(CED_Hit *h){ if ( to_animate && animate_layer == -1 ) animation_start_time = glutGet(GLUT_ELAPSED_TIME); if(!IS_VISIBLE(h->layer)){ - if (to_animate && animate_layer == h->layer) animate_layer = -1; + if (to_animate && animate_layer == int(h->layer) ) animate_layer = -1; return; } // printf("Draw hit at : %f %f %f type = %d and ced_visible_layers = %d \n",h->p.x,h->p.y,h->p.z,h->type,ced_visible_layers); if (to_animate){ if ( animate_layer == -1 ) animate_layer = h->layer; - else if ( animate_layer != h->layer ){ + else if ( animate_layer != int(h->layer) ){ setting.layer[animate_layer] = false; animate_layer = h->layer; animation_start_time = glutGet(GLUT_ELAPSED_TIME); From 73e821ce00883c3c316a036908d7ae6aca0aff7d Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Fri, 16 Jan 2026 17:53:45 +0100 Subject: [PATCH 4/8] update license year --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7773ee..938b178 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ to define colors is better use gimp - it gives that crasy numbers easily ## License and Copyright -Copyright (C) 2005-2017, CED Authors +Copyright (C) 2005-2026, CED Authors CED is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. From 2232170650060b1cca3b7212cd69cb73c953bd20 Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Fri, 16 Jan 2026 18:23:36 +0100 Subject: [PATCH 5/8] Add example usage of CED client with data from EDM4hep. Add animated hits in the readme as well --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/README.md b/README.md index 938b178..618b4ec 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,9 @@ In any Processor: // float x1,float y1,float z1, // unsigned type,unsigned width,unsigned color); + // delay in seconds hit rendering by the time "t" to produce animation effect. "Show FPS" must be switched on. + // void ced_hit_ID_animate(float x,float y,float z, float t, unsigned type, unsigned size, unsigned color, unsigned id); + to define colors is better use gimp - it gives that crasy numbers easily @@ -178,6 +181,70 @@ to define colors is better use gimp - it gives that crasy numbers easily // at the end of event ced_draw_event(); // Make clean up screen before drawing +## Using the CED client library with EDM4hep files in python: + +One must use key4hep environment, e.g.: +```bash +source /cvmfs/sw.hsf.org/key4hep/setup.sh +# or +# source /cvmfs/sw-nightlies.hsf.org/key4hep/setup.sh +``` + +```python +import os +import cppyy +from podio import root_io + +# Load dependencies +for path in os.environ["CMAKE_PREFIX_PATH"].split(":"): + inlcude_dir = os.path.join(path, "include") + if os.path.isdir(inlcude_dir): + cppyy.add_include_path( inlcude_dir ) + + if "/marlinutil/" in path: + cppyy.add_include_path( os.path.join(path, "include", "marlinutil") ) + +cppyy.include("ced_cli.h") +cppyy.include("DDMarlinCED.h") +from cppyy.gbl import ced_client_init, ced_register_elements +from cppyy.gbl import ced_new_event, ced_send_event, ced_selected_id_noblock, +from cppyy.gbl import ced_hit_ID, ced_hit_ID_animate, CED_HIT_POINT, +std = cppyy.gbl.std +DDMarlinCED = cppyy.gbl.DDMarlinCED + +det_compact_file = os.path.join( os.environ["LCGEO"], COMPACT_PATH ) +detector = cppyy.gbl.dd4hep.Detector.getInstance() +detector.fromCompact(det_compact_file) + +ced_client_init("localhost", 7286) +ced_register_elements() + +reader = root_io.Reader(EDM4HEP_FILE) +for event in reader.get("events"): + ced_new_event() + + DDMarlinCED.drawDD4hepDetector( detector, False, std.vector[std.string]() ) + + layer = 1 # layer under which hits are displayed + animated_layer = 2 + size = 5 # size of the hits + color = int(color.lstrip("#000000"), 16) # color of the hits + # Draw all reconstructed hits in layer #1 and animate them in layer #2 + for col in TRACKER_HIT_COLS + CALO_HIT_COLS: + for hit in event.get(col): + pos = hit.getPosition() + t = hit.getTime() + ced_hit_ID(pos.x, pos.y, pos.z, CED_HIT_POINT, layer, size, color, 0) + ced_hit_ID_animate(pos.x, pos.y, pos.z, t, CED_HIT_POINT, layer, size, color, 0) + + ced_send_event() + + # ced_selected_id_noblock() can be used to return id of the picked object. + # A more involved example with kbhit instead of pyhton's input() would be needed to use it. + # picked_id = ced_selected_id_noblock() + + input("Press enter to draw next event") +``` ## License and Copyright Copyright (C) 2005-2026, CED Authors From d7c1ec442113a9fef01efd53d528bf525f4f0e1a Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Fri, 16 Jan 2026 18:24:59 +0100 Subject: [PATCH 6/8] Fix layer arg typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 618b4ec..bb05a8a 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ for event in reader.get("events"): pos = hit.getPosition() t = hit.getTime() ced_hit_ID(pos.x, pos.y, pos.z, CED_HIT_POINT, layer, size, color, 0) - ced_hit_ID_animate(pos.x, pos.y, pos.z, t, CED_HIT_POINT, layer, size, color, 0) + ced_hit_ID_animate(pos.x, pos.y, pos.z, t, CED_HIT_POINT, animated_layer, size, color, 0) ced_send_event() From 85a8fdebd1ac733d822a1aeb47e53191a4cba9cb Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Fri, 16 Jan 2026 18:26:13 +0100 Subject: [PATCH 7/8] Rephrase for clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb05a8a..6088222 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ In any Processor: // float x1,float y1,float z1, // unsigned type,unsigned width,unsigned color); - // delay in seconds hit rendering by the time "t" to produce animation effect. "Show FPS" must be switched on. + // hit rendering is delayed by the time "t" (in seconds). Produce animation effect. "Show FPS" must be switched on. // void ced_hit_ID_animate(float x,float y,float z, float t, unsigned type, unsigned size, unsigned color, unsigned id); From 0fe99f86e2b55b9df1147145162e8cd4e97db056 Mon Sep 17 00:00:00 2001 From: Bohdan Dudar Date: Mon, 19 Jan 2026 13:11:05 +0100 Subject: [PATCH 8/8] Improve example in readme --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6088222..eb4e5bf 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,12 @@ import os import cppyy from podio import root_io +# User Config +COMPACT_PATH="" +EDM4HEP_FILE = "" +TRACKER_HIT_COLS = ["", "", "<...>"] +CALO_HIT_COLS = ["", "", "<...>"] + # Load dependencies for path in os.environ["CMAKE_PREFIX_PATH"].split(":"): inlcude_dir = os.path.join(path, "include") @@ -207,12 +213,12 @@ for path in os.environ["CMAKE_PREFIX_PATH"].split(":"): cppyy.include("ced_cli.h") cppyy.include("DDMarlinCED.h") from cppyy.gbl import ced_client_init, ced_register_elements -from cppyy.gbl import ced_new_event, ced_send_event, ced_selected_id_noblock, -from cppyy.gbl import ced_hit_ID, ced_hit_ID_animate, CED_HIT_POINT, +from cppyy.gbl import ced_new_event, ced_send_event, ced_selected_id_noblock +from cppyy.gbl import ced_hit_ID, ced_hit_ID_animate, CED_HIT_POINT std = cppyy.gbl.std DDMarlinCED = cppyy.gbl.DDMarlinCED -det_compact_file = os.path.join( os.environ["LCGEO"], COMPACT_PATH ) +det_compact_file = os.path.join( os.environ["k4geo_DIR"], COMPACT_PATH ) detector = cppyy.gbl.dd4hep.Detector.getInstance() detector.fromCompact(det_compact_file) @@ -228,7 +234,7 @@ for event in reader.get("events"): layer = 1 # layer under which hits are displayed animated_layer = 2 size = 5 # size of the hits - color = int(color.lstrip("#000000"), 16) # color of the hits + color = 0x000000 # hex color of the hits # Draw all reconstructed hits in layer #1 and animate them in layer #2 for col in TRACKER_HIT_COLS + CALO_HIT_COLS: for hit in event.get(col):