Draw rectangles, circles or arbitrary polygons in a m x n matrix

前端 未结 5 1402
我寻月下人不归
我寻月下人不归 2021-02-14 00:19

I want to simulate the flow around objects in two dimensions. Therefore I wrote a program in C which uses the Navier-Stokes equations to describe the motion of fluids. Now I cam

5条回答
  •  悲哀的现实
    2021-02-14 00:40

    If you want to be able to draw arbitrary shapes, you probably want to use SVG. I can recommend nanosvg.h and nanosvgrast.h with an example (also uses stb_image for other image formats and xcb for displaying the image in X11) It's also available as at github gist here

    #include 
    #include 
    #define STBI_NO_HDR
    #define STBI_NO_LINEAR
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"
    #define NANOSVG_IMPLEMENTATION
    #include "nanosvg.h"
    #define NANOSVGRAST_IMPLEMENTATION
    #include "nanosvgrast.h"
    
    int main(int argc, char **argv){
       xcb_connection_t *c = xcb_connect(0, 0);
       xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
       int w, h, n,
          depth = s->root_depth,
          win_class = XCB_WINDOW_CLASS_INPUT_OUTPUT,
          format = XCB_IMAGE_FORMAT_Z_PIXMAP;
       xcb_colormap_t colormap = s->default_colormap;
       xcb_drawable_t win = xcb_generate_id(c);
       xcb_gcontext_t gc = xcb_generate_id(c);
       xcb_pixmap_t pixmap = xcb_generate_id(c);
       xcb_generic_event_t *ev;
       xcb_image_t *image;
       NSVGimage *shapes = NULL;
       NSVGrasterizer *rast = NULL;
       char *data = NULL;
       unsigned *dp;
       size_t i, len;
       uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
          value_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS,
          values[] = { s->black_pixel, value_mask };
    
       if (argc<2) return -1;
       if ((data = stbi_load(argv[1], &w, &h, &n, 4)))
          ;
       else if ((shapes = nsvgParseFromFile(argv[1], "px", 96.0f))) {
          w = (int)shapes->width;
          h = (int)shapes->height;
          rast = nsvgCreateRasterizer();
          data = malloc(w*h*4);
          nsvgRasterize(rast, shapes, 0,0,1, data, w, h, w*4);
       }else return -1;
       for(i=0,len=w*h,dp=(unsigned *)data;i>16)&0xFF)|((dp[i]<<16)&0xFF0000);
       xcb_create_window(c,depth,win,s->root,0,0,w,h,1,win_class,s->root_visual,mask,values);
       xcb_create_pixmap(c,depth,pixmap,win,w,h);
       xcb_create_gc(c,gc,pixmap,0,NULL);
       image = xcb_image_create_native(c,w,h,format,depth,data,w*h*4,data);
       xcb_image_put(c, pixmap, gc, image, 0, 0, 0);
       xcb_image_destroy(image);
       xcb_map_window(c, win);
       xcb_flush(c);
       while ((ev = xcb_wait_for_event(c))) {
          switch (ev->response_type & ~0x80){
          case XCB_EXPOSE: {
             xcb_expose_event_t *x = (xcb_expose_event_t *)ev;
             xcb_copy_area(c,pixmap,win,gc,x->x,x->y,x->x,x->y,x->width,x->height);
             xcb_flush(c);
          }break;
          case XCB_BUTTON_PRESS: goto end;
          default: break;
          }
       }
    end:
       xcb_free_pixmap(c, pixmap);
       xcb_disconnect(c);
       return 0;
    }
    

    You may need to modify the rasterizer code to fit to your specific format instead of X11, but you should be able to use any svg image editor to generate your shapes (or even just hand code them using a viewbox and path) For instance, draw your images in black and white and just use any one of the generated R,G or B bits in the RGBA result instead of converting it to the X11 pixel format.

    Using svg format will also allow you to convert it to any arbitrary image format (including those mentioned in the edit) while stretching it to any size making it easy to see how stretching the x or y dimensions affects flow. The svg format even allows a large number of transformations on individual​ shapes for fine tuning.

提交回复
热议问题