2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* plotPixels.c --
|
|
|
|
|
*
|
|
|
|
|
* This file contains the procedures that generate pix files. each file is
|
|
|
|
|
* a sequence of unsigned chars, each triplet of chars representing a red,
|
|
|
|
|
* green and blue value between 0 and 255 for a pixel. Pixels go across left
|
|
|
|
|
* to right, and down the image.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
* * of the United States of America may require an export license. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plot/plotPixels.c,v 1.2 2008/06/01 18:37:45 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/geofast.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "dbwind/dbwtech.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "plot/plotInt.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "commands/commands.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/tech.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/styles.h"
|
2020-05-23 23:13:14 +02:00
|
|
|
#include "graphics/graphics.h"
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "dbwind/dbwind.h"
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#ifdef LLNL
|
|
|
|
|
|
|
|
|
|
/* forward declarations */
|
|
|
|
|
|
|
|
|
|
void PlotPixFatLine();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* The parameters below control various aspects of the plotting
|
|
|
|
|
* process. The initial values are defaults for the pixels
|
|
|
|
|
* printer. However, many of them can be modified by users
|
|
|
|
|
* with the "plot option" command.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int PlotPixWidth = 512; /* Number of dots across image.
|
|
|
|
|
*/
|
|
|
|
|
int PlotPixHeight = 512; /* Height of swath to generate at one time,
|
|
|
|
|
* in dots.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Directory in which to create temporary file to hold raster: */
|
|
|
|
|
|
|
|
|
|
static char *defaultDirectory = "/usr/tmp";
|
|
|
|
|
extern char *PlotTempDirectory;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* The variables below are shared between the top-level pixels
|
|
|
|
|
* plotting procedure and the lower-level search functions. They
|
|
|
|
|
* contain specific information about how to generate the current
|
|
|
|
|
* plot. There area three coordinate systems of interest here:
|
|
|
|
|
*
|
|
|
|
|
* 1. Magic root coordinates.
|
|
|
|
|
* 2. Raster coordinates: based on printer pixels, one unit per pixel,
|
|
|
|
|
* where (0,0) corresponds to the lower-leftmost dot that will be
|
|
|
|
|
* printed.
|
|
|
|
|
* 3. Swath coordinates: the raster will be much too large to keep in
|
|
|
|
|
* memory all at once, so it's generated in a series of horizontal
|
|
|
|
|
* swaths. The stippling routines all work in swath-relative
|
|
|
|
|
* coordinates, which are the same as raster coordinates except for
|
|
|
|
|
* a y-displacement (swathY below).
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static PixRaster *pixRasterSwath = NULL; /* Raster used to hold current swath. */
|
|
|
|
|
|
|
|
|
|
extern Point plotLL; /* Point in root Magic coords that corresponds
|
|
|
|
|
* to (0,0) in raster coordinates.
|
|
|
|
|
*/
|
|
|
|
|
extern int swathY; /* The y-coordinate in raster coordinates that
|
|
|
|
|
* corresponds to (0,0) in swath coords. It's
|
|
|
|
|
* always >= 0.
|
|
|
|
|
*/
|
|
|
|
|
int scale; /* How many (2**scaleShift)-ths of a pixel
|
|
|
|
|
* correspond to one Magic unit.
|
|
|
|
|
*/
|
|
|
|
|
extern int scaleShift; /* The idea is that one Magic unit is equal
|
|
|
|
|
* to scale/(2**scaleShift) pixels.
|
|
|
|
|
*/
|
|
|
|
|
static Rect rootClip; /* Total root area of the plot. Used for
|
|
|
|
|
* clipping.
|
|
|
|
|
*/
|
|
|
|
|
static Rect swathClip; /* Rectangle used for clipping to the area of
|
|
|
|
|
* the current swath. This is in swath
|
|
|
|
|
* coordinates.
|
|
|
|
|
*/
|
|
|
|
|
static int curStyle; /* Current style being processed. */
|
|
|
|
|
static TileTypeBitMask *curMask; /* Mask of layers currently being stippled.
|
|
|
|
|
* This is the AND of the mask from curStyle
|
|
|
|
|
* and the layers that the user wants plotted.
|
|
|
|
|
*/
|
|
|
|
|
static int crossSize; /* Length of each arm of the crosses used
|
|
|
|
|
* to draw labels, in pixel units.
|
|
|
|
|
*/
|
|
|
|
|
static RasterFont *labelPixFont; /* Font to use when rendering labels. */
|
|
|
|
|
static RasterFont *cellNamePixFont; /* Font to use when rendering cell names. */
|
|
|
|
|
static RasterFont *cellIdPixFont; /* Font to use when rendering cell ids. */
|
|
|
|
|
|
|
|
|
|
#endif /* LLNL */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotPixTechInit --
|
|
|
|
|
*
|
|
|
|
|
* Called once at beginning of technology file read-in to initialize
|
|
|
|
|
* data structures.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Clears out the list of things to plot.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixTechInit()
|
|
|
|
|
{
|
|
|
|
|
/* most intersting stuff is done by PlotVersTechInit -- setting default
|
|
|
|
|
* plot directory, default font names, etc.
|
|
|
|
|
*/
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotPixTechLine --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked by the technology module once for
|
|
|
|
|
* each line in the "pixels" subsection of the "plot" section
|
|
|
|
|
* of the technology file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns TRUE (otherwise the technology module would
|
|
|
|
|
* abort Magic with a fatal error).
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Builds up the table of pixels styles.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
bool
|
|
|
|
|
PlotPixTechLine(sectionName, argc, argv)
|
|
|
|
|
char *sectionName; /* Name of this section (unused). */
|
|
|
|
|
int argc; /* Number of arguments on line. */
|
|
|
|
|
char *argv[]; /* Pointers to fields of line. */
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef LLNL
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotPixPoint --
|
|
|
|
|
*
|
|
|
|
|
* Sets a particular pixel of a PixRaster.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If x and y lie inside the raster then the pixel that they select
|
|
|
|
|
* is set to 1. If x or y is outside the raster area then nothing
|
|
|
|
|
* happens.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixPoint(raster, x, y, style)
|
|
|
|
|
PixRaster *raster; /* Raster containing pixel to be
|
|
|
|
|
* filled.
|
|
|
|
|
*/
|
|
|
|
|
int x, y; /* Coordinates of pixel. */
|
|
|
|
|
int style; /* style to render the pixel with. */
|
|
|
|
|
{
|
|
|
|
|
char *rp; /* ptr to pixel to change. */
|
|
|
|
|
if ((x < 0) || (x >= raster->pix_width)) return;
|
|
|
|
|
y = (raster->pix_height - 1) - y;
|
|
|
|
|
if ((y < 0) || (y >= raster->pix_height)) return;
|
|
|
|
|
|
|
|
|
|
rp = raster->pix_pixels + x + y*raster->pix_width;
|
2020-05-23 23:13:14 +02:00
|
|
|
*rp = (*rp & ~(GrStyleTable[style].mask)) |
|
2017-04-25 14:41:48 +02:00
|
|
|
(GrStyleTable[style].color & GrStyleTable[style].mask);
|
|
|
|
|
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotPixArbLine --
|
|
|
|
|
*
|
|
|
|
|
* Draws a one-pixel-wide line between two points.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A line is drawn between pixels src and dst. Only the portion
|
|
|
|
|
* of the line that lies inside the raster is drawn; the endpoints
|
|
|
|
|
* may lie outside the raster (this feature is necessary to draw
|
|
|
|
|
* straight lines that cross multiple swaths).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixArbLine(raster, src, dst, style)
|
|
|
|
|
Raster *raster; /* Where to render the line. */
|
|
|
|
|
Point *src; /* One endpoint of line, in raster coords. */
|
|
|
|
|
Point *dst; /* The other endpoint, in raster coords. */
|
|
|
|
|
int style; /* Display style to render this line in */
|
|
|
|
|
{
|
|
|
|
|
int x, y, dx, dy, xinc, incr1, incr2, d, done;
|
|
|
|
|
|
|
|
|
|
/* Compute the total x- and y-motions, and arrange for the line to be
|
|
|
|
|
* drawn in increasing order of y-coordinate.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
dx = dst->p_x - src->p_x;
|
|
|
|
|
dy = dst->p_y - src->p_y;
|
|
|
|
|
if (dy < 0)
|
|
|
|
|
{
|
|
|
|
|
dy = -dy;
|
|
|
|
|
dx = -dx;
|
|
|
|
|
x = dst->p_x;
|
|
|
|
|
y = dst->p_y;
|
|
|
|
|
dst = src;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x = src->p_x;
|
|
|
|
|
y = src->p_y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The code below is just the Bresenham algorithm from Foley and
|
|
|
|
|
* Van Dam (pp. 435), modified slightly so that it can work in
|
|
|
|
|
* all directions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (dx < 0)
|
|
|
|
|
{
|
|
|
|
|
xinc = -1;
|
|
|
|
|
dx = -dx;
|
|
|
|
|
}
|
|
|
|
|
else xinc = 1;
|
|
|
|
|
if (dx >= dy)
|
|
|
|
|
{
|
|
|
|
|
d = 2*dy - dx;
|
|
|
|
|
incr1 = 2*dy;
|
|
|
|
|
incr2 = 2*(dy - dx);
|
|
|
|
|
done = dst->p_x;
|
|
|
|
|
for ( ; x != done ; x += xinc)
|
|
|
|
|
{
|
|
|
|
|
PlotPixPoint(raster, x, y, style);
|
|
|
|
|
if (d < 0)
|
|
|
|
|
d += incr1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d += incr2;
|
|
|
|
|
y += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = 2*dx - dy;
|
|
|
|
|
incr1 = 2*dx;
|
|
|
|
|
incr2 = 2*(dx - dy);
|
|
|
|
|
done = dst->p_y;
|
|
|
|
|
for ( ; y != done ; y += 1)
|
|
|
|
|
{
|
|
|
|
|
PlotPixPoint(raster, x, y, style);
|
|
|
|
|
if (d < 0)
|
|
|
|
|
d += incr1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d += incr2;
|
|
|
|
|
x += xinc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PlotPixPoint(raster, x, y, style);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotPixLine --
|
|
|
|
|
*
|
|
|
|
|
* This procedure plots a line of a given thickness.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The current raster is modified.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotPixLine(area, widen, style)
|
|
|
|
|
Rect *area; /* The "corner" points of this rectangle
|
|
|
|
|
* give the endpoints of the line, in
|
|
|
|
|
* Magic root coordinates.
|
|
|
|
|
*/
|
|
|
|
|
int widen; /* Amount by which to widen line. 0 means
|
|
|
|
|
* line is drawn one pixel wide, 1 means 3
|
|
|
|
|
* pixels wide, etc.
|
|
|
|
|
*/
|
|
|
|
|
int style; /* style in which to render the line */
|
|
|
|
|
{
|
|
|
|
|
Rect swathArea;
|
|
|
|
|
|
|
|
|
|
plotTransToSwath(area, &swathArea);
|
|
|
|
|
|
|
|
|
|
/* Handle Manhattan lines using rectangle-drawing, since it's faster. */
|
|
|
|
|
|
|
|
|
|
if ((swathArea.r_xbot == swathArea.r_xtop) ||
|
|
|
|
|
(swathArea.r_ybot == swathArea.r_ytop))
|
|
|
|
|
{
|
|
|
|
|
GEO_EXPAND(&swathArea, widen, &swathArea);
|
|
|
|
|
GEOCLIP(&swathArea, &swathClip);
|
|
|
|
|
if ((swathArea.r_xbot <= swathArea.r_xtop) &&
|
|
|
|
|
(swathArea.r_ybot <= swathArea.r_ytop))
|
|
|
|
|
plotFillPixRaster(pixRasterSwath, &swathArea,style, GR_STSOLID);
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-05-23 23:13:14 +02:00
|
|
|
PlotPixFatLine(pixRasterSwath,
|
|
|
|
|
&swathArea.r_ll, &swathArea.r_ur,
|
2017-04-25 14:41:48 +02:00
|
|
|
widen, curStyle);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotPixFatLine --
|
|
|
|
|
*
|
|
|
|
|
* Draws a line many pixels wide between two points.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A line is drawn between pixels src and dst. Only the portion
|
|
|
|
|
* of the line that lies inside the raster is drawn; the endpoints
|
|
|
|
|
* may lie outside the raster (this feature is necessary to draw
|
|
|
|
|
* straight lines that cross multiple swaths). The line is drawn
|
|
|
|
|
* several pixels wide, as determined by the "widen" parameter.
|
|
|
|
|
* The ends of the line are square, not rounded, which may cause
|
|
|
|
|
* upleasant effects for some uses. If the line is Manhattan,
|
|
|
|
|
* this procedure is very inefficient: it's better to use the
|
|
|
|
|
* PlotFillPixRaster procedure.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixFatLine(raster, src, dst, widen, style)
|
|
|
|
|
PixRaster *raster; /* Where to render the line. */
|
|
|
|
|
Point *src; /* One endpoint of line, in raster coords. */
|
|
|
|
|
Point *dst; /* The other endpoint, in raster coords. */
|
|
|
|
|
int widen; /* How much to widen the line. 0 means the
|
|
|
|
|
* line is one pixel wide, 1 means it's 3
|
|
|
|
|
* pixels wide, and so on.
|
|
|
|
|
*/
|
|
|
|
|
int style;
|
|
|
|
|
{
|
|
|
|
|
double dx, dy, x, y;
|
|
|
|
|
int nLines;
|
|
|
|
|
|
|
|
|
|
/* Just draw (2*widen) + 1 lines spaced about one pixel apart.
|
|
|
|
|
* The first lines here compute how far apart to space the lines.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nLines = (2*widen) + 1;
|
|
|
|
|
x = dst->p_x - src->p_x;
|
|
|
|
|
y = dst->p_y - src->p_y;
|
|
|
|
|
dy = sqrt(x*x + y*y);
|
|
|
|
|
dx = y/dy;
|
|
|
|
|
dy = -x/dy;
|
|
|
|
|
x = -dy*(widen);
|
|
|
|
|
y = dx*(widen);
|
|
|
|
|
|
|
|
|
|
for (x = -dx*widen, y = -dy*widen;
|
|
|
|
|
nLines > 0;
|
|
|
|
|
nLines -= 1, x += dx, y += dy)
|
|
|
|
|
{
|
|
|
|
|
Point newSrc, newDst;
|
|
|
|
|
|
|
|
|
|
if (x > 0)
|
|
|
|
|
newSrc.p_x = (x + .5);
|
|
|
|
|
else newSrc.p_x = (x - .5);
|
|
|
|
|
if (y > 0)
|
|
|
|
|
newSrc.p_y = (y + .5);
|
|
|
|
|
else newSrc.p_y = (y - .5);
|
|
|
|
|
newDst.p_x = dst->p_x + newSrc.p_x;
|
|
|
|
|
newDst.p_y = dst->p_y + newSrc.p_y;
|
|
|
|
|
newSrc.p_x += src->p_x;
|
|
|
|
|
newSrc.p_y += src->p_y;
|
|
|
|
|
|
|
|
|
|
PlotPixArbLine(raster, &newSrc, &newDst, style);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotPixRect --
|
|
|
|
|
*
|
|
|
|
|
* This procedure takes a rectangular area, given in Magic root
|
|
|
|
|
* coordinates, and draws it as an outline of a given thickness.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies raster.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotPixRect(area, widen, style)
|
|
|
|
|
Rect *area; /* Rectangular area to draw, in root
|
|
|
|
|
* coordinates.
|
|
|
|
|
*/
|
|
|
|
|
int widen; /* If zero, rectangular outline is drawn
|
|
|
|
|
* one pixel wide. If non-zero, the outline
|
|
|
|
|
* is widened by this many units on each
|
|
|
|
|
* side.
|
|
|
|
|
*/
|
|
|
|
|
int style; /* style in which to render the rect */
|
|
|
|
|
{
|
|
|
|
|
Rect side;
|
|
|
|
|
|
|
|
|
|
/* First, the bottom side. */
|
|
|
|
|
|
|
|
|
|
if (area->r_xbot != area->r_xtop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_ytop = side.r_ybot;
|
|
|
|
|
plotPixLine(&side, widen,style);
|
|
|
|
|
|
|
|
|
|
/* Now the top side, if it doesn't coincide with the bottom. */
|
|
|
|
|
|
|
|
|
|
if (area->r_ybot != area->r_ytop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_ybot = side.r_ytop;
|
|
|
|
|
plotPixLine(&side, widen, style);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now do the left side. */
|
|
|
|
|
|
|
|
|
|
if (area->r_ybot != area->r_ytop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_xtop = side.r_xbot;
|
|
|
|
|
plotPixLine(&side, widen, style);
|
|
|
|
|
|
|
|
|
|
/* Now the right side, if it doesn't coincide with the left. */
|
|
|
|
|
|
|
|
|
|
if (area->r_xbot != area->r_xtop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_xbot = side.r_xtop;
|
|
|
|
|
plotPixLine(&side, widen, style);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotPixTile --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called for paint tiles. It renders each tile
|
|
|
|
|
* in the current style, in the current swath.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the raster area.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plotPixTile(tile, cxp)
|
|
|
|
|
Tile *tile; /* Tile that's of type to be output. */
|
|
|
|
|
TreeContext *cxp; /* Describes search in progress. */
|
|
|
|
|
{
|
|
|
|
|
Rect tileArea, rootArea, swathArea;
|
|
|
|
|
Transform *trans = &cxp->tc_scx->scx_trans;
|
|
|
|
|
|
|
|
|
|
/* Transform tile coords to root coords and then to swath coords. */
|
|
|
|
|
|
|
|
|
|
TITORECT(tile, &tileArea);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
TxPrintf("PlotPixTile: (%d,%d)(%d,%d) ",
|
|
|
|
|
tileArea.r_xbot,
|
|
|
|
|
tileArea.r_ybot,
|
|
|
|
|
tileArea.r_xtop,
|
|
|
|
|
tileArea.r_ytop);
|
|
|
|
|
#endif
|
|
|
|
|
GEOTRANSRECT(trans, &tileArea, &rootArea);
|
|
|
|
|
plotTransToSwath(&rootArea, &swathArea);
|
|
|
|
|
|
|
|
|
|
/* Clip and then fill with the color. */
|
|
|
|
|
|
|
|
|
|
GEOCLIP(&swathArea, &swathClip);
|
|
|
|
|
if (swathArea.r_xbot > swathArea.r_xtop) return 0;
|
|
|
|
|
if (swathArea.r_ybot > swathArea.r_ytop) return 0;
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
TxPrintf(">> (%d,%d)(%d,%d)\n",
|
|
|
|
|
swathArea.r_xbot,
|
|
|
|
|
swathArea.r_ybot,
|
|
|
|
|
swathArea.r_xtop,
|
|
|
|
|
swathArea.r_ytop);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* if the current style's fill-mode is GR_STOUTLINE or GR_STCROSS
|
|
|
|
|
* we cannot let plotFillPixRaster render the tile, since we get
|
2020-05-23 23:13:14 +02:00
|
|
|
* extra horizontal lines at swath boundaries. Too bad, it was a
|
|
|
|
|
* neat idea, but we cannot force the user to render the entire
|
2017-04-25 14:41:48 +02:00
|
|
|
* image at once (*sigh*)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if((GrStyleTable[curStyle].fill == GR_STOUTLINE) ||
|
2020-05-23 23:13:14 +02:00
|
|
|
(GrStyleTable[curStyle].fill == GR_STCROSS))
|
2017-04-25 14:41:48 +02:00
|
|
|
{ /* draw the outline */
|
|
|
|
|
plotPixRect(&tileArea, 1, curStyle);
|
|
|
|
|
}
|
|
|
|
|
if (GrStyleTable[curStyle].fill == GR_STCROSS)
|
|
|
|
|
{ /* draw the cross */
|
|
|
|
|
Point src, dst;
|
|
|
|
|
|
|
|
|
|
src = swathArea.r_ll;
|
|
|
|
|
dst = swathArea.r_ur;
|
|
|
|
|
PlotPixFatLine(pixRasterSwath, &src, &dst, 1, curStyle);
|
|
|
|
|
src.p_y = swathArea.r_ytop;
|
|
|
|
|
dst.p_y = swathArea.r_ybot;
|
|
|
|
|
PlotPixFatLine(pixRasterSwath, &src, &dst, 1, curStyle);
|
|
|
|
|
}
|
|
|
|
|
plotFillPixRaster(pixRasterSwath, &swathArea, curStyle, -1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotPixLabel --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked for labels. It generates bits to
|
|
|
|
|
* display the label in the current raster swath.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search from aborting.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the raster.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plotPixLabel(scx, label)
|
|
|
|
|
SearchContext *scx; /* Describes state of search when label
|
|
|
|
|
* was found.
|
|
|
|
|
*/
|
|
|
|
|
Label *label; /* Label that was found. */
|
|
|
|
|
{
|
|
|
|
|
Rect rootArea, swathArea, labelSize;
|
|
|
|
|
Point point;
|
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
|
|
/* Translate the label's area and relative position to root
|
|
|
|
|
* coordinates and then to swath coordinates. Figure out
|
|
|
|
|
* the point relative to which the label is to be positioned.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
|
|
|
|
|
plotTransToSwath(&rootArea, &swathArea);
|
|
|
|
|
pos = GeoTransPos(&scx->scx_trans, label->lab_just);
|
|
|
|
|
PlotTextSize(labelPixFont, label->lab_text, &labelSize);
|
|
|
|
|
|
|
|
|
|
switch (pos)
|
|
|
|
|
{
|
|
|
|
|
case GEO_NORTH:
|
|
|
|
|
case GEO_NORTHEAST:
|
|
|
|
|
case GEO_NORTHWEST:
|
|
|
|
|
point.p_y = swathArea.r_ytop + crossSize + 2 - labelSize.r_ybot;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GEO_CENTER:
|
|
|
|
|
case GEO_WEST:
|
|
|
|
|
case GEO_EAST:
|
|
|
|
|
point.p_y = (swathArea.r_ytop + swathArea.r_ybot)/2;
|
|
|
|
|
point.p_y -= (labelSize.r_ytop + labelSize.r_ybot)/2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GEO_SOUTH:
|
|
|
|
|
case GEO_SOUTHEAST:
|
|
|
|
|
case GEO_SOUTHWEST:
|
|
|
|
|
point.p_y = swathArea.r_ybot - crossSize - 2 - labelSize.r_ytop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
switch (pos)
|
|
|
|
|
{
|
|
|
|
|
case GEO_WEST:
|
|
|
|
|
case GEO_NORTHWEST:
|
|
|
|
|
case GEO_SOUTHWEST:
|
|
|
|
|
point.p_x = swathArea.r_xbot - crossSize - 2 - labelSize.r_xtop;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GEO_CENTER:
|
|
|
|
|
case GEO_NORTH:
|
|
|
|
|
case GEO_SOUTH:
|
|
|
|
|
point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
|
|
|
|
|
point.p_x -= (labelSize.r_xtop + labelSize.r_xbot)/2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GEO_EAST:
|
|
|
|
|
case GEO_NORTHEAST:
|
|
|
|
|
case GEO_SOUTHEAST:
|
|
|
|
|
point.p_x = swathArea.r_xtop + crossSize + 2 - labelSize.r_xbot;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output lines marking the label's area. Different things are
|
|
|
|
|
* done depending on whether the label is a point, a line, or an
|
|
|
|
|
* area.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((rootArea.r_xbot == rootArea.r_xtop) &&
|
|
|
|
|
(rootArea.r_ybot == rootArea.r_ytop))
|
|
|
|
|
{
|
|
|
|
|
Rect tmp;
|
|
|
|
|
|
|
|
|
|
/* Point label. Output a cross. */
|
|
|
|
|
|
|
|
|
|
tmp = swathArea;
|
|
|
|
|
tmp.r_ytop += crossSize;
|
|
|
|
|
tmp.r_ybot -= crossSize;
|
|
|
|
|
GEO_EXPAND(&tmp, 1, &tmp);
|
|
|
|
|
GEOCLIP(&tmp, &swathClip);
|
|
|
|
|
if ((tmp.r_xbot <= tmp.r_xtop) &&
|
|
|
|
|
(tmp.r_ybot <= tmp.r_ytop))
|
|
|
|
|
plotFillPixRaster(pixRasterSwath, &tmp, STYLE_LABEL, GR_STSOLID);
|
|
|
|
|
tmp = swathArea;
|
|
|
|
|
tmp.r_xtop += crossSize;
|
|
|
|
|
tmp.r_xbot -= crossSize;
|
|
|
|
|
GEO_EXPAND(&tmp, 1, &tmp);
|
|
|
|
|
GEOCLIP(&tmp, &swathClip);
|
|
|
|
|
if ((tmp.r_xbot <= tmp.r_xtop) &&
|
|
|
|
|
(tmp.r_ybot <= tmp.r_ytop))
|
|
|
|
|
plotFillPixRaster(pixRasterSwath, &tmp,STYLE_LABEL, GR_STSOLID);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Line or rectangle. Draw outline.
|
|
|
|
|
* plotFillPixRaster will outline the area if STYLE_LABEL has
|
|
|
|
|
* fill mode GR_STOUTLINE.
|
|
|
|
|
* Cute, berry, but it loses when the rect crosses a swath boundary.
|
|
|
|
|
*/
|
|
|
|
|
GEOCLIP(&swathArea, &swathClip);
|
|
|
|
|
plotPixRect(&rootArea, 1, STYLE_LABEL);
|
|
|
|
|
/* plotFillPixRaster(pixRasterSwath, &swathArea, STYLE_LABEL, -1); */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output the text for the label. */
|
|
|
|
|
|
|
|
|
|
labelSize.r_xbot += point.p_x - 1;
|
|
|
|
|
labelSize.r_xtop += point.p_x + 1;
|
|
|
|
|
labelSize.r_ybot += point.p_y - 1;
|
|
|
|
|
labelSize.r_ytop += point.p_y + 1;
|
2020-05-23 23:13:14 +02:00
|
|
|
PlotPixRasterText(pixRasterSwath, &swathClip,
|
2017-04-25 14:41:48 +02:00
|
|
|
labelPixFont, label->lab_text, &point, STYLE_LABEL);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotPixCell --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked for unexpanded cells.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search from aborting.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The raster is modified to depict the cell's boundary,
|
|
|
|
|
* name, and instance id.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plotPixCell(scx)
|
|
|
|
|
SearchContext *scx; /* Describes cell whose bbox is to
|
|
|
|
|
* be plotted.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
char idName[100];
|
|
|
|
|
Rect rootArea, swathArea, textSize;
|
|
|
|
|
Point point;
|
|
|
|
|
CellDef *def;
|
|
|
|
|
|
|
|
|
|
/* Convert the cell's bounding box to root coordinates and then
|
|
|
|
|
* draw the outline.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
def = scx->scx_use->cu_def;
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea);
|
|
|
|
|
plotPixRect(&rootArea, 1, STYLE_BLACK);
|
|
|
|
|
|
|
|
|
|
if (!PlotShowCellNames)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
/* Output the cell's name and id text. */
|
|
|
|
|
plotTransToSwath(&rootArea, &swathArea);
|
|
|
|
|
PlotTextSize(cellNamePixFont, def->cd_name, &textSize);
|
|
|
|
|
point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
|
|
|
|
|
point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2;
|
|
|
|
|
point.p_y = (2*swathArea.r_ytop + swathArea.r_ybot)/3;
|
|
|
|
|
point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2;
|
2020-05-23 23:13:14 +02:00
|
|
|
PlotPixRasterText(pixRasterSwath, &swathClip,
|
2017-04-25 14:41:48 +02:00
|
|
|
cellNamePixFont, def->cd_name, &point, STYLE_BBOX);
|
|
|
|
|
|
|
|
|
|
(void) DBPrintUseId(scx, idName, 100, TRUE);
|
|
|
|
|
PlotTextSize(cellIdPixFont, idName, &textSize);
|
|
|
|
|
point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
|
|
|
|
|
point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2;
|
|
|
|
|
point.p_y = (swathArea.r_ytop + 2*swathArea.r_ybot)/3;
|
|
|
|
|
point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2;
|
2020-05-23 23:13:14 +02:00
|
|
|
PlotPixRasterText(pixRasterSwath, &swathClip,
|
2017-04-25 14:41:48 +02:00
|
|
|
cellIdPixFont, idName, &point, STYLE_BBOX);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Plotpixels --
|
|
|
|
|
*
|
|
|
|
|
* This procedure generates a pix file usable by various programs
|
|
|
|
|
* that produce images on Dicomed cameras and so on.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Lots and lots of disk space is chewed up by the file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixels(scx, layers, xMask, width)
|
|
|
|
|
SearchContext *scx; /* The use and area and transformation
|
|
|
|
|
* in this describe what to plot.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *layers; /* Tells what layers to plot. Only
|
|
|
|
|
* paint layers in this mask, and also
|
|
|
|
|
* expanded according to xMask, are
|
|
|
|
|
* plotted. If L_LABELS is set, then
|
|
|
|
|
* labels on the layers are also
|
|
|
|
|
* plotted, if expanded according to
|
|
|
|
|
* xMask. If L_CELL is set, then
|
|
|
|
|
* subcells that are unexpanded
|
|
|
|
|
* according to xMask are plotted as
|
|
|
|
|
* bounding boxes.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* An expansion mask, used to indicate
|
|
|
|
|
* the window whose expansion status
|
|
|
|
|
* will be used to determine
|
|
|
|
|
* visibility. Zero means treat
|
|
|
|
|
* everything as expanded.
|
|
|
|
|
*/
|
|
|
|
|
int width; /* How many pixels across the plot
|
|
|
|
|
* should be.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
static char *yesNo[] = {"no", "yes", NULL};
|
|
|
|
|
int dotsAcross, dotsDown, swathsDown, scaleDown;
|
|
|
|
|
char fileName[200], answer[32];
|
|
|
|
|
float mBytes;
|
|
|
|
|
Transform tinv;
|
|
|
|
|
int action, result;
|
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* check to make sure that the swath height is a multiple of 8 so that stipples
|
|
|
|
|
* will look correct across swath boundaries.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (PlotPixHeight & 007) {
|
|
|
|
|
TxPrintf("Warning: plot parameter \"pixheight\" is not a multiple of 8. It\n");
|
|
|
|
|
TxPrintf("will be rounded from %d to %d.\n", PlotPixHeight, (PlotPixHeight&(~007))+8);
|
|
|
|
|
PlotPixHeight = (PlotPixHeight&(~007))+8;
|
|
|
|
|
}
|
|
|
|
|
/* did the user specify an explicit width? */
|
|
|
|
|
if (width != 0)
|
|
|
|
|
PlotPixWidth = width;
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootClip);
|
|
|
|
|
GEO_EXPAND(&rootClip, 1, &rootClip);
|
|
|
|
|
dotsAcross = width;
|
|
|
|
|
if (dotsAcross <= 0)
|
|
|
|
|
dotsAcross = PlotPixWidth;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Compute the number of pixels per magic unit.
|
|
|
|
|
* This number will be the fraction: scale / (1 << scaleShift).
|
|
|
|
|
* In order to be reasonably sure that we have enough precision
|
|
|
|
|
* in the numerator of the fraction, require that scale have at
|
|
|
|
|
* least three bits (i.e., be greater than or equal to 4).
|
|
|
|
|
*/
|
|
|
|
|
for (scale = 0, scaleShift = 4; ; scaleShift++)
|
|
|
|
|
{
|
|
|
|
|
scaleDown = 1 << scaleShift;
|
|
|
|
|
scale = (scaleDown * dotsAcross) / (rootClip.r_xtop - rootClip.r_xbot);
|
|
|
|
|
if (scaleShift >= 8 * sizeof (int))
|
|
|
|
|
{
|
|
|
|
|
TxError("The area selected is too many lambda wide to plot.\n");
|
|
|
|
|
TxError("(There are numerical problems with rasterizing it).\n");
|
|
|
|
|
TxError("Try selecting a smaller area, or else asking for ");
|
|
|
|
|
TxError("a wider plot.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (scale >= 4)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Compute scaling information, and tell the user how big the
|
|
|
|
|
* plot will be.
|
|
|
|
|
*/
|
|
|
|
|
dotsDown = ((rootClip.r_ytop - rootClip.r_ybot)*scale) >> scaleShift;
|
|
|
|
|
swathsDown = (dotsDown + PlotPixHeight - 1)/PlotPixHeight;
|
|
|
|
|
dotsDown = swathsDown * PlotPixHeight;
|
|
|
|
|
mBytes = (double)(PlotPixWidth*dotsDown)*3.0/1000000.0;
|
|
|
|
|
TxPrintf("Plot will take %.2f Megabytes in \"%s\".\n",
|
|
|
|
|
mBytes, PlotTempDirectory);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Do you still want the plot? [yes] ");
|
|
|
|
|
if (TxGetLine(answer, sizeof answer) == NULL || answer[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
action = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while ((action = Lookup(answer, yesNo)) < 0);
|
|
|
|
|
if (action == 0) return;
|
|
|
|
|
|
|
|
|
|
/* The plot has been "approved". Now obtain swath rasters if
|
|
|
|
|
* we don't already have them. If the swath size has changed,
|
|
|
|
|
* recycle the rasters for new ones.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (pixRasterSwath == NULL)
|
|
|
|
|
pixRasterSwath = PlotNewPixRaster(PlotPixHeight, PlotPixWidth);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((pixRasterSwath->pix_width != PlotPixWidth)
|
|
|
|
|
|| (pixRasterSwath->pix_height != PlotPixHeight))
|
|
|
|
|
{
|
|
|
|
|
PlotFreePixRaster(pixRasterSwath);
|
|
|
|
|
pixRasterSwath = PlotNewPixRaster(PlotPixHeight, PlotPixWidth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Load font information for the plot, if it isn't already
|
|
|
|
|
* loaded. We use the "versatec" fonts for convenience.
|
|
|
|
|
*/
|
|
|
|
|
labelPixFont = PlotLoadFont(PlotVersLabelFont);
|
|
|
|
|
cellNamePixFont = PlotLoadFont(PlotVersNameFont);
|
|
|
|
|
cellIdPixFont = PlotLoadFont(PlotVersIdFont);
|
|
|
|
|
if ((labelPixFont == NULL) ||
|
|
|
|
|
(cellNamePixFont == NULL) ||
|
|
|
|
|
(cellIdPixFont == NULL))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("PlotPixels: can't load fonts\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute the name of the file to use for output, and open it. */
|
|
|
|
|
|
|
|
|
|
sprintf(fileName, "%s/magicPlot-%d-%d-XXXXXX", PlotTempDirectory,
|
|
|
|
|
PlotPixWidth, PlotPixHeight*swathsDown);
|
|
|
|
|
result = mkstemp(fileName);
|
|
|
|
|
if (result == -1)
|
|
|
|
|
{
|
|
|
|
|
TxError("Couldn't create temporary filename for %s\n", fileName);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
file = PaOpen(fileName, "w", (char *) NULL, (char *) NULL, (char *) NULL,
|
|
|
|
|
(char **) NULL);
|
|
|
|
|
if (file == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Couldn't open file \"%s\" to write plot.\n", fileName);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set up the rest of the transformation variables.
|
|
|
|
|
* Arrange for the plot to be centered on the page.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
plotLL.p_y = rootClip.r_ybot;
|
|
|
|
|
plotLL.p_x = (rootClip.r_xtop+rootClip.r_xbot)/2 - (PlotPixWidth*8)/scale;
|
|
|
|
|
if (plotLL.p_x > rootClip.r_xbot)
|
|
|
|
|
plotLL.p_x = rootClip.r_xbot;
|
|
|
|
|
|
|
|
|
|
/* Compute a distance equal to 1/8th the size of a typical wire
|
|
|
|
|
* (max of thicknesses of routing layers). This is used to offset
|
|
|
|
|
* text from labels and to compute cross size for point labels.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (RtrMetalWidth > RtrPolyWidth)
|
|
|
|
|
crossSize = (RtrMetalWidth*scale)/(scaleDown*8);
|
|
|
|
|
else crossSize = (RtrPolyWidth*scale)/(scaleDown*8);
|
|
|
|
|
if (crossSize < 2) crossSize = 2;
|
|
|
|
|
|
|
|
|
|
/* Step down the page one swath at a time, rasterizing everything
|
|
|
|
|
* that overlaps the current swath, then outputting the swath.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
GeoInvertTrans(&scx->scx_trans, &tinv);
|
|
|
|
|
for (swathsDown -= 1; swathsDown >= 0; swathsDown -= 1)
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx2;
|
|
|
|
|
Rect root, labelArea;
|
|
|
|
|
int labelHeight;
|
|
|
|
|
|
|
|
|
|
swathY = swathsDown * PlotPixHeight;
|
|
|
|
|
PlotClearPixRaster(pixRasterSwath, (Rect *) NULL);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Compute the area of the swath that overlaps the portion of
|
|
|
|
|
* the layout we're plotting.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
plotTransToSwath(&rootClip, &swathClip);
|
|
|
|
|
if (swathClip.r_xbot < 0) swathClip.r_xbot = 0;
|
|
|
|
|
if (swathClip.r_ybot < 0) swathClip.r_ybot = 0;
|
|
|
|
|
if (swathClip.r_xtop >= PlotPixWidth)
|
|
|
|
|
swathClip.r_xtop = PlotPixWidth - 1;
|
|
|
|
|
if (swathClip.r_ytop >= PlotPixHeight)
|
|
|
|
|
swathClip.r_ytop = PlotPixHeight - 1;
|
|
|
|
|
|
|
|
|
|
/* Compute the area of layout that overlaps this swath. This is
|
|
|
|
|
* done twice, once for mask material and once for labels. The
|
|
|
|
|
* separate computation for labels is because labels stick out
|
|
|
|
|
* from their positioning points. We may have to search a larger
|
|
|
|
|
* area than just the swath in order to find all the labels that
|
|
|
|
|
* must be drawn in this swath. Only the y-direction needs to
|
|
|
|
|
* be expanded this way, since we're only swathing in y. Even
|
|
|
|
|
* non-label stuff has to be expanded slightly, because lines
|
|
|
|
|
* are drawn more than 1 pixel thick.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
scx2 = *scx;
|
|
|
|
|
root.r_xbot = (scaleDown*swathClip.r_xbot)/scale + plotLL.p_x;
|
|
|
|
|
root.r_xtop = (scaleDown*swathClip.r_xtop)/scale + plotLL.p_x;
|
|
|
|
|
root.r_ybot = (scaleDown*(swathY-4))/scale + plotLL.p_y;
|
|
|
|
|
root.r_ytop = (scaleDown*(swathY+swathClip.r_ytop+4))/scale+plotLL.p_y;
|
|
|
|
|
GEO_EXPAND(&root, 1, &root);
|
|
|
|
|
GeoTransRect(&tinv, &root, &scx2.scx_area);
|
|
|
|
|
|
|
|
|
|
labelArea.r_xbot = root.r_xbot;
|
|
|
|
|
labelArea.r_xtop = root.r_xtop;
|
|
|
|
|
labelHeight =
|
|
|
|
|
(labelPixFont->fo_bbox.r_ytop - labelPixFont->fo_bbox.r_ybot) + 2;
|
|
|
|
|
labelArea.r_ybot =
|
|
|
|
|
(scaleDown*(swathY-crossSize-labelHeight))/scale
|
|
|
|
|
+ plotLL.p_y;
|
|
|
|
|
labelArea.r_ytop =
|
|
|
|
|
(scaleDown*(swathY+swathClip.r_ytop+crossSize+labelHeight))/scale
|
|
|
|
|
+ plotLL.p_y;
|
|
|
|
|
GEO_EXPAND(&labelArea, 1, &labelArea);
|
|
|
|
|
|
|
|
|
|
/* For each style, output areas for all the tiles
|
|
|
|
|
* requested by the style.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (curStyle = 0; curStyle < DBWNumStyles; curStyle++)
|
|
|
|
|
{
|
|
|
|
|
/* visit all the tiles in this swath */
|
|
|
|
|
curMask = DBWStyleToTypes(curStyle);
|
|
|
|
|
(void) DBTreeSrTiles(&scx2, curMask, xMask, plotPixTile,
|
|
|
|
|
(ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output labels, if they are wanted. */
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(layers, L_LABEL))
|
|
|
|
|
{
|
|
|
|
|
curMask = layers;
|
|
|
|
|
TTMaskSetType(curMask, TT_SPACE);
|
|
|
|
|
GeoTransRect(&tinv, &labelArea, &scx2.scx_area);
|
|
|
|
|
(void)DBTreeSrLabels(&scx2, curMask, xMask, (TerminalPath *) NULL,
|
|
|
|
|
TF_LABEL_ATTACH, plotPixLabel, (ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output subcell bounding boxes, if they are wanted. */
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(layers, L_CELL))
|
|
|
|
|
{
|
|
|
|
|
(void) DBTreeSrCells(&scx2, xMask, plotPixCell, (ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("#");
|
|
|
|
|
TxFlush();
|
|
|
|
|
|
|
|
|
|
if (PlotDumpPixRaster(pixRasterSwath,file)!= 0)
|
|
|
|
|
goto error;
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close the file and tell the user where it is */
|
|
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
|
TxPrintf("\nPlot complete. pix file is \"%s\"\n", fileName);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
TxError("\npixel plot aborted.\n");
|
|
|
|
|
fclose(file);
|
|
|
|
|
unlink(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotNewPixRaster --
|
|
|
|
|
*
|
|
|
|
|
* Allocate and initialize a new raster structure.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is a pointer to the new PixRaster object.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Memory is allocated.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
PixRaster *
|
|
|
|
|
PlotNewPixRaster(height, width)
|
|
|
|
|
int height; /* PixRaster's height in pixels.*/
|
|
|
|
|
int width; /* PixRaster's width in pixels.*/
|
|
|
|
|
{
|
|
|
|
|
PixRaster *new;
|
|
|
|
|
|
|
|
|
|
new = (PixRaster *) mallocMagic(sizeof(PixRaster));
|
|
|
|
|
new->pix_width = width;
|
|
|
|
|
new->pix_height = height;
|
|
|
|
|
new->pix_pixels = (char *) mallocMagic((unsigned) (height * width));
|
|
|
|
|
return new;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotFreePixRaster --
|
|
|
|
|
*
|
|
|
|
|
* Frees up the memory associated with an existing PixRaster structure.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The storage associated with PixRaster is returned to the allocator.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotFreePixRaster(pr)
|
|
|
|
|
PixRaster *pr; /* PixRaster whose memory is to be freed.
|
|
|
|
|
* Should have been created with
|
|
|
|
|
* PlotNewPixRaster.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) pr->pix_pixels);
|
|
|
|
|
freeMagic((char *) pr);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotClearPixRaster --
|
|
|
|
|
*
|
|
|
|
|
* This procedure clears out an area of the PixRaster.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The area of the PixRaster indicated by "area" is set to all zeroes.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotClearPixRaster(pr, area)
|
|
|
|
|
PixRaster *pr; /* PixRaster that's to be cleared. */
|
|
|
|
|
Rect *area; /* Area to be cleared, in PixRaster
|
|
|
|
|
* coords. NULL means clear the
|
|
|
|
|
* whole PixRaster.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
char *left, *right, *cur;
|
|
|
|
|
int line;
|
|
|
|
|
|
|
|
|
|
if (area == NULL)
|
|
|
|
|
{
|
|
|
|
|
bzero((char *) pr->pix_pixels,
|
|
|
|
|
pr->pix_height*pr->pix_width);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute the address of the leftmost word in the topmost line
|
|
|
|
|
* to be cleared, and the rightmost word in the topmost line to
|
|
|
|
|
* be cleared.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
left = pr->pix_pixels +
|
|
|
|
|
((pr->pix_height-1) - area->r_ytop)* pr->pix_width;
|
|
|
|
|
right = left + area->r_xtop;
|
|
|
|
|
left += area->r_xbot;
|
|
|
|
|
|
|
|
|
|
/* Clear the area one PixRaster line at a time, top to bottom. */
|
|
|
|
|
|
|
|
|
|
for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
|
|
|
|
|
{
|
|
|
|
|
/* Clear the line. */
|
|
|
|
|
|
|
|
|
|
for (cur = left; cur <= right; cur += 1)
|
|
|
|
|
*cur = 0;
|
|
|
|
|
left += pr->pix_width;
|
|
|
|
|
right += pr->pix_width;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotFillPixRaster --
|
|
|
|
|
*
|
|
|
|
|
* Given a PixRaster and an area, this procedure renders the given area
|
2020-05-23 23:13:14 +02:00
|
|
|
* of the PixRaster with a particular stipple pattern or other
|
2017-04-25 14:41:48 +02:00
|
|
|
* appropriate style.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The current PixRaster is modified..
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotFillPixRaster(pr, area, style, fill)
|
|
|
|
|
PixRaster *pr; /* Pointer to PixRaster whose bits are
|
|
|
|
|
* to be filled in.
|
|
|
|
|
*/
|
|
|
|
|
Rect *area; /* Area to be filled in pixel coords.
|
|
|
|
|
* This is an inclusive area: it
|
|
|
|
|
* includes the boundary pixels. The
|
|
|
|
|
* caller must ensure that it is
|
|
|
|
|
* clipped to the PixRaster area.
|
|
|
|
|
*/
|
|
|
|
|
int style; /* index of style to be used */
|
|
|
|
|
int fill; /* if >0, override GrStyleTable fill mode */
|
|
|
|
|
{
|
|
|
|
|
char *left, *cur;
|
|
|
|
|
int line;
|
|
|
|
|
char *right;
|
|
|
|
|
int curStipple, curColor, curMask; /* local copies so we don't have to
|
2020-05-23 23:13:14 +02:00
|
|
|
* continually indirect through
|
2017-04-25 14:41:48 +02:00
|
|
|
* GrStyleTable
|
|
|
|
|
*/
|
|
|
|
|
Rect r; /* for passing to plotPixLine */
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
TxPrintf("plotFillPixRaster: raster buffer@0x%x : ", pr->pix_pixels);
|
|
|
|
|
TxPrintf(" (%d,%d)(%d,%d)\n",
|
|
|
|
|
area->r_xbot,
|
|
|
|
|
area->r_ybot,
|
|
|
|
|
area->r_xtop,
|
|
|
|
|
area->r_ytop);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Compute the address of the leftmost word in the topmost line
|
|
|
|
|
* to be filled, and the rightmost word in the topmost line to
|
|
|
|
|
* be filled.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* find beginning of first swath line that is affected */
|
|
|
|
|
|
|
|
|
|
left = pr->pix_pixels +
|
|
|
|
|
((pr->pix_height-1) - area->r_ytop)*pr->pix_width;
|
|
|
|
|
right = left + area->r_xtop; /* right edge */
|
|
|
|
|
left += area->r_xbot; /* left edge */
|
|
|
|
|
|
|
|
|
|
/* Process the area one PixRaster line at a time, top to bottom. */
|
|
|
|
|
curStipple = GrStyleTable[style].stipple;
|
|
|
|
|
curColor = GrStyleTable[style].color;
|
|
|
|
|
curMask = GrStyleTable[style].mask;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* now select the appropriate rendering style
|
|
|
|
|
* and render the area. If we were passed a non-negative fill argument,
|
2020-05-23 23:13:14 +02:00
|
|
|
* let it override the fill mode from GrStyleTable. Otherwise, use the
|
2017-04-25 14:41:48 +02:00
|
|
|
* mode from the table. This is so we can make solid areas in STYLE_LABEL,
|
|
|
|
|
* for example, instead of getting the arms of the crosses hollow.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if (fill < 0)
|
2017-04-25 14:41:48 +02:00
|
|
|
fill = GrStyleTable[style].fill;
|
|
|
|
|
|
|
|
|
|
switch (fill)
|
|
|
|
|
{
|
|
|
|
|
case GR_STSTIPPLE:
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
TxPrintf ("Stipple: %d %d %d %d %d %d %d %d \n",
|
|
|
|
|
GrStippleTable[curStipple][0],
|
|
|
|
|
GrStippleTable[curStipple][1],
|
|
|
|
|
GrStippleTable[curStipple][2],
|
|
|
|
|
GrStippleTable[curStipple][3],
|
|
|
|
|
GrStippleTable[curStipple][4],
|
|
|
|
|
GrStippleTable[curStipple][5],
|
|
|
|
|
GrStippleTable[curStipple][6],
|
|
|
|
|
GrStippleTable[curStipple][7]);
|
|
|
|
|
#endif
|
|
|
|
|
for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
|
|
|
|
|
{
|
|
|
|
|
for (cur = left; cur <= right; cur += 1)
|
|
|
|
|
|
|
|
|
|
/* select "line" of stipple pattern and AND it with the bitmask
|
|
|
|
|
* for the bit in the line
|
2020-05-23 23:13:14 +02:00
|
|
|
* x&07 == x % 8 and is faster
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if(GrStippleTable[curStipple][line&07] &
|
|
|
|
|
1<<(int)((7-(cur-pr->pix_pixels)%
|
|
|
|
|
pr->pix_width)&07))
|
|
|
|
|
*cur = (*cur & ~curMask) | (curColor & curMask);
|
|
|
|
|
|
|
|
|
|
left += pr->pix_width;
|
|
|
|
|
right += pr->pix_width;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GR_STGRID:
|
|
|
|
|
/* not implemented */
|
|
|
|
|
break;
|
|
|
|
|
/* cross and outline are handled at a higher level */
|
|
|
|
|
case GR_STCROSS:
|
|
|
|
|
/* can't do it here due to swath boundary problems. */
|
|
|
|
|
break;
|
|
|
|
|
case GR_STOUTLINE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GR_STSOLID:
|
|
|
|
|
default:
|
|
|
|
|
for (line = area->r_ytop; line >= area->r_ybot; line -= 1)
|
|
|
|
|
{
|
|
|
|
|
for (cur = left; cur <= right; cur += 1)
|
|
|
|
|
*cur = (*cur & ~curMask) | (curColor & curMask);
|
|
|
|
|
left += pr->pix_width;
|
|
|
|
|
right += pr->pix_width;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotDumpPixRaster --
|
|
|
|
|
*
|
|
|
|
|
* Writes out the contents of the given PixRaster to the given file,
|
|
|
|
|
* in binary format. Goes trhough color map table to get the values for
|
|
|
|
|
* each pixel.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 if all was well. Returns non-zero if there was
|
|
|
|
|
* an I/O error. In this event, this procedure prints an
|
|
|
|
|
* error message before returning.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Information is added to file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
PlotDumpPixRaster(pr, file)
|
|
|
|
|
PixRaster *pr; /* PixRaster to be dumped. */
|
|
|
|
|
FILE *file; /* File stream on which to dump it. */
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int r, g, b;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < (pr->pix_width) * (pr->pix_height); i++)
|
|
|
|
|
{
|
|
|
|
|
GrGetColor(pr->pix_pixels[i], &r, &g, &b);
|
|
|
|
|
if (putc(r, file) == EOF) /* red */
|
|
|
|
|
{
|
|
|
|
|
TxError("I/O error in writing PixRaster file: %s.\n",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (putc(g, file) == EOF) /* green */
|
|
|
|
|
{
|
|
|
|
|
TxError("I/O error in writing PixRaster file: %s.\n",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (putc(b, file) == EOF) /* blue */
|
|
|
|
|
{
|
|
|
|
|
TxError("I/O error in writing PixRaster file: %s.\n",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotPixRasterText --
|
|
|
|
|
*
|
|
|
|
|
* Given a text string and a font, this procedure scan-converts
|
|
|
|
|
* the string and writespixels in the current raster that correspond
|
|
|
|
|
* to on-bits in the text.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Bits are modified in the raster.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotPixRasterText(raster, clip, font, string, point, style)
|
|
|
|
|
PixRaster *raster; /* Raster whose bits are to be filled in. */
|
|
|
|
|
Rect *clip; /* Area to which to clip the text. Must be
|
|
|
|
|
* entirely within the area of the raster.
|
|
|
|
|
*/
|
|
|
|
|
RasterFont *font; /* Font to use for rasterizing string. Must
|
|
|
|
|
* have been obtained by calling PlotLoadFont.
|
|
|
|
|
*/
|
|
|
|
|
char *string; /* String of text to rasterize. */
|
|
|
|
|
Point *point; /* X-Y coordinates of origin of text. The
|
|
|
|
|
* origin need not be inside the area of
|
|
|
|
|
* the raster, but only raster points inside
|
|
|
|
|
* the area will be modified.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
int style; /* style for the text to be rendered in --
|
2017-04-25 14:41:48 +02:00
|
|
|
* used only for the correct color.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int xOrig; /* X-origin for current character. */
|
|
|
|
|
int color;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
color = GrStyleTable[style].color;
|
|
|
|
|
/* Outer loop: process each character. */
|
|
|
|
|
|
|
|
|
|
xOrig = point->p_x;
|
|
|
|
|
for (; *string != 0; string++)
|
|
|
|
|
{
|
|
|
|
|
int cBytesPerLine, i;
|
|
|
|
|
struct dispatch *d; /* Descriptor for current character. */
|
|
|
|
|
|
|
|
|
|
/* Handle spaces and tabs specially by just spacing over. */
|
|
|
|
|
|
|
|
|
|
if ((*string == ' ') || (*string == '\t'))
|
|
|
|
|
{
|
|
|
|
|
xOrig += font->fo_chars['t'].width;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Middle loop: render each character one raster line at a
|
|
|
|
|
* time, from top to bottom. Skip rows that are outside the
|
|
|
|
|
* area of the raster.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
d = &font->fo_chars[*string];
|
|
|
|
|
cBytesPerLine = (d->left + d->right + 7) >> 3;
|
|
|
|
|
for (i = 0; i < d->up + d->down; i++)
|
|
|
|
|
{
|
|
|
|
|
int y, j;
|
|
|
|
|
char *charBitPtr;
|
|
|
|
|
|
|
|
|
|
y = point->p_y + d->up - 1 - i;
|
|
|
|
|
if (y < clip->r_ybot) break;
|
|
|
|
|
if (y > clip->r_ytop) continue;
|
|
|
|
|
|
|
|
|
|
/* Inner loop: process a series of bytes in a row to
|
|
|
|
|
* render one raster line of one character. Be sure
|
|
|
|
|
* to skip areas that fall outside the raster to the
|
|
|
|
|
* left or right.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (j = -d->left,
|
|
|
|
|
charBitPtr = font->fo_bits + d->addr + i*cBytesPerLine;
|
|
|
|
|
j < d->right;
|
|
|
|
|
j += 8, charBitPtr++)
|
|
|
|
|
{
|
|
|
|
|
char *rPtr;
|
|
|
|
|
int charBits, x, k;
|
|
|
|
|
|
|
|
|
|
x = xOrig + j;
|
|
|
|
|
if (x > clip->r_xtop) break;
|
|
|
|
|
if (x < clip->r_xbot - 7) continue;
|
|
|
|
|
|
|
|
|
|
rPtr = (char *) raster->pix_pixels;
|
|
|
|
|
rPtr += (raster->pix_height - 1 - y)*raster->pix_width + x;
|
|
|
|
|
charBits = *charBitPtr & 0xff;
|
|
|
|
|
|
|
|
|
|
/* Inner inner loop: process the bytes worth of bits, setting
|
|
|
|
|
* pixels in the raster to the current color
|
|
|
|
|
*/
|
|
|
|
|
for(k=7;k>=0;k--)
|
|
|
|
|
{
|
|
|
|
|
if(charBits&(1<<k))
|
|
|
|
|
*rPtr |= color;
|
|
|
|
|
rPtr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xOrig += d->width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* LLNL */
|