void _set_common_mi_attributes (plDrawState *drawstate, void * ptr) { int line_style, num_dashes, offset; unsigned int *dashbuf; bool dash_array_allocated = false; miGCAttribute attributes[5]; int values [5]; unsigned int local_dashbuf[PL_MAX_DASH_ARRAY_LEN]; miGC *pGC; pGC = (miGC *)ptr; /* recover passed libxmi GC */ /* set all miGC attributes that are not dash related */ /* set five integer-valued miGC attributes */ attributes[0] = MI_GC_FILL_RULE; values[0] = (drawstate->fill_rule_type == PL_FILL_NONZERO_WINDING ? MI_WINDING_RULE : MI_EVEN_ODD_RULE); attributes[1] = MI_GC_JOIN_STYLE; values[1] = mi_join_style[drawstate->join_type]; attributes[2] = MI_GC_CAP_STYLE; values[2] = mi_cap_style[drawstate->cap_type]; attributes[3] = MI_GC_ARC_MODE; values[3] = MI_ARC_CHORD; /* libplot convention */ attributes[4] = MI_GC_LINE_WIDTH; values[4] = drawstate->quantized_device_line_width; miSetGCAttribs (pGC, 5, attributes, values); /* set a double-valued miGC attribute */ miSetGCMiterLimit (pGC, drawstate->miter_limit); /* now determine and set dashing-related attributes */ if (drawstate->dash_array_in_effect) /* have user-specified dash array */ { int i; num_dashes = drawstate->dash_array_len; if (num_dashes > 0) /* non-solid line type */ { bool odd_length; double min_sing_val, max_sing_val; int dash_cycle_length; /* compute minimum singular value of user->device coordinate map, which we use as a multiplicative factor to convert line widths (cf. g_linewidth.c), dash lengths, etc. */ _matrix_sing_vals (drawstate->transform.m, &min_sing_val, &max_sing_val); line_style = MI_LINE_ON_OFF_DASH; odd_length = (num_dashes & 1 ? true : false); { int array_len; array_len = (odd_length ? 2 : 1) * num_dashes; if (array_len <= PL_MAX_DASH_ARRAY_LEN) dashbuf = local_dashbuf; /* use dash buffer on stack */ else { dashbuf = (unsigned int *)_pl_xmalloc (array_len * sizeof(unsigned int)); dash_array_allocated = true; } } dash_cycle_length = 0; for (i = 0; i < num_dashes; i++) { double unrounded_dashlen; int dashlen; unrounded_dashlen = min_sing_val * drawstate->dash_array[i]; dashlen = IROUND(unrounded_dashlen); dashlen = IMAX(dashlen, 1); dashbuf[i] = (unsigned int)dashlen; dash_cycle_length += dashlen; if (odd_length) { dashbuf[num_dashes + i] = (unsigned int)dashlen; dash_cycle_length += dashlen; } } if (odd_length) num_dashes *= 2; offset = IROUND(min_sing_val * drawstate->dash_offset); if (dash_cycle_length > 0) /* choose an offset in range 0..dash_cycle_length-1 */ { while (offset < 0) offset += dash_cycle_length; offset %= dash_cycle_length; } } else /* zero-length dash array, i.e. solid line type */ { line_style = MI_LINE_SOLID; dashbuf = NULL; offset = 0; } } else /* have one of the canonical line types */ { if (drawstate->line_type == PL_L_SOLID) { line_style = MI_LINE_SOLID; num_dashes = 0; dashbuf = NULL; offset = 0; } else { const int *dash_array; int scale, i; line_style = MI_LINE_ON_OFF_DASH; num_dashes = _pl_g_line_styles[drawstate->line_type].dash_array_len; dash_array = _pl_g_line_styles[drawstate->line_type].dash_array; dashbuf = local_dashbuf; /* it is large enough */ offset = 0; /* scale by line width in terms of pixels, if nonzero */ scale = drawstate->quantized_device_line_width; if (scale <= 0) scale = 1; for (i = 0; i < num_dashes; i++) { int dashlen; dashlen = scale * dash_array[i]; dashlen = IMAX(dashlen, 1); dashbuf[i] = (unsigned int)dashlen; } } } /* set dash-related attributes in libxmi's graphics context */ miSetGCAttrib (pGC, MI_GC_LINE_STYLE, line_style); if (line_style != (int)MI_LINE_SOLID) miSetGCDashes (pGC, num_dashes, dashbuf, offset); if (dash_array_allocated) free (dashbuf); }
int main () { miPoint points[4]; /* 3 line segments in the polyline */ miArc arc; /* 1 arc to be drawn */ miPixel pixels[4]; /* pixel values for drawing and dashing */ unsigned int dashes[2]; /* length of `on' and `off' dashes */ miGC *pGC; /* graphics context */ miPaintedSet *paintedSet; /* opaque object to be painted */ miCanvas *canvas; /* drawing canvas (including pixmap) */ miPoint offset; /* for miPaintedSet -> miCanvas transfer */ int i, j; /* define polyline: vertices are (25,5) (5,5), (5,25), (35,22) */ points[0].x = 25; points[0].y = 5; points[1].x = 5; points[1].y = 5; points[2].x = 5; points[2].y = 25; points[3].x = 35; points[3].y = 22; /* define elliptic arc */ arc.x = 20; arc.y = 15; /* upper left corner of bounding box */ arc.width = 30; /* x range of box: 20..50 */ arc.height = 16; /* y range of box: 15..31 */ arc.angle1 = 0 * 64; /* starting angle (1/64'ths of a degree) */ arc.angle2 = 270 * 64; /* angle range (1/64'ths of a degree) */ /* create and modify graphics context */ pixels[0] = 1; /* pixel value for `off' dashes, if drawn */ pixels[1] = 2; /* default pixel for drawing */ pixels[2] = 3; /* another pixel, for multicolored dashes */ pixels[3] = 4; /* another pixel, for multicolored dashes */ dashes[0] = 4; /* length of `on' dashes */ dashes[1] = 2; /* length of `off' dashes */ pGC = miNewGC (4, pixels); miSetGCAttrib (pGC, MI_GC_LINE_STYLE, MI_LINE_ON_OFF_DASH); miSetGCDashes (pGC, 2, dashes, 0); miSetGCAttrib (pGC, MI_GC_LINE_WIDTH, 0); /* Bresenham algorithm */ /* create empty painted set */ paintedSet = miNewPaintedSet (); /* paint dashed polyline and dashed arc onto painted set */ miDrawLines (paintedSet, pGC, MI_COORD_MODE_ORIGIN, 4, points); miDrawArcs (paintedSet, pGC, 1, &arc); /* create 60x35 canvas (initPixel=0); merge painted set onto it */ canvas = miNewCanvas (60, 35, 0); offset.x = 0; offset.y = 0; miCopyPaintedSetToCanvas (paintedSet, canvas, offset); /* write canvas's pixmap (a 60x35 array of miPixels) to stdout */ for (j = 0; j < canvas->drawable->height; j++) { for (i = 0; i < canvas->drawable->width; i++) /* note: column index precedes row index */ printf ("%d", canvas->drawable->pixmap[j][i]); printf ("\n"); } /* clean up */ miDeleteCanvas (canvas); miDeleteGC (pGC); miClearPaintedSet (paintedSet); /* not necessary */ miDeletePaintedSet (paintedSet); return 0; }