2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* plotVers.c --
|
|
|
|
|
*
|
|
|
|
|
* This file contains the procedures that generate plots on
|
|
|
|
|
* Versatec-style black-and-white printers.
|
|
|
|
|
*
|
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/plotVers.c,v 1.3 2010/06/24 12:37:25 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2025-07-14 15:18:49 +02:00
|
|
|
#include <unistd.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#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 "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 "dbwind/dbwind.h"
|
|
|
|
|
#include "cif/cif.h" /* for CIFGetOutputScale() */
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "plot/plotInt.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
/* Library imports: */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
extern int rasFileByteCount;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Records of the following type are used to describe how to generate
|
|
|
|
|
* output for the mask layers. Each style describes a particular
|
|
|
|
|
* stipple pattern.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct versatecstyle
|
|
|
|
|
{
|
|
|
|
|
TileTypeBitMask vs_layers; /* Layers to plot in this style. */
|
|
|
|
|
Stipple vs_stipple; /* Stipple pattern to use. */
|
|
|
|
|
int vs_flags; /* Flag bits, see below. */
|
|
|
|
|
struct versatecstyle *vs_next; /* Pointer to next style in list. */
|
|
|
|
|
|
|
|
|
|
/* If the color flag is false, all stipples will be black */
|
|
|
|
|
VersatecColor vs_color; /* Stipple color */
|
|
|
|
|
} VersatecStyle;
|
|
|
|
|
|
|
|
|
|
/* Flag values for VersatecStyles:
|
|
|
|
|
*
|
|
|
|
|
* VS_CROSS - if this bit is set, then generate an outline with an
|
|
|
|
|
* X through the middle, like for contacts, instead of
|
|
|
|
|
* stippling. The stipple pattern is ignored in this
|
|
|
|
|
* case.
|
|
|
|
|
* VS_BORDER - if this bit is set, generate an outline with no X
|
|
|
|
|
* through the middle and no stipple. The stipple
|
|
|
|
|
* pattern is ignored in this case.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define VS_CROSS 1
|
|
|
|
|
#define VS_BORDER 2
|
|
|
|
|
|
|
|
|
|
static VersatecStyle *plotVersStyles;
|
|
|
|
|
static VersatecStyle *plotColorVersStyles;
|
|
|
|
|
|
|
|
|
|
char *plotVersatecColorNames[] = {
|
|
|
|
|
"Black",
|
|
|
|
|
"Cyan",
|
|
|
|
|
"Magenta",
|
|
|
|
|
"Yellow"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* The parameters below control various aspects of the plotting
|
|
|
|
|
* process. The initial values are defaults for the versatec
|
|
|
|
|
* printer. However, many of them can be modified by users
|
|
|
|
|
* with the "plot option" command.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Supported format. Default is "hprtl". */
|
|
|
|
|
|
|
|
|
|
unsigned char PlotVersPlotType = HPRTL;
|
|
|
|
|
|
|
|
|
|
int PlotVersWidth = 2400; /* Number of dots across Versatec page.
|
|
|
|
|
* Should be a multiple of 32.
|
|
|
|
|
*/
|
|
|
|
|
int PlotVersDotsPerInch = 300; /* Dots per inch. */
|
|
|
|
|
int PlotVersSwathHeight = 64; /* Width of swath to generate at one time,
|
|
|
|
|
* in dots.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Name of printer to use for output: */
|
|
|
|
|
|
|
|
|
|
static char *defaultPrinter = "versatec";
|
|
|
|
|
char *PlotVersPrinter = NULL;
|
|
|
|
|
|
|
|
|
|
/* Command to use to actually print rasterized file. Contains two %s'es,
|
|
|
|
|
* which are supplied with the printer name and the name of the raster file.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static char *defaultCommand = "lp -d %s %s";
|
|
|
|
|
char *PlotVersCommand = NULL;
|
|
|
|
|
|
|
|
|
|
/* Directory in which to create temporary file to hold raster: */
|
|
|
|
|
|
|
|
|
|
static char *defaultDirectory = "/tmp";
|
|
|
|
|
char *PlotTempDirectory = NULL;
|
|
|
|
|
|
|
|
|
|
/* Name of fonts to use: */
|
|
|
|
|
|
|
|
|
|
static char *defaultIdFont = "vfont.I.12";
|
|
|
|
|
char *PlotVersIdFont = NULL;
|
|
|
|
|
static char *defaultNameFont = "vfont.B.12";
|
|
|
|
|
char *PlotVersNameFont = NULL;
|
|
|
|
|
static char *defaultLabelFont = "vfont.R.8";
|
|
|
|
|
char *PlotVersLabelFont = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* The variables below are shared between the top-level Versatec
|
|
|
|
|
* 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).
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Point plotLL; /* Point in root Magic coords that corresponds
|
|
|
|
|
* to (0,0) in raster coordinates.
|
|
|
|
|
*/
|
|
|
|
|
int swathY; /* The y-coordinate in raster coordinates that
|
|
|
|
|
* corresponds to (0,0) in swath coords. It's
|
|
|
|
|
* always >= 0.
|
|
|
|
|
*/
|
|
|
|
|
static int scale; /* How many (2**scaleShift)-ths of a pixel
|
|
|
|
|
* correspond to one Magic unit.
|
|
|
|
|
*/
|
|
|
|
|
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 VersatecStyle *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 *labelFont; /* Font to use when rendering labels. */
|
|
|
|
|
static RasterFont *cellNameFont; /* Font to use when rendering cell names. */
|
|
|
|
|
static RasterFont *cellIdFont; /* Font to use when rendering cell ids. */
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotVersTechInit --
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotVersTechInit()
|
|
|
|
|
{
|
|
|
|
|
VersatecStyle *style;
|
|
|
|
|
|
|
|
|
|
for (style = plotVersStyles; style != NULL; style = style->vs_next)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) style);
|
|
|
|
|
}
|
|
|
|
|
plotVersStyles = NULL;
|
|
|
|
|
|
|
|
|
|
if (PlotVersPrinter == NULL)
|
|
|
|
|
StrDup(&PlotVersPrinter, defaultPrinter);
|
|
|
|
|
if (PlotVersCommand == NULL)
|
|
|
|
|
StrDup(&PlotVersCommand, defaultCommand);
|
|
|
|
|
if (PlotTempDirectory == NULL)
|
|
|
|
|
StrDup(&PlotTempDirectory, defaultDirectory);
|
|
|
|
|
if (PlotVersIdFont == NULL)
|
|
|
|
|
StrDup(&PlotVersIdFont, defaultIdFont);
|
|
|
|
|
if (PlotVersNameFont == NULL)
|
|
|
|
|
StrDup(&PlotVersNameFont, defaultNameFont);
|
|
|
|
|
if (PlotVersLabelFont == NULL)
|
|
|
|
|
StrDup(&PlotVersLabelFont, defaultLabelFont);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotVersTechInit()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotColorVersTechInit --
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotColorVersTechInit()
|
|
|
|
|
{
|
|
|
|
|
VersatecStyle *style;
|
|
|
|
|
|
|
|
|
|
for (style = plotColorVersStyles; style != NULL; style = style->vs_next)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) style);
|
|
|
|
|
}
|
|
|
|
|
plotColorVersStyles = NULL;
|
|
|
|
|
|
|
|
|
|
if (PlotVersPrinter == NULL)
|
|
|
|
|
StrDup(&PlotVersPrinter, defaultPrinter);
|
|
|
|
|
if (PlotVersCommand == NULL)
|
|
|
|
|
StrDup(&PlotVersCommand, defaultCommand);
|
|
|
|
|
if (PlotTempDirectory == NULL)
|
|
|
|
|
StrDup(&PlotTempDirectory, defaultDirectory);
|
|
|
|
|
if (PlotVersIdFont == NULL)
|
|
|
|
|
StrDup(&PlotVersIdFont, defaultIdFont);
|
|
|
|
|
if (PlotVersNameFont == NULL)
|
|
|
|
|
StrDup(&PlotVersNameFont, defaultNameFont);
|
|
|
|
|
if (PlotVersLabelFont == NULL)
|
|
|
|
|
StrDup(&PlotVersLabelFont, defaultLabelFont);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotColorVersTechInit()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotVersTechLine --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked by the technology module once for
|
|
|
|
|
* each line in the "versatec" 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 Versatec styles.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PlotVersTechLine(sectionName, argc, argv)
|
|
|
|
|
char *sectionName; /* Name of this section (unused). */
|
|
|
|
|
int argc; /* Number of arguments on line. */
|
|
|
|
|
char *argv[]; /* Pointers to fields of line. */
|
|
|
|
|
{
|
|
|
|
|
VersatecStyle *new;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
new = (VersatecStyle *) mallocMagic(sizeof(VersatecStyle));
|
|
|
|
|
|
|
|
|
|
DBTechNoisyNameMask(argv[0], &new->vs_layers);
|
|
|
|
|
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(argv[1], "X") == 0)
|
|
|
|
|
new->vs_flags = VS_CROSS;
|
|
|
|
|
else if (strcmp(argv[1], "B") == 0)
|
|
|
|
|
new->vs_flags = VS_BORDER;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("Second field must be \"X\" or \"B\"\n");
|
|
|
|
|
freeMagic((char *) new);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-01-06 17:12:11 +01:00
|
|
|
unsigned int value;
|
|
|
|
|
int i;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (argc != 17)
|
|
|
|
|
{
|
|
|
|
|
TechError("\"versatec\" lines must have either 2 or 17 fields.\n");
|
|
|
|
|
freeMagic((char *)new);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
new->vs_color = 0;
|
|
|
|
|
new->vs_flags = 0;
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
(void) sscanf(argv[i+1], "%x", &value);
|
|
|
|
|
new->vs_stipple[i] = (value<<16) | (value & 0xffff);
|
|
|
|
|
#ifndef WORDS_BIGENDIAN
|
|
|
|
|
new->vs_stipple[i] = PlotSwapBytes(new->vs_stipple[i]);
|
|
|
|
|
#endif /* WORDS_BIGENDIAN */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new->vs_next = plotVersStyles;
|
|
|
|
|
plotVersStyles = new;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PlotVersTechLine(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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* PlotColorVersTechLine --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked by the technology module once for
|
|
|
|
|
* each line in the "colorversatec" 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 ColorVersatec styles.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PlotColorVersTechLine(sectionName, argc, argv)
|
|
|
|
|
char *sectionName; /* Name of this section (unused). */
|
|
|
|
|
int argc; /* Number of arguments on line. */
|
|
|
|
|
char *argv[]; /* Pointers to fields of line. */
|
|
|
|
|
{
|
|
|
|
|
VersatecStyle *new;
|
2024-10-10 21:13:24 +02:00
|
|
|
static const struct { const char *l_str; int l_color; } colors[] = {
|
2024-10-04 18:02:09 +02:00
|
|
|
{"black", BLACK},
|
|
|
|
|
{"cyan", CYAN},
|
|
|
|
|
{"magenta", MAGENTA},
|
|
|
|
|
{"yellow", YELLOW},
|
|
|
|
|
{"K", BLACK},
|
|
|
|
|
{"C", CYAN},
|
|
|
|
|
{"M", MAGENTA},
|
|
|
|
|
{"Y", YELLOW},
|
|
|
|
|
{0}
|
2017-04-25 14:41:48 +02:00
|
|
|
};
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
new = (VersatecStyle *)mallocMagic(sizeof(VersatecStyle));
|
|
|
|
|
|
|
|
|
|
DBTechNoisyNameMask(argv[0], &new->vs_layers);
|
|
|
|
|
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
new->vs_color = BLACK;
|
|
|
|
|
if (strcmp(argv[1], "X") == 0)
|
|
|
|
|
new->vs_flags = VS_CROSS;
|
|
|
|
|
else if (strcmp(argv[1], "B") == 0)
|
|
|
|
|
new->vs_flags = VS_BORDER;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("Second field must be \"X\" or \"B\"\n");
|
|
|
|
|
freeMagic((char *) new);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-01-06 17:12:11 +01:00
|
|
|
unsigned int value;
|
|
|
|
|
int i, j;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (argc != 3 && argc != 4 && argc != 6 && argc != 10 && argc != 18)
|
|
|
|
|
{
|
|
|
|
|
TechError("\"colorversatec\" lines must have 2 fields + 1, 2, 4, 8,"
|
|
|
|
|
" or 16 stipple word values.\n");
|
|
|
|
|
freeMagic((char *)new);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2024-10-10 21:13:24 +02:00
|
|
|
i = LookupStruct(argv[1], (const LookupTable *) colors, sizeof colors[0]);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("First field must be BLACK, CYAN, MAGENTA or YELLOW.\n");
|
|
|
|
|
freeMagic((char *)new);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
new->vs_color = colors[i].l_color;
|
|
|
|
|
new->vs_flags = 0;
|
|
|
|
|
for (j = 0; j < 16; j += (argc - 2))
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < (argc - 2); i++)
|
|
|
|
|
{
|
|
|
|
|
sscanf(argv[i + 2], "%x", &value);
|
|
|
|
|
new->vs_stipple[j + i] = (value << 16) | (value & 0xffff);
|
|
|
|
|
#ifndef WORDS_BIGENDIAN
|
|
|
|
|
new->vs_stipple[j + i] = PlotSwapBytes(new->vs_stipple[i]);
|
|
|
|
|
#endif /* WORDS_BIGENDIAN */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new->vs_next = plotColorVersStyles;
|
|
|
|
|
plotColorVersStyles = new;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PlotColorVersTechLine(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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|
|
|
|
|
|
|
|
|
|
#ifdef VERSATEC
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotTransToSwath --
|
|
|
|
|
*
|
|
|
|
|
* Transforms a rectangle from Magic root coordinates to the
|
|
|
|
|
* coordinates of the current swath.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Dst is modified to hold a rectangle that has been transformed
|
|
|
|
|
* to swath coordinates.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotTransToSwath(src, dst)
|
|
|
|
|
Rect *src; /* Rectangle in Magic root coords. */
|
|
|
|
|
Rect *dst; /* Rectangle to be filled in with swath
|
|
|
|
|
* corresponding to src.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
dst->r_xbot = ((src->r_xbot - plotLL.p_x)*scale) >> scaleShift;
|
|
|
|
|
dst->r_xtop = ((src->r_xtop - plotLL.p_x)*scale) >> scaleShift;
|
|
|
|
|
dst->r_ybot = (((src->r_ybot - plotLL.p_y)*scale) >> scaleShift) - swathY;
|
|
|
|
|
dst->r_ytop = (((src->r_ytop - plotLL.p_y)*scale) >> scaleShift) - swathY;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotVersLine --
|
|
|
|
|
*
|
|
|
|
|
* This procedure plots a line of a given thickness.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The current raster is modified.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotVersLine(area, widen, raster)
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
Raster *raster; /* Raster to write to */
|
|
|
|
|
{
|
|
|
|
|
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))
|
|
|
|
|
PlotFillRaster(raster, &swathArea, PlotBlackStipple);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
PlotRastFatLine(raster, &swathArea.r_ll, &swathArea.r_ur, widen);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotVersRect --
|
|
|
|
|
*
|
|
|
|
|
* This procedure takes a rectangular area, given in Magic root
|
|
|
|
|
* coordinates, translates it to swath coordinates, and draws
|
|
|
|
|
* it as an outline of a given thickness.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies raster.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plotVersRect(area, widen, raster)
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
Raster *raster; /* Raster to plot to */
|
|
|
|
|
{
|
|
|
|
|
Rect side;
|
|
|
|
|
|
|
|
|
|
/* First, the bottom side. */
|
|
|
|
|
|
|
|
|
|
if (area->r_xbot != area->r_xtop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_ytop = side.r_ybot;
|
|
|
|
|
plotVersLine(&side, widen, raster);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
plotVersLine(&side, widen, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now do the left side. */
|
|
|
|
|
|
|
|
|
|
if (area->r_ybot != area->r_ytop)
|
|
|
|
|
{
|
|
|
|
|
side = *area;
|
|
|
|
|
side.r_xtop = side.r_xbot;
|
|
|
|
|
plotVersLine(&side, widen, raster);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
plotVersLine(&side, widen, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotVersTile --
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
plotVersTile(tile, cxp)
|
|
|
|
|
Tile *tile; /* Tile that's of type to be output. */
|
|
|
|
|
TreeContext *cxp; /* Describes search in progress. */
|
|
|
|
|
{
|
|
|
|
|
Rect tileArea, rootArea, swathArea, edge;
|
|
|
|
|
TileType ntype;
|
|
|
|
|
Tile *neighbor;
|
|
|
|
|
Transform *trans = &cxp->tc_scx->scx_trans;
|
|
|
|
|
Raster *raster = (Raster *)cxp->tc_filter->tf_arg;
|
|
|
|
|
|
|
|
|
|
/* Transform tile coords to root coords and then to swath coords. */
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
TITORECT(tile, &tileArea);
|
|
|
|
|
GEOTRANSRECT(trans, &tileArea, &rootArea);
|
|
|
|
|
plotTransToSwath(&rootArea, &swathArea);
|
|
|
|
|
|
|
|
|
|
/* Handle X'ed things specially. */
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (curStyle->vs_flags & VS_CROSS)
|
|
|
|
|
{
|
|
|
|
|
if (!IsSplit(tile))
|
|
|
|
|
if (((swathArea.r_xtop - swathArea.r_xbot) > 6)
|
|
|
|
|
&& ((swathArea.r_ytop - swathArea.r_ybot) > 6))
|
|
|
|
|
{
|
|
|
|
|
Rect r2;
|
|
|
|
|
plotVersLine(&rootArea, 0, raster);
|
|
|
|
|
r2.r_xtop = rootArea.r_xbot;
|
|
|
|
|
r2.r_ybot = rootArea.r_ybot;
|
|
|
|
|
r2.r_xbot = rootArea.r_xtop;
|
|
|
|
|
r2.r_ytop = rootArea.r_ytop;
|
|
|
|
|
plotVersLine(&r2, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile))
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
TileType dinfo;
|
|
|
|
|
Rect r;
|
|
|
|
|
|
|
|
|
|
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &cxp->tc_scx->scx_trans);
|
|
|
|
|
if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS))
|
|
|
|
|
PlotPolyRaster(raster, &swathArea, &swathClip, dinfo,
|
|
|
|
|
curStyle->vs_stipple);
|
|
|
|
|
|
|
|
|
|
/* Diagonal is always drawn (clipping handled in plotVersLine) */
|
|
|
|
|
|
|
|
|
|
r = rootArea;
|
|
|
|
|
if (dinfo & TT_DIRECTION)
|
|
|
|
|
{
|
|
|
|
|
/* swap X to make diagonal go the other way */
|
|
|
|
|
r.r_xbot = r.r_xtop;
|
|
|
|
|
r.r_xtop = rootArea.r_xbot;
|
|
|
|
|
}
|
|
|
|
|
plotVersLine(&r, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Clip and then stipple. */
|
|
|
|
|
|
|
|
|
|
GEOCLIP(&swathArea, &swathClip);
|
|
|
|
|
if (swathArea.r_xbot > swathArea.r_xtop) return 0;
|
|
|
|
|
if (swathArea.r_ybot > swathArea.r_ytop) return 0;
|
|
|
|
|
if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS))
|
|
|
|
|
PlotFillRaster(raster, &swathArea, curStyle->vs_stipple);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now output lines for any edges between material of the type
|
|
|
|
|
* currently being drawn and material of other types. This is
|
|
|
|
|
* done by searching along the tile's borders for neighbors that
|
|
|
|
|
* have the wrong types. First, search the tile's bottom border
|
|
|
|
|
* (unless it is at infinity).
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
|
|
|
|
|
goto searchleft; /* nothing on bottom of split */
|
|
|
|
|
|
|
|
|
|
if (tileArea.r_ybot > TiPlaneRect.r_ybot)
|
|
|
|
|
{
|
|
|
|
|
edge.r_ybot = edge.r_ytop = tileArea.r_ybot;
|
|
|
|
|
for (neighbor = LB(tile); LEFT(neighbor) < tileArea.r_xtop;
|
|
|
|
|
neighbor = TR(neighbor))
|
|
|
|
|
{
|
|
|
|
|
ntype = TiGetTopType(neighbor);
|
|
|
|
|
if (TTMaskHasType(&curMask, ntype)) continue;
|
|
|
|
|
edge.r_xbot = LEFT(neighbor);
|
|
|
|
|
edge.r_xtop = RIGHT(neighbor);
|
|
|
|
|
if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
|
|
|
|
|
if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
|
|
|
|
|
GEOTRANSRECT(trans, &edge, &rootArea);
|
|
|
|
|
plotVersLine(&rootArea, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
searchleft:
|
|
|
|
|
if (IsSplit(tile) && (SplitSide(tile)))
|
|
|
|
|
goto searchtop; /* Nothing on left side of split */
|
|
|
|
|
|
|
|
|
|
/* Now go along the tile's left border, doing the same thing. Ignore
|
|
|
|
|
* edges that are at infinity.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (tileArea.r_xbot > TiPlaneRect.r_xbot)
|
|
|
|
|
{
|
|
|
|
|
edge.r_xbot = edge.r_xtop = tileArea.r_xbot;
|
|
|
|
|
for (neighbor = BL(tile); BOTTOM(neighbor) < tileArea.r_ytop;
|
|
|
|
|
neighbor = RT(neighbor))
|
|
|
|
|
{
|
|
|
|
|
ntype = TiGetRightType(neighbor);
|
|
|
|
|
if (TTMaskHasType(&curMask, ntype)) continue;
|
|
|
|
|
edge.r_ybot = BOTTOM(neighbor);
|
|
|
|
|
edge.r_ytop = TOP(neighbor);
|
|
|
|
|
if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
|
|
|
|
|
if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
|
|
|
|
|
GEOTRANSRECT(trans, &edge, &rootArea);
|
|
|
|
|
plotVersLine(&rootArea, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Same thing for the tile's top border. */
|
|
|
|
|
|
|
|
|
|
searchtop:
|
|
|
|
|
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile)))
|
|
|
|
|
goto searchright; /* Nothing on top side of tile */
|
|
|
|
|
|
|
|
|
|
if (tileArea.r_ytop < TiPlaneRect.r_ytop)
|
|
|
|
|
{
|
|
|
|
|
edge.r_ybot = edge.r_ytop = tileArea.r_ytop;
|
|
|
|
|
for (neighbor = RT(tile); RIGHT(neighbor) > tileArea.r_xbot;
|
|
|
|
|
neighbor = BL(neighbor))
|
|
|
|
|
{
|
|
|
|
|
ntype = TiGetBottomType(neighbor);
|
|
|
|
|
if (TTMaskHasType(&curMask, ntype)) continue;
|
|
|
|
|
edge.r_xbot = LEFT(neighbor);
|
|
|
|
|
edge.r_xtop = RIGHT(neighbor);
|
|
|
|
|
if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
|
|
|
|
|
if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
|
|
|
|
|
GEOTRANSRECT(trans, &edge, &rootArea);
|
|
|
|
|
plotVersLine(&rootArea, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally, the right border. */
|
|
|
|
|
|
|
|
|
|
searchright:
|
|
|
|
|
if (IsSplit(tile) && !(SplitSide(tile)))
|
|
|
|
|
return 0; /* Nothing on right side of tile */
|
|
|
|
|
|
|
|
|
|
if (tileArea.r_xtop < TiPlaneRect.r_xtop)
|
|
|
|
|
{
|
|
|
|
|
edge.r_xbot = edge.r_xtop = tileArea.r_xtop;
|
|
|
|
|
for (neighbor = TR(tile); TOP(neighbor) > tileArea.r_ybot;
|
|
|
|
|
neighbor = LB(neighbor))
|
|
|
|
|
{
|
|
|
|
|
ntype = TiGetLeftType(neighbor);
|
|
|
|
|
if (TTMaskHasType(&curMask, ntype)) continue;
|
|
|
|
|
edge.r_ybot = BOTTOM(neighbor);
|
|
|
|
|
edge.r_ytop = TOP(neighbor);
|
|
|
|
|
if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
|
|
|
|
|
if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
|
|
|
|
|
GEOTRANSRECT(trans, &edge, &rootArea);
|
|
|
|
|
plotVersLine(&rootArea, 0, raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotVersLabel --
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
plotVersLabel(scx, label, tpath, raster)
|
|
|
|
|
SearchContext *scx; /* Describes state of search when label
|
|
|
|
|
* was found.
|
|
|
|
|
*/
|
|
|
|
|
Label *label; /* Label that was found. */
|
|
|
|
|
TerminalPath *tpath; /* Ignored. */
|
|
|
|
|
Raster *raster; /* Raster to write to */
|
|
|
|
|
{
|
|
|
|
|
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(labelFont, 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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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))
|
|
|
|
|
PlotFillRaster(raster, &tmp, PlotBlackStipple);
|
|
|
|
|
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))
|
|
|
|
|
PlotFillRaster(raster, &tmp, PlotBlackStipple);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Line or rectangle. Draw outline. */
|
|
|
|
|
|
|
|
|
|
plotVersRect(&rootArea, 1, raster);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output the text for the label. Before outputting the label,
|
|
|
|
|
* erase the area where the label will appear in order to make
|
|
|
|
|
* the label more visible.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
GEOCLIP(&labelSize, &swathClip);
|
|
|
|
|
PlotClearRaster(raster, &labelSize);
|
|
|
|
|
PlotRasterText(raster, &swathClip, labelFont, label->lab_text, &point);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plotVersCell --
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
plotVersCell(scx, raster)
|
|
|
|
|
SearchContext *scx; /* Describes cell whose bbox is to
|
|
|
|
|
* be plotted.
|
2020-05-23 23:13:14 +02:00
|
|
|
*/
|
2017-04-25 14:41:48 +02:00
|
|
|
Raster *raster; /* Raster to write to */
|
|
|
|
|
{
|
|
|
|
|
char idName[100];
|
|
|
|
|
Rect rootArea, swathArea, textSize;
|
|
|
|
|
Point point;
|
|
|
|
|
CellDef *def;
|
|
|
|
|
|
|
|
|
|
/* Convert the cell's bounding box to root coordinates and then
|
|
|
|
|
* draw as a thick outline.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
def = scx->scx_use->cu_def;
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea);
|
|
|
|
|
plotVersRect(&rootArea, 2, raster);
|
|
|
|
|
|
|
|
|
|
if (!PlotShowCellNames)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
/* Output the cell's name and id text. */
|
|
|
|
|
if (cellNameFont != NULL)
|
|
|
|
|
{
|
|
|
|
|
plotTransToSwath(&rootArea, &swathArea);
|
|
|
|
|
PlotTextSize(cellNameFont, 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;
|
|
|
|
|
PlotRasterText(raster, &swathClip, cellNameFont, def->cd_name, &point);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cellIdFont != NULL)
|
|
|
|
|
{
|
|
|
|
|
DBPrintUseId(scx, idName, 100, TRUE);
|
|
|
|
|
PlotTextSize(cellIdFont, 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;
|
|
|
|
|
PlotRasterText(raster, &swathClip, cellIdFont, idName, &point);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlotVersatec --
|
|
|
|
|
*
|
|
|
|
|
* This procedure generates a raster file suitable for driving
|
|
|
|
|
* printers like the Versatec black-and-white family, and runs
|
|
|
|
|
* a spooling program to print the file.
|
|
|
|
|
*
|
|
|
|
|
* If PlotVersPlotType is VERSATEC_COLOR, it will generate a
|
|
|
|
|
* versatec color plot file in straight color raster format.
|
|
|
|
|
*
|
|
|
|
|
* If PlotVersPlotType is HPGL2 or HPRTL, it will generate
|
2020-05-23 23:13:14 +02:00
|
|
|
* an HPRTL file for the supported HP plotters.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Lots of disk space is chewed up by the file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlotVersatec(scx, layers, xMask, user_scale)
|
|
|
|
|
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 user_scale; /* Scalefactor of output */
|
|
|
|
|
{
|
2024-10-10 21:18:48 +02:00
|
|
|
static const char * const yesNo[] = {"no", "yes", NULL};
|
2017-04-25 14:41:48 +02:00
|
|
|
int dotsAcross, dotsDown, swathsDown, scaleDown;
|
|
|
|
|
int mag_width; /* lambda */
|
2020-05-23 23:13:14 +02:00
|
|
|
float width; /* inches */
|
2017-04-25 14:41:48 +02:00
|
|
|
char fileName[200], command[300], answer[32];
|
|
|
|
|
float length, mBytes;
|
|
|
|
|
Transform tinv;
|
|
|
|
|
int action, result;
|
|
|
|
|
FILE *file;
|
|
|
|
|
VersatecColor color;
|
|
|
|
|
bool haveColorMessage;
|
|
|
|
|
int usedScale, maxScale;
|
|
|
|
|
float oscale;
|
|
|
|
|
Raster *raster = NULL;
|
|
|
|
|
|
|
|
|
|
/* CMYK color separated raster buffers. */
|
2019-06-07 20:13:50 +02:00
|
|
|
Raster *kRaster = NULL, *cRaster = NULL, *mRaster = NULL, *yRaster = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
haveColorMessage = FALSE;
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootClip);
|
|
|
|
|
GEO_EXPAND(&rootClip, 1, &rootClip);
|
|
|
|
|
|
|
|
|
|
/* Get conversion factor (internal units to inches) */
|
|
|
|
|
oscale = CIFGetOutputScale(1000); /* convert to microns */
|
|
|
|
|
oscale *= 3.937e-5; /* convert to inches */
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Compute plot width from scalefactor */
|
|
|
|
|
mag_width = rootClip.r_xtop - rootClip.r_xbot;
|
|
|
|
|
maxScale = ((float)PlotVersWidth / (float)PlotVersDotsPerInch)
|
|
|
|
|
/ (oscale * (float)mag_width);
|
|
|
|
|
width = (float)user_scale * oscale * (float)mag_width;
|
|
|
|
|
|
|
|
|
|
dotsAcross = (int)(width * (float)PlotVersDotsPerInch);
|
|
|
|
|
if (dotsAcross <= 0 || dotsAcross > PlotVersWidth)
|
|
|
|
|
{
|
|
|
|
|
dotsAcross = PlotVersWidth;
|
|
|
|
|
usedScale = maxScale;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
usedScale = user_scale;
|
|
|
|
|
|
|
|
|
|
/* Recompute width based on the actual scale used */
|
|
|
|
|
width = (float)usedScale * oscale * (float)mag_width;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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) / mag_width;
|
|
|
|
|
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 >= 8)
|
|
|
|
|
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 + PlotVersSwathHeight - 1)/PlotVersSwathHeight;
|
|
|
|
|
dotsDown = swathsDown * PlotVersSwathHeight;
|
|
|
|
|
mBytes = ((PlotVersWidth/8)*dotsDown)/1000000.0;
|
|
|
|
|
length = dotsDown;
|
|
|
|
|
length /= PlotVersDotsPerInch;
|
|
|
|
|
TxPrintf("Plot will be %.1f inches wide by %.1f inches long.\n", width, length);
|
2020-05-23 23:13:14 +02:00
|
|
|
TxPrintf("It will take %.2f Megabytes in \"%s\".\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
(PlotVersPlotType == HPRTL || PlotVersPlotType == HPGL2)
|
|
|
|
|
? 4.0 * mBytes : mBytes, PlotTempDirectory);
|
|
|
|
|
TxPrintf("Lambda: %.3f (um) Requested scale: %dX Actual scale: %dX "
|
|
|
|
|
"[Full scale: %dX].\n", CIFGetOutputScale(1000),
|
|
|
|
|
user_scale, usedScale, maxScale);
|
|
|
|
|
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 a swath raster if
|
|
|
|
|
* we don't already have one. If the swath size has changed,
|
|
|
|
|
* recycle the raster for a new one.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if ((raster != NULL) && ((raster->ras_width != PlotVersWidth)
|
|
|
|
|
|| (raster->ras_height != PlotVersSwathHeight)))
|
|
|
|
|
{
|
|
|
|
|
if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
|
|
|
|
|
{
|
|
|
|
|
PlotFreeRaster(cRaster);
|
|
|
|
|
PlotFreeRaster(mRaster);
|
|
|
|
|
PlotFreeRaster(yRaster);
|
|
|
|
|
}
|
|
|
|
|
PlotFreeRaster(kRaster);
|
|
|
|
|
raster = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (raster == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
|
|
|
|
|
{
|
|
|
|
|
cRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
|
|
|
|
|
mRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
|
|
|
|
|
yRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
|
|
|
|
|
}
|
|
|
|
|
kRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
|
|
|
|
|
raster = kRaster;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Load font information for the plot, if it isn't already
|
|
|
|
|
* loaded.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
labelFont = PlotLoadFont(PlotVersLabelFont);
|
|
|
|
|
cellNameFont = PlotLoadFont(PlotVersNameFont);
|
|
|
|
|
cellIdFont = PlotLoadFont(PlotVersIdFont);
|
|
|
|
|
|
|
|
|
|
/* Compute the name of the file to use for output, and open it. */
|
|
|
|
|
|
|
|
|
|
sprintf(fileName, "%s/magicPlotXXXXXX", PlotTempDirectory);
|
|
|
|
|
result = mkstemp(fileName);
|
|
|
|
|
if (result == -1)
|
|
|
|
|
{
|
|
|
|
|
TxError("Failed to 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 - (PlotVersWidth*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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
GeoInvertTrans(&scx->scx_trans, &tinv);
|
|
|
|
|
for (color = BLACK; color <= YELLOW; color++)
|
|
|
|
|
{
|
|
|
|
|
int swathsDownThisColor;
|
|
|
|
|
|
|
|
|
|
swathsDownThisColor = swathsDown;
|
|
|
|
|
rasFileByteCount = 0;
|
|
|
|
|
|
|
|
|
|
/* issue preamble for this color's raster. if we are doing colors */
|
|
|
|
|
switch (PlotVersPlotType)
|
|
|
|
|
{
|
|
|
|
|
case HPRTL:
|
|
|
|
|
PlotHPRTLHeader(PlotVersWidth, dotsDown, PlotVersDotsPerInch, file);
|
|
|
|
|
break;
|
|
|
|
|
case HPGL2:
|
|
|
|
|
PlotHPGL2Header(PlotVersWidth, dotsDown, PlotVersDotsPerInch,
|
|
|
|
|
usedScale, file);
|
2020-05-23 23:13:14 +02:00
|
|
|
break;
|
2017-04-25 14:41:48 +02:00
|
|
|
case VERSATEC_COLOR:
|
|
|
|
|
if (PlotDumpColorPreamble(color, file, dotsDown, PlotVersWidth) != 0)
|
|
|
|
|
goto error;
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
TxPrintf("\nDumping %s Raster:", plotVersatecColorNames[color]);
|
|
|
|
|
TxFlush();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
for (swathsDownThisColor -= 1;
|
|
|
|
|
swathsDownThisColor >= 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
swathsDownThisColor -= 1)
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx2;
|
|
|
|
|
Rect root, labelArea;
|
|
|
|
|
int labelHeight;
|
|
|
|
|
|
|
|
|
|
swathY = swathsDownThisColor * PlotVersSwathHeight;
|
|
|
|
|
if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
|
|
|
|
|
{
|
|
|
|
|
PlotClearRaster(cRaster, (Rect *) NULL);
|
|
|
|
|
PlotClearRaster(mRaster, (Rect *) NULL);
|
|
|
|
|
PlotClearRaster(yRaster, (Rect *) NULL);
|
|
|
|
|
}
|
|
|
|
|
PlotClearRaster(kRaster, (Rect *) NULL);
|
|
|
|
|
|
|
|
|
|
/* Compute the area of the swath that overlaps the portion of
|
|
|
|
|
* the layout we're plotting.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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 >= PlotVersWidth)
|
|
|
|
|
swathClip.r_xtop = PlotVersWidth - 1;
|
|
|
|
|
if (swathClip.r_ytop >= PlotVersSwathHeight)
|
|
|
|
|
swathClip.r_ytop = PlotVersSwathHeight - 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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (labelFont != NULL)
|
|
|
|
|
{
|
|
|
|
|
labelHeight = (labelFont->fo_bbox.r_ytop
|
|
|
|
|
- labelFont->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 Versatec style, output stippled areas for all
|
2020-05-23 23:13:14 +02:00
|
|
|
* the tiles requested by the style.
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch (PlotVersPlotType)
|
|
|
|
|
{
|
|
|
|
|
case VERSATEC_BW:
|
|
|
|
|
curStyle = plotVersStyles;
|
|
|
|
|
break;
|
|
|
|
|
case HPGL2: case HPRTL:
|
2020-05-23 23:13:14 +02:00
|
|
|
curStyle = plotColorVersStyles;
|
2017-04-25 14:41:48 +02:00
|
|
|
if (curStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning: No color versatec styles are defined"
|
|
|
|
|
" in the technology file!\nPlotting aborted.\n");
|
2025-02-13 09:22:28 +01:00
|
|
|
goto error_close_only;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2020-05-23 23:13:14 +02:00
|
|
|
curStyle = plotColorVersStyles;
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!haveColorMessage)
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning: No color versatec styles are defined"
|
|
|
|
|
" in the technology file!\nPlot will be"
|
|
|
|
|
" monochrome.\n");
|
2020-05-23 23:13:14 +02:00
|
|
|
haveColorMessage = TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
curStyle = plotVersStyles;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (curStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning: No monochrome versatec styles are"
|
|
|
|
|
" defined in the technology file!\nPlotting"
|
|
|
|
|
" aborted.\n");
|
2025-02-13 09:22:28 +01:00
|
|
|
goto error_close_only;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( ; curStyle != NULL; curStyle = curStyle->vs_next)
|
|
|
|
|
{
|
|
|
|
|
/* if we are plotting in B&W, then visit all the tiles in this
|
|
|
|
|
* swath, otherwise only visit them if they should be
|
|
|
|
|
* plotted in the current style's color.
|
|
|
|
|
*/
|
|
|
|
|
if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
|
|
|
|
|
{
|
|
|
|
|
switch (curStyle->vs_color)
|
|
|
|
|
{
|
|
|
|
|
case CYAN:
|
|
|
|
|
raster = cRaster;
|
|
|
|
|
break;
|
|
|
|
|
case MAGENTA:
|
|
|
|
|
raster = mRaster;
|
|
|
|
|
break;
|
|
|
|
|
case YELLOW:
|
|
|
|
|
raster = yRaster;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
raster = kRaster;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((PlotVersPlotType != VERSATEC_COLOR) || (curStyle->vs_color == color))
|
|
|
|
|
{
|
|
|
|
|
TTMaskAndMask3(&curMask, layers, &curStyle->vs_layers);
|
|
|
|
|
(void) DBTreeSrTiles(&scx2, &curMask, xMask, plotVersTile,
|
|
|
|
|
(ClientData) raster);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
raster = kRaster;
|
|
|
|
|
|
|
|
|
|
/* Output labels, if they are wanted. */
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(layers, L_LABEL) && (color == BLACK) &&
|
|
|
|
|
(labelFont != NULL))
|
|
|
|
|
{
|
|
|
|
|
curMask = *layers;
|
|
|
|
|
TTMaskSetType(&curMask, TT_SPACE);
|
|
|
|
|
GeoTransRect(&tinv, &labelArea, &scx2.scx_area);
|
|
|
|
|
(void) DBTreeSrLabels(&scx2, &curMask, xMask,
|
|
|
|
|
(TerminalPath *) NULL, TF_LABEL_ATTACH,
|
|
|
|
|
plotVersLabel, (ClientData) raster);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output subcell bounding boxes, if they are wanted. */
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(layers, L_CELL) && color == BLACK)
|
|
|
|
|
{
|
|
|
|
|
(void) DBTreeSrCells(&scx2, xMask, plotVersCell, (ClientData) raster);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TxPrintf("#");
|
|
|
|
|
TxFlush();
|
|
|
|
|
|
|
|
|
|
switch (PlotVersPlotType)
|
|
|
|
|
{
|
|
|
|
|
case HPGL2: case HPRTL:
|
|
|
|
|
PlotDumpHPRTL(file, kRaster, cRaster, mRaster, yRaster);
|
|
|
|
|
break;
|
|
|
|
|
case VERSATEC_COLOR: case VERSATEC_BW:
|
|
|
|
|
if (PlotDumpRaster(raster, file) != 0)
|
|
|
|
|
goto error;
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto error;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Only the VERSATEC_COLOR type runs colors separately */
|
|
|
|
|
if (PlotVersPlotType != VERSATEC_COLOR) break;
|
|
|
|
|
TxPrintf ("\nWrote %d bytes of data.\n", rasFileByteCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write trailers */
|
|
|
|
|
|
|
|
|
|
switch (PlotVersPlotType)
|
|
|
|
|
{
|
|
|
|
|
case HPGL2:
|
|
|
|
|
PlotHPGL2Trailer(file);
|
|
|
|
|
break;
|
|
|
|
|
case HPRTL:
|
|
|
|
|
PlotHPRTLTrailer(file);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close the file and issue the command to plot it. */
|
|
|
|
|
|
|
|
|
|
TxPrintf("\n");
|
|
|
|
|
fclose(file);
|
|
|
|
|
sprintf(command, PlotVersCommand, PlotVersPrinter, fileName);
|
|
|
|
|
if (system(command) != 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Couldn't execute spooler command to print \"%s\"\n",
|
|
|
|
|
fileName);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
2025-02-13 09:22:28 +01:00
|
|
|
error:
|
2017-04-25 14:41:48 +02:00
|
|
|
TxError("\nVersatec plot aborted.\n");
|
|
|
|
|
fclose(file);
|
|
|
|
|
unlink(fileName);
|
2025-02-13 09:22:28 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
error_close_only:
|
|
|
|
|
fclose(file);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* VERSATEC */
|