void eda_cairo_arc (cairo_t *cr, int flags, double width, double x, double y, double radius, double start_angle, double sweep_angle) { int s_width; double x1, y1, x2, y2; double s_x, s_y, s_radius; double offset, dummy = 0; if (!(flags & EDA_CAIRO_ENABLE_HINTS)) { do_arc (cr, x, y, radius, start_angle, sweep_angle); return; } WORLDtoSCREEN (cr, x - radius, y + radius, &x1, &y1); WORLDtoSCREEN (cr, x + radius, y - radius, &x2, &y2); s_width = screen_width (cr, width); offset = ((s_width % 2) == 0) ? 0 : 0.5; s_x = (double)(x1 + x2) / 2.; s_y = (double)(y1 + y2) / 2.; s_radius = (double)(y2 - y1) / 2.; cairo_device_to_user (cr, &s_x, &s_y); cairo_device_to_user_distance (cr, &offset, &dummy); cairo_device_to_user_distance (cr, &s_radius, &dummy); do_arc (cr, s_x + offset, s_y + offset, s_radius, start_angle, sweep_angle); }
gfxRect gfxContext::DeviceToUser(gfxRect rect) const { gfxRect ret = rect; cairo_device_to_user(mCairo, &ret.pos.x, &ret.pos.y); cairo_device_to_user_distance(mCairo, &ret.size.width, &ret.size.height); return ret; }
static void fill_pixel_rect(DiaRenderer *object, int x, int y, int width, int height, Color *color) { #if 1 /* if we do it with cairo there is something wrong with the clipping? */ DiaCairoInteractiveRenderer *renderer = DIA_CAIRO_INTERACTIVE_RENDERER (object); GdkGC *gc = renderer->gc; GdkColor gdkcolor; color_convert(color, &gdkcolor); gdk_gc_set_foreground(gc, &gdkcolor); gdk_draw_rectangle (renderer->pixmap, gc, TRUE, x, y, width, height); #else DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (object); double x1u = x + .5, y1u = y + .5, x2u = x + width + .5, y2u = y + height + .5; double lw[2]; lw[0] = 1; lw[1] = 0; cairo_device_to_user_distance (renderer->cr, &lw[0], &lw[1]); cairo_set_line_width (renderer->cr, lw[0]); cairo_device_to_user (renderer->cr, &x1u, &y1u); cairo_device_to_user (renderer->cr, &x2u, &y2u); cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0); cairo_rectangle (renderer->cr, x1u, y1u, x2u - x1u, y2u - y1u); cairo_fill (renderer->cr); #endif }
gfxSize gfxContext::DeviceToUser(const gfxSize& size) const { gfxSize ret = size; cairo_device_to_user_distance(mCairo, &ret.width, &ret.height); return ret; }
static int cr_device_to_user_distance (lua_State *L) { cairo_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_CONTEXT); double x = luaL_checknumber(L, 2), y = luaL_checknumber(L, 3); cairo_device_to_user_distance(*obj, &x, &y); lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; }
CAMLprim value ml_cairo_device_to_user_distance (value cr, value p) { double x, y; x = Double_field (p, 0); y = Double_field (p, 1); cairo_device_to_user_distance (cairo_t_val (cr), &x, &y); check_cairo_status (cr); return ml_cairo_point (x, y); }
static VALUE cr_device_to_user_distance (VALUE self, VALUE dx, VALUE dy) { double pair[2]; pair[0] = NUM2DBL (dx); pair[1] = NUM2DBL (dy); cairo_device_to_user_distance (_SELF, pair, pair + 1); cr_check_status (_SELF); return rb_cairo__float_array (pair, 2); }
/*! * \brief Ensure a minimum of one device unit * Dia as well as many other drawing applications/libraries is using a * line with 0f 0.0 tho mean hairline. Cairo doe not have this capability * so this functions should be used to get the thinnest line possible. * \protected \memberof _DiaCairoRenderer */ static void ensure_minimum_one_device_unit(DiaCairoRenderer *renderer, real *value) { double ax = 1., ay = 1.; cairo_device_to_user_distance (renderer->cr, &ax, &ay); ax = MAX(ax, ay); if (*value < ax) *value = ax; }
///maps back to user distance before stoking. void scaled_stroke(cairo_t *cr) { double xwise = 1; double ywise = 1; cairo_save(cr); cairo_device_to_user_distance (cr,&xwise,&ywise); cairo_scale(cr,xwise,ywise); cairo_stroke(cr); cairo_restore(cr); }
static PyObject * pycairo_device_to_user_distance (PycairoContext *o, PyObject *args) { double dx, dy; if (!PyArg_ParseTuple (args, "dd:Context.device_to_user_distance", &dx, &dy)) return NULL; cairo_device_to_user_distance (o->ctx, &dx, &dy); RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx); return Py_BuildValue("(dd)", dx, dy); }
static void set_linewidth(DiaRenderer *self, real linewidth) { DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (self); DIAG_NOTE(g_message("set_linewidth %f", linewidth)); /* make hairline? */ if (linewidth == 0.0) { double ax = 0.0, ay = 0.0; double bx = 1.0, by = 0.0; cairo_device_to_user_distance (renderer->cr, &ax, &ay); cairo_device_to_user_distance (renderer->cr, &bx, &by); linewidth = sqrt ((bx - ax) * (bx - ax) + (by - ay) * (by - ay)); } cairo_set_line_width (renderer->cr, linewidth); DIAG_STATE(renderer->cr) }
void eda_cairo_center_arc (cairo_t *cr, int flags, double center_width, double line_width, double x, double y, double radius, double start_angle, double sweep_angle) { int s_center_width, s_line_width; double s_x, s_y, dummy = 0; int s_diameter; double even_center_width; double even_line_width; double even_diameter; double center_offset; double s_radius; int do_radius_hint = TRUE; if (!(flags & EDA_CAIRO_ENABLE_HINTS)) { do_arc (cr, x, y, radius, start_angle, sweep_angle); return; } WORLDtoSCREEN (cr, x, y, &s_x, &s_y); s_diameter = SCREENabs (cr, 2 * radius); even_diameter = ((s_diameter % 2) == 0); s_radius = (double) s_diameter / 2.; /* Switch off radius hinting for small radii. If we don't, then we get * a very abrupt transition once the arc reaches a single pixel size. */ if (s_radius <= 1.) do_radius_hint = FALSE; /* Hint the center of the arc based on where a line * of thickness center_width (world) would drawn */ s_center_width = screen_width (cr, center_width); even_center_width = (center_width == -1 || (s_center_width % 2) == 0); center_offset = even_center_width ? 0. : 0.5; /* Hint the radius to land its extermity on the pixel grid */ s_line_width = screen_width (cr, line_width); even_line_width = (line_width == -1 || (s_line_width % 2) == 0); if (do_radius_hint) s_radius += ((even_center_width == even_line_width) == even_diameter) ? 0. : 0.5; s_x += center_offset; s_y += center_offset; cairo_device_to_user (cr, &s_x, &s_y); cairo_device_to_user_distance (cr, &s_radius, &dummy); do_arc (cr, s_x, s_y, s_radius, start_angle, sweep_angle); }
static PyObject * pycairo_device_to_user_distance (PycairoContext *o, PyObject *args) { double dx, dy; if (!PyArg_ParseTuple (args, "dd:Context.device_to_user_distance", &dx, &dy)) return NULL; cairo_device_to_user_distance (o->ctx, &dx, &dy); if (Pycairo_Check_Status (cairo_status (o->ctx))) return NULL; return Py_BuildValue("(dd)", dx, dy); }
/** Draw the rectangle _centered_ at current Cairo coordinates. @param width Width of the rectangle. @param height Height of the rectangle. @param pixelOutput Round width and height to pixels. */ static void gerbv_draw_rectangle(cairo_t *cairoTarget, gdouble width, gdouble height, gboolean pixelOutput) { if (pixelOutput) { cairo_user_to_device_distance (cairoTarget, &width, &height); width -= (int)round(width) % 2; height -= (int)round(height) % 2; cairo_device_to_user_distance (cairoTarget, &width, &height); } cairo_rectangle (cairoTarget, -width/2.0, -height/2.0, width, height); return; }
///maps to user distance before displaying text void scaled_show_text (cairo_t *cr, const char* s, float size=-1.) { double xwise = 1; double ywise = 1; cairo_save(cr); if (size > 0) cairo_set_font_size(cr, size); cairo_device_to_user_distance (cr, &xwise, &ywise); cairo_scale(cr,xwise,ywise); cairo_show_text (cr, s ); cairo_restore(cr); }
void lsm_cairo_box_device_to_user (cairo_t *cairo, LsmBox *to, const LsmBox *from) { if (to == NULL) return; if (from == NULL || cairo == NULL) { to->x = 0; to->y = 0; to->width = 0; to->height = 0; } *to = *from; cairo_device_to_user (cairo, &to->x, &to->y); cairo_device_to_user_distance (cairo, &to->width, &to->height); }
static void draw_pixel_rect(DiaRenderer *object, int x, int y, int width, int height, Color *color) { DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (object); double x1u = x + .5, y1u = y + .5, x2u = x + width + .5, y2u = y + height + .5; double lw[2]; lw[0] = 1; lw[1] = 0; cairo_device_to_user_distance (renderer->cr, &lw[0], &lw[1]); cairo_set_line_width (renderer->cr, lw[0]); cairo_device_to_user (renderer->cr, &x1u, &y1u); cairo_device_to_user (renderer->cr, &x2u, &y2u); cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0); cairo_rectangle (renderer->cr, x1u, y1u, x2u - x1u, y2u - y1u); cairo_stroke (renderer->cr); }
static void draw_pixel_line(DiaRenderer *object, int x1, int y1, int x2, int y2, Color *color) { DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (object); double x1u = x1 + .5, y1u = y1 + .5, x2u = x2 + .5, y2u = y2 + .5; double lw[2]; lw[0] = 1; lw[1] = 0; cairo_device_to_user_distance (renderer->cr, &lw[0], &lw[1]); cairo_set_line_width (renderer->cr, lw[0]); cairo_device_to_user (renderer->cr, &x1u, &y1u); cairo_device_to_user (renderer->cr, &x2u, &y2u); cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0); cairo_move_to (renderer->cr, x1u, y1u); cairo_line_to (renderer->cr, x2u, y2u); cairo_stroke (renderer->cr); }
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) { FloatRect result; double x = frect.x(); double y = frect.y(); cairo_t* cr = m_data->cr; cairo_user_to_device(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user(cr, &x, &y); result.setX(static_cast<float>(x)); result.setY(static_cast<float>(y)); x = frect.width(); y = frect.height(); cairo_user_to_device_distance(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user_distance(cr, &x, &y); result.setWidth(static_cast<float>(x)); result.setHeight(static_cast<float>(y)); return result; }
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; double x = frect.x(); double y = frect.y(); cairo_t* cr = platformContext()->cr(); cairo_user_to_device(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user(cr, &x, &y); result.setX(narrowPrecisionToFloat(x)); result.setY(narrowPrecisionToFloat(y)); // We must ensure width and height are at least 1 (or -1) when // we're given float values in the range between 0 and 1 (or -1 and 0). double width = frect.width(); double height = frect.height(); cairo_user_to_device_distance(cr, &width, &height); if (width > -1 && width < 0) width = -1; else if (width > 0 && width < 1) width = 1; else width = round(width); if (height > -1 && width < 0) height = -1; else if (height > 0 && height < 1) height = 1; else height = round(height); cairo_device_to_user_distance(cr, &width, &height); result.setWidth(narrowPrecisionToFloat(width)); result.setHeight(narrowPrecisionToFloat(height)); return result; }
int draw_image_to_cairo_target (cairo_t *cairoTarget, gerbv_image_t *image, gdouble pixelWidth, enum draw_mode drawMode, gerbv_selection_info_t *selectionInfo, gerbv_render_info_t *renderInfo, gboolean allowOptimization, gerbv_user_transformation_t transform, gboolean pixelOutput) { const int hole_cross_inc_px = 8; struct gerbv_net *net, *polygonStartNet=NULL; double x1, y1, x2, y2, cp_x=0, cp_y=0; gdouble *p, p0, p1, dx, dy, lineWidth, r; gerbv_netstate_t *oldState; gerbv_layer_t *oldLayer; cairo_operator_t drawOperatorClear, drawOperatorDark; gboolean invertPolarity = FALSE, oddWidth = FALSE; gdouble minX=0, minY=0, maxX=0, maxY=0; gdouble criticalRadius; gdouble scaleX = transform.scaleX; gdouble scaleY = transform.scaleY; gboolean limitLineWidth = TRUE; gboolean displayPixel = TRUE; /* If we are scaling the image at all, ignore the line width checks * since scaled up lines can still be visible */ if ((scaleX != 1)||(scaleY != 1)){ limitLineWidth = FALSE; } if (transform.mirrorAroundX) scaleY *= -1; if (transform.mirrorAroundY) scaleX *= -1; cairo_translate (cairoTarget, transform.translateX, transform.translateY); cairo_scale (cairoTarget, scaleX, scaleY); cairo_rotate (cairoTarget, transform.rotation); gboolean useOptimizations = allowOptimization; /* If the user is using any transformations for this layer, then don't * bother using rendering optimizations */ if ((fabs(transform.translateX) > 0.00001) || (fabs(transform.translateY) > 0.00001) || (fabs(transform.scaleX - 1) > 0.00001) || (fabs(transform.scaleY - 1) > 0.00001) || (fabs(transform.rotation) > 0.00001) || transform.mirrorAroundX || transform.mirrorAroundY) useOptimizations = FALSE; if (useOptimizations && pixelOutput) { minX = renderInfo->lowerLeftX; minY = renderInfo->lowerLeftY; maxX = renderInfo->lowerLeftX + (renderInfo->displayWidth / renderInfo->scaleFactorX); maxY = renderInfo->lowerLeftY + (renderInfo->displayHeight / renderInfo->scaleFactorY); } /* do initial justify */ cairo_translate (cairoTarget, image->info->imageJustifyOffsetActualA, image->info->imageJustifyOffsetActualB); /* set the fill rule so aperture holes are cleared correctly */ cairo_set_fill_rule (cairoTarget, CAIRO_FILL_RULE_EVEN_ODD); /* offset image */ cairo_translate (cairoTarget, image->info->offsetA, image->info->offsetB); /* do image rotation */ cairo_rotate (cairoTarget, image->info->imageRotation); /* load in polarity operators depending on the image polarity */ invertPolarity = transform.inverted; if (image->info->polarity == GERBV_POLARITY_NEGATIVE) invertPolarity = !invertPolarity; if (drawMode == DRAW_SELECTIONS) invertPolarity = FALSE; if (invertPolarity) { drawOperatorClear = CAIRO_OPERATOR_OVER; drawOperatorDark = CAIRO_OPERATOR_CLEAR; cairo_set_operator (cairoTarget, CAIRO_OPERATOR_OVER); cairo_paint (cairoTarget); cairo_set_operator (cairoTarget, CAIRO_OPERATOR_CLEAR); } else { drawOperatorClear = CAIRO_OPERATOR_CLEAR; drawOperatorDark = CAIRO_OPERATOR_OVER; } /* next, push two cairo states to simulate the first layer and netstate translations (these will be popped when another layer or netstate is started */ cairo_save (cairoTarget); cairo_save (cairoTarget); /* store the current layer and netstate so we know when they change */ oldLayer = image->layers; oldState = image->states; for (net = image->netlist->next; net != NULL; net = gerbv_image_return_next_renderable_object(net)) { /* check if this is a new layer */ if (net->layer != oldLayer){ /* it's a new layer, so recalculate the new transformation matrix for it */ cairo_restore (cairoTarget); cairo_restore (cairoTarget); cairo_save (cairoTarget); /* do any rotations */ cairo_rotate (cairoTarget, net->layer->rotation); /* handle the layer polarity */ if ((net->layer->polarity == GERBV_POLARITY_CLEAR)^invertPolarity) { cairo_set_operator (cairoTarget, CAIRO_OPERATOR_CLEAR); drawOperatorClear = CAIRO_OPERATOR_OVER; drawOperatorDark = CAIRO_OPERATOR_CLEAR; } else { cairo_set_operator (cairoTarget, CAIRO_OPERATOR_OVER); drawOperatorClear = CAIRO_OPERATOR_CLEAR; drawOperatorDark = CAIRO_OPERATOR_OVER; } /* Draw any knockout areas */ gerbv_knockout_t *ko = &net->layer->knockout; if (ko->firstInstance == TRUE) { cairo_operator_t oldOperator = cairo_get_operator (cairoTarget); if (ko->polarity == GERBV_POLARITY_CLEAR) { cairo_set_operator (cairoTarget, drawOperatorClear); } else { cairo_set_operator (cairoTarget, drawOperatorDark); } cairo_new_path (cairoTarget); cairo_rectangle (cairoTarget, ko->lowerLeftX - ko->border, ko->lowerLeftY - ko->border, ko->width + 2*ko->border, ko->height + 2*ko->border); draw_fill (cairoTarget, drawMode, selectionInfo, image, net); cairo_set_operator (cairoTarget, oldOperator); } /* Finally, reapply old netstate transformation */ cairo_save (cairoTarget); draw_apply_netstate_transformation (cairoTarget, net->state); oldLayer = net->layer; } /* check if this is a new netstate */ if (net->state != oldState){ /* pop the transformation matrix back to the "pre-state" state and resave it */ cairo_restore (cairoTarget); cairo_save (cairoTarget); /* it's a new state, so recalculate the new transformation matrix for it */ draw_apply_netstate_transformation (cairoTarget, net->state); oldState = net->state; } /* if we are only drawing from the selection buffer, search if this net is in the buffer */ if (drawMode == DRAW_SELECTIONS) { /* this flag makes sure we don't draw any unintentional polygons... if we've successfully entered a polygon (the first net matches, and we don't want to check the nets inside the polygon) then polygonStartNet will be set */ if (!polygonStartNet) { if (!draw_net_is_in_selection_buffer_remove (net, selectionInfo, FALSE)) continue; } } /* step and repeat */ gerbv_step_and_repeat_t *sr = &net->layer->stepAndRepeat; int ix, iy; for (ix = 0; ix < sr->X; ix++) { for (iy = 0; iy < sr->Y; iy++) { double sr_x = ix * sr->dist_X; double sr_y = iy * sr->dist_Y; if (useOptimizations && pixelOutput && ((net->boundingBox.right+sr_x < minX) || (net->boundingBox.left+sr_x > maxX) || (net->boundingBox.top+sr_y < minY) || (net->boundingBox.bottom+sr_y > maxY))) { continue; } x1 = net->start_x + sr_x; y1 = net->start_y + sr_y; x2 = net->stop_x + sr_x; y2 = net->stop_y + sr_y; /* translate circular x,y data as well */ if (net->cirseg) { cp_x = net->cirseg->cp_x + sr_x; cp_y = net->cirseg->cp_y + sr_y; } /* render any labels attached to this net */ /* NOTE: this is currently only used on PNP files, so we may make some assumptions here... */ if (net->label) { cairo_set_font_size (cairoTarget, 0.05); cairo_save (cairoTarget); cairo_move_to (cairoTarget, x1, y1); cairo_scale (cairoTarget, 1, -1); cairo_show_text (cairoTarget, net->label->str); cairo_restore (cairoTarget); } /* Polygon area fill routines */ switch (net->interpolation) { case GERBV_INTERPOLATION_PAREA_START : draw_render_polygon_object (net, cairoTarget, sr_x, sr_y, image, drawMode, selectionInfo, pixelOutput); continue; case GERBV_INTERPOLATION_DELETED: continue; default : break; } /* * If aperture state is off we allow use of undefined apertures. * This happens when gerber files starts, but hasn't decided on * which aperture to use. */ if (image->aperture[net->aperture] == NULL) continue; switch (net->aperture_state) { case GERBV_APERTURE_STATE_ON : /* if the aperture width is truly 0, then render as a 1 pixel width line. 0 diameter apertures are used by some programs to draw labels, etc, and they are rendered by other programs as 1 pixel wide */ /* NOTE: also, make sure all lines are at least 1 pixel wide, so they always show up at low zoom levels */ if (limitLineWidth&&((image->aperture[net->aperture]->parameter[0] < pixelWidth)&& (pixelOutput))) criticalRadius = pixelWidth/2.0; else criticalRadius = image->aperture[net->aperture]->parameter[0]/2.0; lineWidth = criticalRadius*2.0; // convert to a pixel integer cairo_user_to_device_distance (cairoTarget, &lineWidth, &x1); if (pixelOutput) { lineWidth = round(lineWidth); if ((int)lineWidth % 2) { oddWidth = TRUE; } else { oddWidth = FALSE; } } cairo_device_to_user_distance (cairoTarget, &lineWidth, &x1); cairo_set_line_width (cairoTarget, lineWidth); switch (net->interpolation) { case GERBV_INTERPOLATION_x10 : case GERBV_INTERPOLATION_LINEARx01 : case GERBV_INTERPOLATION_LINEARx001 : case GERBV_INTERPOLATION_LINEARx1 : cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND); /* weed out any lines that are * obviously not going to * render on the visible screen */ switch (image->aperture[net->aperture]->type) { case GERBV_APTYPE_CIRCLE : if (renderInfo->show_cross_on_drill_holes && image->layertype == GERBV_LAYERTYPE_DRILL) { /* Draw center crosses on slot hole */ cairo_set_line_width (cairoTarget, pixelWidth); cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE); r = image->aperture[net->aperture]->parameter[0]/2.0 + hole_cross_inc_px*pixelWidth; draw_cairo_cross (cairoTarget, x1, y1, r); draw_cairo_cross (cairoTarget, x2, y2, r); cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cairoTarget, lineWidth); } draw_cairo_move_to (cairoTarget, x1, y1, oddWidth, pixelOutput); draw_cairo_line_to (cairoTarget, x2, y2, oddWidth, pixelOutput); draw_stroke (cairoTarget, drawMode, selectionInfo, image, net); break; case GERBV_APTYPE_RECTANGLE : dx = image->aperture[net->aperture]->parameter[0]/2; dy = image->aperture[net->aperture]->parameter[1]/2; if(x1 > x2) dx = -dx; if(y1 > y2) dy = -dy; cairo_new_path(cairoTarget); draw_cairo_move_to (cairoTarget, x1 - dx, y1 - dy, FALSE, pixelOutput); draw_cairo_line_to (cairoTarget, x1 - dx, y1 + dy, FALSE, pixelOutput); draw_cairo_line_to (cairoTarget, x2 - dx, y2 + dy, FALSE, pixelOutput); draw_cairo_line_to (cairoTarget, x2 + dx, y2 + dy, FALSE, pixelOutput); draw_cairo_line_to (cairoTarget, x2 + dx, y2 - dy, FALSE, pixelOutput); draw_cairo_line_to (cairoTarget, x1 + dx, y1 - dy, FALSE, pixelOutput); draw_fill (cairoTarget, drawMode, selectionInfo, image, net); break; /* TODO: for now, just render ovals or polygons like a circle */ case GERBV_APTYPE_OVAL : case GERBV_APTYPE_POLYGON : draw_cairo_move_to (cairoTarget, x1,y1, oddWidth, pixelOutput); draw_cairo_line_to (cairoTarget, x2,y2, oddWidth, pixelOutput); draw_stroke (cairoTarget, drawMode, selectionInfo, image, net); break; /* macros can only be flashed, so ignore any that might be here */ default: GERB_COMPILE_WARNING(_("Skipped aperture type \"%s\""), _(aperture_names[image->aperture[net->aperture]->type])); break; } break; case GERBV_INTERPOLATION_CW_CIRCULAR : case GERBV_INTERPOLATION_CCW_CIRCULAR : /* cairo doesn't have a function to draw oval arcs, so we must * draw an arc and stretch it by scaling different x and y values */ cairo_new_path(cairoTarget); if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE) { cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE); } else { cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND); } cairo_save (cairoTarget); cairo_translate(cairoTarget, cp_x, cp_y); cairo_scale (cairoTarget, net->cirseg->width, net->cirseg->height); if (net->cirseg->angle2 > net->cirseg->angle1) { cairo_arc (cairoTarget, 0.0, 0.0, 0.5, DEG2RAD(net->cirseg->angle1), DEG2RAD(net->cirseg->angle2)); } else { cairo_arc_negative (cairoTarget, 0.0, 0.0, 0.5, DEG2RAD(net->cirseg->angle1), DEG2RAD(net->cirseg->angle2)); } cairo_restore (cairoTarget); draw_stroke (cairoTarget, drawMode, selectionInfo, image, net); break; default : GERB_COMPILE_WARNING(_("Skipped interpolation type %d"), net->interpolation); break; } break; case GERBV_APERTURE_STATE_OFF : break; case GERBV_APERTURE_STATE_FLASH : p = image->aperture[net->aperture]->parameter; cairo_save (cairoTarget); draw_cairo_translate_adjust(cairoTarget, x2, y2, pixelOutput); switch (image->aperture[net->aperture]->type) { case GERBV_APTYPE_CIRCLE : if (renderInfo->show_cross_on_drill_holes && image->layertype == GERBV_LAYERTYPE_DRILL) { /* Draw center cross on drill hole */ cairo_set_line_width (cairoTarget, pixelWidth); cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE); r = p[0]/2.0 + hole_cross_inc_px*pixelWidth; draw_cairo_cross (cairoTarget, 0, 0, r); cairo_set_line_width (cairoTarget, lineWidth); cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND); } gerbv_draw_circle(cairoTarget, p[0]); gerbv_draw_aperture_hole (cairoTarget, p[1], p[2], pixelOutput); break; case GERBV_APTYPE_RECTANGLE : // some CAD programs use very thin flashed rectangles to compose // logos/images, so we must make sure those display here displayPixel = pixelOutput; p0 = p[0]; p1 = p[1]; if (limitLineWidth && (p[0] < pixelWidth) && pixelOutput) { p0 = pixelWidth; displayPixel = FALSE; } if (limitLineWidth && (p[1] < pixelWidth) && pixelOutput) { p1 = pixelWidth; displayPixel = FALSE; } gerbv_draw_rectangle(cairoTarget, p0, p1, displayPixel); gerbv_draw_aperture_hole (cairoTarget, p[2], p[3], displayPixel); break; case GERBV_APTYPE_OVAL : gerbv_draw_oblong(cairoTarget, p[0], p[1]); gerbv_draw_aperture_hole (cairoTarget, p[2], p[3], pixelOutput); break; case GERBV_APTYPE_POLYGON : gerbv_draw_polygon(cairoTarget, p[0], p[1], p[2]); gerbv_draw_aperture_hole (cairoTarget, p[3], p[4], pixelOutput); break; case GERBV_APTYPE_MACRO : gerbv_draw_amacro(cairoTarget, drawOperatorClear, drawOperatorDark, image->aperture[net->aperture]->simplified, (gint)p[0], pixelWidth, drawMode, selectionInfo, image, net); break; default : GERB_MESSAGE(_("Unknown aperture type")); return 0; } /* and finally fill the path */ draw_fill (cairoTarget, drawMode, selectionInfo, image, net); cairo_restore (cairoTarget); break; default: GERB_MESSAGE(_("Unknown aperture state")); return 0; } } } } /* restore the initial two state saves (one for layer, one for netstate)*/ cairo_restore (cairoTarget); cairo_restore (cairoTarget); return 1; }
void LcCairoPainter::device_to_user_distance(double* dx, double* dy) { cairo_device_to_user_distance(_cr, dx, dy); }
void Context::deviceToUserDistance( double *dx, double *dy ) { cairo_device_to_user_distance( mCairo, dx, dy ); }
void _cairo_paint_grid (cairo_t *cr, cairo_rectangle_int_t *rectangle, GthGridType grid_type) { double ux, uy; cairo_save (cr); ux = uy = 1.0; cairo_device_to_user_distance (cr, &ux, &uy); cairo_set_line_width (cr, MAX (ux, uy)); cairo_rectangle (cr, rectangle->x - ux + 0.5, rectangle->y - uy + 0.5, rectangle->width + (ux * 2), rectangle->height + (uy * 2)); cairo_clip (cr); #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 2) cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE); #endif cairo_rectangle (cr, rectangle->x + 0.5, rectangle->y + 0.5, rectangle->width - 0.5, rectangle->height - 0.5); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_stroke (cr); if (grid_type == GTH_GRID_NONE) { cairo_restore (cr); return; } if (grid_type == GTH_GRID_THIRDS) { int i; cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60); for (i = 1; i < 3; i++) { cairo_move_to (cr, rectangle->x + rectangle->width * i / 3 + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + rectangle->width * i / 3 + 0.5, rectangle->y + rectangle->height - 0.5); cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 3 + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 3 + 0.5); } cairo_stroke (cr); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10); for (i = 1; i < 9; i++) { if (i % 3 == 0) continue; cairo_move_to (cr, rectangle->x + rectangle->width * i / 9 + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + rectangle->width * i / 9 + 0.5, rectangle->y + rectangle->height - 0.5); cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 9 + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 9 + 0.5); } cairo_stroke (cr); } else if (grid_type == GTH_GRID_GOLDEN) { cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60); int grid_x0, grid_x1, grid_x2, grid_x3; int grid_y0, grid_y1, grid_y2, grid_y3; int x_delta, y_delta; grid_x0 = rectangle->x; grid_x3 = rectangle->x + rectangle->width; grid_y0 = rectangle->y; grid_y3 = rectangle->y + rectangle->height; x_delta = rectangle->width * GOLDER_RATIO_FACTOR; y_delta = rectangle->height * GOLDER_RATIO_FACTOR; grid_x1 = grid_x0 + x_delta; grid_x2 = grid_x3 - x_delta; grid_y1 = grid_y0 + y_delta; grid_y2 = grid_y3 - y_delta; cairo_move_to (cr, grid_x1 + 0.5, grid_y0 + 0.5); cairo_line_to (cr, grid_x1 + 0.5, grid_y3 + 0.5); if (x_delta < rectangle->width / 2) { cairo_move_to (cr, grid_x2 + 0.5, grid_y0 + 0.5); cairo_line_to (cr, grid_x2 + 0.5, grid_y3 + 0.5); } cairo_move_to (cr, grid_x0 + 0.5, grid_y1 + 0.5); cairo_line_to (cr, grid_x3 + 0.5, grid_y1 + 0.5); if (y_delta < rectangle->height / 2) { cairo_move_to (cr, grid_x0 + 0.5, grid_y2 + 0.5); cairo_line_to (cr, grid_x3 + 0.5, grid_y2 + 0.5); } cairo_stroke (cr); } else if (grid_type == GTH_GRID_CENTER) { int i; cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60); cairo_move_to (cr, rectangle->x + rectangle->width / 2 + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + rectangle->width / 2 + 0.5, rectangle->y + rectangle->height - 0.5); cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height / 2 + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height / 2 + 0.5); cairo_stroke (cr); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10); for (i = 1; i < 4; i++) { if (i == 2) continue; cairo_move_to (cr, rectangle->x + rectangle->width * i / 4 + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + rectangle->width * i / 4 + 0.5, rectangle->y + rectangle->height - 0.5); cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 4 + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 4 + 0.5); } cairo_stroke (cr); } else if (grid_type == GTH_GRID_UNIFORM) { int x; int y; if (rectangle->width / GRID_STEP_3 <= MAX_GRID_LINES) { cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.40); for (x = GRID_STEP_3; x < rectangle->width; x += GRID_STEP_3) { cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5); } for (y = GRID_STEP_3; y < rectangle->height; y += GRID_STEP_3) { cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5); } cairo_stroke (cr); } if (rectangle->width / GRID_STEP_2 <= MAX_GRID_LINES) { cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.20); for (x = GRID_STEP_2; x < rectangle->width; x += GRID_STEP_2) { if (x % GRID_STEP_3 == 0) continue; cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5); } for (y = GRID_STEP_2; y < rectangle->height; y += GRID_STEP_2) { if (y % GRID_STEP_3 == 0) continue; cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5); } cairo_stroke (cr); } if (rectangle->width / GRID_STEP_1 <= MAX_GRID_LINES) { cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10); for (x = GRID_STEP_1; x < rectangle->width; x += GRID_STEP_1) { if (x % GRID_STEP_2 == 0) continue; cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5); cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5); } for (y = GRID_STEP_1; y < rectangle->height; y += GRID_STEP_1) { if (y % GRID_STEP_2 == 0) continue; cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5); cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5); } } cairo_stroke (cr); } cairo_restore (cr); }
GpStatus gdip_pen_setup (GpGraphics *graphics, GpPen *pen) { GpStatus status; cairo_matrix_t product; double widthx; if (!graphics || !pen) return InvalidParameter; status = gdip_brush_setup (graphics, pen->brush); if (status != Ok) return status; cairo_matrix_init_identity (&product); /* Here we use product of pen->matrix and graphics->copy_of_ctm. * This gives us absolute results with respect to graphics. We * do following irrespective of the pen->changed state since graphics * has its own matrix and we need to multiply that with pen->matrix * every time we perform stroke operations. Graphics matrix gets * reset to its own state after stroking. */ cairo_matrix_multiply (&product, &pen->matrix, graphics->copy_of_ctm); /* Pen scaling by 0 are supported by MS GDI+ but would error in Cairo, see bug #338233 */ if (gdip_near_zero (product.xx) || gdip_near_zero (product.yy)) { /* *both* X and Y are affected if either is 0 */ product.xx = product.yy = 0.0001f; } cairo_set_matrix (graphics->ct, &product); /* Don't need to setup, if pen is the same as the cached pen and * it is not changed. Just comparing pointers may not be sufficient * to say that the pens are same. It is possible to have different * pen on the same memory, but probability is very low. We would * need a function to check the equality of the pens in that case. */ if (pen == graphics->last_pen && !pen->changed) return Ok; if (pen->width < 1.0) { /* we draw a pixel wide line if width is < 1.0 */ double widthy = 1.0; widthx = 1.0; cairo_device_to_user_distance (graphics->ct, &widthx, &widthy); } else { widthx = (double) pen->width; } cairo_set_line_width (graphics->ct, widthx); cairo_set_miter_limit (graphics->ct, (double) pen->miter_limit); cairo_set_line_join (graphics->ct, convert_line_join (pen->line_join)); cairo_set_line_cap (graphics->ct, convert_line_cap (pen)); if (pen->dash_count > 0) { double *dash_array; /* note: pen->width may be different from what was used to call cairo_set_line_width, e.g. 0.0 (#78742) */ dash_array = convert_dash_array (pen->dash_array, widthx, pen->dash_count); if (!dash_array) return OutOfMemory; cairo_set_dash (graphics->ct, dash_array, pen->dash_count, pen->dash_offset); GdipFree (dash_array); } else /* Clear the dashes, if set in previous calls */ cairo_set_dash (graphics->ct, NULL, 0, 0); /* We are done with using all the changes in the pen. */ pen->changed = FALSE; graphics->last_pen = pen; return gdip_get_status (cairo_status (graphics->ct)); }
void eda_cairo_stroke (cairo_t *cr, int flags, int line_type, int line_end, double wwidth, double wlength, double wspace) { double offset = 0; double dashes[4]; double dummy = 0; cairo_line_cap_t cap; cairo_line_cap_t round_cap_if_legible = CAIRO_LINE_CAP_ROUND; int num_dashes; int iwidth; double width = wwidth, length = wlength, space = wspace; if (flags & EDA_CAIRO_ENABLE_HINTS) { width = iwidth = screen_width (cr, wwidth); length = screen_width (cr, wlength); space = screen_width (cr, wspace); cairo_device_to_user_distance (cr, &width, &dummy); cairo_device_to_user_distance (cr, &length, &dummy); cairo_device_to_user_distance (cr, &space, &dummy); offset = ((iwidth % 2) == 0) ? 0 : 0.5; round_cap_if_legible = (iwidth <= 1) ? CAIRO_LINE_CAP_SQUARE : CAIRO_LINE_CAP_ROUND; } cairo_set_line_width (cr, width); cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); switch (line_end) { case END_NONE: cap = CAIRO_LINE_CAP_BUTT; break; case END_SQUARE: cap = CAIRO_LINE_CAP_SQUARE; break; case END_ROUND: cap = round_cap_if_legible; break; default: g_warn_if_reached (); cap = CAIRO_LINE_CAP_BUTT; break; } switch (line_type) { default: g_warn_if_reached (); /* Fall through */ case TYPE_SOLID: num_dashes = 0; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, cap); cairo_stroke (cr); break; case TYPE_DOTTED: dashes[0] = 0; /* DOT */ dashes[1] = space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; case TYPE_DASHED: dashes[0] = length; /* DASH */ dashes[1] = space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke (cr); break; case TYPE_CENTER: dashes[0] = length; /* DASH */ dashes[1] = 2 * space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke_preserve (cr); dashes[0] = 0; /* DOT */ dashes[1] = 2 * space + length; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, -length - space + offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; case TYPE_PHANTOM: dashes[0] = length; /* DASH */ dashes[1] = 3 * space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke_preserve (cr); dashes[0] = 0; /* DOT */ dashes[1] = space; dashes[2] = 0; /* DOT */ dashes[3] = 2 * space + length; num_dashes = 4; cairo_set_dash (cr, dashes, num_dashes, -length - space + offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; } cairo_set_dash (cr, NULL, 0, 0.); }