コード例 #1
0
ファイル: draw.c プロジェクト: SayCV/geda-gerbv
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;
}
コード例 #2
0
ファイル: draw-gdk.c プロジェクト: rupin/test-gerbv
/*
 * Convert a gerber image to a GDK clip mask to be used when creating pixmap
 */
int
draw_gdk_image_to_pixmap(GdkPixmap **pixmap, gerbv_image_t *image, 
	     double scale, double trans_x, double trans_y,
	     gchar drawMode,
	     gerbv_selection_info_t *selectionInfo, gerbv_render_info_t *renderInfo,
	     gerbv_user_transformation_t transform)
{
	GdkGC *gc = gdk_gc_new(*pixmap);
	GdkGC *pgc = gdk_gc_new(*pixmap);
	GdkGCValues gc_values;
	struct gerbv_net *net;
	gerbv_netstate_t *oldState;
	gerbv_layer_t *oldLayer;
	gint x1, y1, x2, y2;
	glong xlong1, ylong1, xlong2, ylong2;
	int p1, p2;
	int cir_width = 0, cir_height = 0;
	int cp_x = 0, cp_y = 0;
	GdkColor transparent, opaque;
	gerbv_polarity_t polarity;
	gdouble tempX,tempY;
	gdouble minX=0,minY=0,maxX=0,maxY=0;

	if (transform.inverted) {
		if (image->info->polarity == GERBV_POLARITY_POSITIVE)
			polarity = GERBV_POLARITY_NEGATIVE;
		else
			polarity = GERBV_POLARITY_POSITIVE;
	} else {
		polarity = image->info->polarity;
	}
	if (drawMode == DRAW_SELECTIONS)
		polarity = GERBV_POLARITY_POSITIVE;

	gboolean useOptimizations = TRUE;
	// 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;

	// calculate the transformation matrix for the user_transformation options
	cairo_matrix_t fullMatrix, scaleMatrix;
	cairo_matrix_init (&fullMatrix, 1, 0, 0, 1, 0, 0);
	cairo_matrix_init (&scaleMatrix, 1, 0, 0, 1, 0, 0);

	cairo_matrix_translate (&fullMatrix, trans_x, trans_y);
	cairo_matrix_scale (&fullMatrix, scale, scale);
	cairo_matrix_scale (&scaleMatrix, scale, scale);
	/* offset image */

	cairo_matrix_translate (&fullMatrix, transform.translateX, -1*transform.translateY);
	// don't use mirroring for the scale matrix
	gdouble scaleX = transform.scaleX;
	gdouble scaleY = -1*transform.scaleY;
	cairo_matrix_scale (&scaleMatrix, scaleX, -1*scaleY);
	if (transform.mirrorAroundX)
		scaleY *= -1;
	if (transform.mirrorAroundY)
		scaleX *= -1;

	cairo_matrix_scale (&fullMatrix, scaleX, scaleY);
	/* do image rotation */
	cairo_matrix_rotate (&fullMatrix, transform.rotation);
	//cairo_matrix_rotate (&scaleMatrix, transform.rotation);

	/* do image rotation */
	cairo_matrix_rotate (&fullMatrix, image->info->imageRotation);

	if (useOptimizations) {
		minX = renderInfo->lowerLeftX;
		minY = renderInfo->lowerLeftY;
		maxX = renderInfo->lowerLeftX + (renderInfo->displayWidth /
					renderInfo->scaleFactorX);
		maxY = renderInfo->lowerLeftY + (renderInfo->displayHeight /
					renderInfo->scaleFactorY);
	}

	if (image == NULL || image->netlist == NULL) {
		/*
		 * Destroy GCs before exiting
		 */
		gdk_gc_unref(gc);
		gdk_gc_unref(pgc);

		return 0;
	}

	/* Set up the two "colors" we have */
	opaque.pixel = 0; /* opaque will not let color through */
	transparent.pixel = 1; /* transparent will let color through */ 

	/*
	* Clear clipmask and set draw color depending image on image polarity
	*/
	if (polarity == GERBV_POLARITY_NEGATIVE) {
		gdk_gc_set_foreground(gc, &transparent);
		gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
		gdk_gc_set_foreground(gc, &opaque);
	} else {
		gdk_gc_set_foreground(gc, &opaque);
		gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
		gdk_gc_set_foreground(gc, &transparent);
	}
	oldLayer = image->layers;
	oldState = image->states;
	for (net = image->netlist->next ; net != NULL; net = gerbv_image_return_next_renderable_object(net)) {
		int repeat_X=1, repeat_Y=1;
		double repeat_dist_X=0.0, repeat_dist_Y=0.0;
		int repeat_i, repeat_j;

		/*
		 * If step_and_repeat (%SR%) used, repeat the drawing;
		 */
		repeat_X = net->layer->stepAndRepeat.X;
		repeat_Y = net->layer->stepAndRepeat.Y;
		repeat_dist_X = net->layer->stepAndRepeat.dist_X;
		repeat_dist_Y = net->layer->stepAndRepeat.dist_Y;

		/* check if this is a new netstate */
		if (net->state != oldState){
			/* it's a new state, so recalculate the new transformation matrix
			   for it */
			draw_gdk_apply_netstate_transformation (&fullMatrix, &scaleMatrix, net->state);
			oldState = net->state;	
		}
		/* check if this is a new layer */
		/* for now, only do layer rotations in GDK rendering */
		if (net->layer != oldLayer){
			cairo_matrix_rotate (&fullMatrix, net->layer->rotation);
			oldLayer = net->layer;
		}

		if (drawMode == DRAW_SELECTIONS) {
			int i;
			gboolean foundNet = FALSE;
			
			for (i=0; i<selectionInfo->selectedNodeArray->len; i++){
				gerbv_selection_item_t sItem = g_array_index (selectionInfo->selectedNodeArray,
					gerbv_selection_item_t, i);
				if (sItem.net == net)
					foundNet = TRUE;
			}
			if (!foundNet)
				continue;
		}

		for(repeat_i = 0; repeat_i < repeat_X; repeat_i++) {
		for(repeat_j = 0; repeat_j < repeat_Y; repeat_j++) {
		  double sr_x = repeat_i * repeat_dist_X;
		  double sr_y = repeat_j * repeat_dist_Y;
			
			if ((useOptimizations)&&((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;
			}

		/* 
		 * If circle segment, scale and translate that one too
		 */
		if (net->cirseg) {
		    tempX = net->cirseg->width;
		    tempY = net->cirseg->height;
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    cir_width = (int)round(tempX);
		    cir_height = (int)round(tempY);
		    
		    tempX = net->cirseg->cp_x;
		    tempY = net->cirseg->cp_y;
		    cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		    cp_x = (int)round(tempX);
		    cp_y = (int)round(tempY);
		}

		/*
		 * Set GdkFunction depending on if this (gerber) layer is inverted
		 * and allow for the photoplot being negative.
		 */
		gdk_gc_set_function(gc, GDK_COPY);
		if ((net->layer->polarity == GERBV_POLARITY_CLEAR) != (polarity == GERBV_POLARITY_NEGATIVE))
		    gdk_gc_set_foreground(gc, &opaque);
		else
		    gdk_gc_set_foreground(gc, &transparent);

		/*
		 * Polygon Area Fill routines
		 */
		switch (net->interpolation) {
		case GERBV_INTERPOLATION_PAREA_START :
		    draw_gdk_render_polygon_object (net,image,sr_x,sr_y,&fullMatrix,
		    	&scaleMatrix,gc,pgc,pixmap);
		    continue;
		/* make sure we completely skip over any deleted nodes */
		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) {
		  /* Commenting this out since it gets emitted every time you click on the screen 
		     if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
		     GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
		  */
		    continue;
		}

		/*
		 * Scale points with window scaling and translate them
		 */
		tempX = net->start_x + sr_x;
		tempY = net->start_y + sr_y;
		cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		xlong1 = (int)round(tempX);
		ylong1 = (int)round(tempY);

		tempX = net->stop_x + sr_x;
		tempY = net->stop_y + sr_y;
		cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
		xlong2 = (int)round(tempX);
		ylong2 = (int)round(tempY);

		/* if the object is way outside our view window, just skip over it in order
		   to eliminate some GDK clipping problems at high zoom levels */
		if ((xlong1 < -10000) && (xlong2 < -10000))
			continue;
		if ((ylong1 < -10000) && (ylong2 < -10000))
			continue;
		if ((xlong1 > 10000) && (xlong2 > 10000))
			continue;
		if ((ylong1 > 10000) && (ylong2 > 10000))
			continue;

		if (xlong1 > G_MAXINT) x1 = G_MAXINT;
		else if (xlong1 < G_MININT) x1 = G_MININT;
		else x1 = (int)xlong1;

		if (xlong2 > G_MAXINT) x2 = G_MAXINT;
		else if (xlong2 < G_MININT) x2 = G_MININT;
		else x2 = (int)xlong2;

		if (ylong1 > G_MAXINT) y1 = G_MAXINT;
		else if (ylong1 < G_MININT) y1 = G_MININT;
		else y1 = (int)ylong1;

		if (ylong2 > G_MAXINT) y2 = G_MAXINT;
		else if (ylong2 < G_MININT) y2 = G_MININT;
		else y2 = (int)ylong2;
			
		switch (net->aperture_state) {
		case GERBV_APERTURE_STATE_ON :
		    tempX = image->aperture[net->aperture]->parameter[0];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    p1 = (int)round(tempX);

		   // p1 = (int)round(image->aperture[net->aperture]->parameter[0] * scale);
		    if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE)
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID, 
						   GDK_CAP_PROJECTING, 
						   GDK_JOIN_MITER);
		    else
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID, 
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
		    
		    switch (net->interpolation) {
		    case GERBV_INTERPOLATION_x10 :
		    case GERBV_INTERPOLATION_LINEARx01 :
		    case GERBV_INTERPOLATION_LINEARx001 :
			GERB_MESSAGE(_("Linear != x1\n"));
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_ON_OFF_DASH, 
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
			gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
			gdk_gc_set_line_attributes(gc, p1, 
						   GDK_LINE_SOLID,
						   GDK_CAP_ROUND, 
						   GDK_JOIN_MITER);
			break;
		    case GERBV_INTERPOLATION_LINEARx1 :
			if (image->aperture[net->aperture]->type != GERBV_APTYPE_RECTANGLE)
			    gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
			else {
			    gint dx, dy;
			    GdkPoint poly[6];
			    
			    tempX = image->aperture[net->aperture]->parameter[0]/2;
			    tempY = image->aperture[net->aperture]->parameter[1]/2;
			    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
			    dx = (int)round(tempX);
			    dy = (int)round(tempY);

			    if(x1 > x2) dx = -dx;
			    if(y1 > y2) dy = -dy;
			    poly[0].x = x1 - dx; poly[0].y = y1 - dy;
			    poly[1].x = x1 - dx; poly[1].y = y1 + dy;
			    poly[2].x = x2 - dx; poly[2].y = y2 + dy;
			    poly[3].x = x2 + dx; poly[3].y = y2 + dy;
			    poly[4].x = x2 + dx; poly[4].y = y2 - dy;
			    poly[5].x = x1 + dx; poly[5].y = y1 - dy;
			    gdk_draw_polygon(*pixmap, gc, 1, poly, 6);
			}
				break;
		    case GERBV_INTERPOLATION_CW_CIRCULAR :
		    case GERBV_INTERPOLATION_CCW_CIRCULAR :
			gerbv_gdk_draw_arc(*pixmap, gc, cp_x, cp_y, cir_width, cir_height, 
					   net->cirseg->angle1, net->cirseg->angle2);
			break;
		    default :
			break;
		    }
		    break;
		case GERBV_APERTURE_STATE_OFF :
		    break;
		case GERBV_APERTURE_STATE_FLASH :
		    tempX = image->aperture[net->aperture]->parameter[0];
		    tempY = image->aperture[net->aperture]->parameter[1];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    p1 = (int)round(tempX);
		    p2 = (int)round(tempY);
		    tempX = image->aperture[net->aperture]->parameter[2];
		    cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
		    
		    switch (image->aperture[net->aperture]->type) {
		    case GERBV_APTYPE_CIRCLE :
			gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
			/*
			 * If circle has an inner diameter we must remove
			 * that part of the circle to make a hole in it.
			 * We should actually support square holes too,
			 * but due to laziness I don't.
			 */
			if (p2) {
			    gdk_gc_get_values(gc, &gc_values);
			    if (gc_values.foreground.pixel == opaque.pixel) {
				gdk_gc_set_foreground(gc, &transparent);
				gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
				gdk_gc_set_foreground(gc, &opaque);
			    } else {
				gdk_gc_set_foreground(gc, &opaque);
				gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
				gdk_gc_set_foreground(gc, &transparent);
			    }
			}

			break;
		    case GERBV_APTYPE_RECTANGLE:
			gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
			break;
		    case GERBV_APTYPE_OVAL :
			gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
			break;
		    case GERBV_APTYPE_POLYGON :
			gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
			break;
		    case GERBV_APTYPE_MACRO :
			gerbv_gdk_draw_amacro(*pixmap, gc, 
					      image->aperture[net->aperture]->simplified,
					      scale, x2, y2);
			break;
		    default :
			GERB_MESSAGE(_("Unknown aperture type\n"));
			return 0;
		    }
		    break;
		default :
		    GERB_MESSAGE(_("Unknown aperture state\n"));
		    return 0;
		}
		}
		}
	}
	/*
	* Destroy GCs before exiting
	*/
	gdk_gc_unref(gc);
	gdk_gc_unref(pgc);

	return 1;

} /* image2pixmap */