2017-04-25 14:41:48 +02:00
|
|
|
/* CIFreadpaint.c -
|
|
|
|
|
*
|
|
|
|
|
* This file contains more routines to parse CIF files. In
|
|
|
|
|
* particular, it contains the routines to handle paint,
|
|
|
|
|
* including rectangles, wires, flashes, and polygons.
|
|
|
|
|
*
|
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
|
2024-10-04 12:37:02 +02:00
|
|
|
static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdpt.c,v 1.2 2010/06/24 12:37:15 tim Exp $";
|
2017-04-25 14:41:48 +02:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2017-10-09 17:51:51 +02:00
|
|
|
#include <string.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <math.h> /* for wire path-to-poly path conversion */
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
#include "cif/CIFread.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "textio/textio.h"
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseBox --
|
|
|
|
|
*
|
|
|
|
|
* This procedure parses a CIF box command.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A box is added to the CIF information for this cell. The
|
|
|
|
|
* box better not have corners that fall on half-unit boundaries.
|
|
|
|
|
*
|
|
|
|
|
* Correction:
|
|
|
|
|
* A box may be centered on a half lambda grid but have width
|
|
|
|
|
* and height such that the resulting box is entirely on the lambda
|
|
|
|
|
* grid. So: don't divide by 2 until the last step!
|
|
|
|
|
* ---Tim Edwards, 4/20/00
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseBox(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
Point center;
|
|
|
|
|
Point direction;
|
|
|
|
|
Rect rectangle, r2;
|
|
|
|
|
int savescale;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Take the 'B'. */
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
if (cifReadPlane == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Treat length and width as a point so we can make use of the code in */
|
|
|
|
|
/* CIFParsePoint(); however, before moving on, check that both values */
|
|
|
|
|
/* are strictly positive. */
|
|
|
|
|
|
|
|
|
|
if (!CIFParsePoint(&rectangle.r_ur, 1))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("box, but no length and/or width; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (rectangle.r_xtop <= 0)
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("box length not strictly positive; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (rectangle.r_ytop <= 0)
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("box width not strictly positive; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
savescale = cifReadScale1;
|
|
|
|
|
|
|
|
|
|
if (!CIFParsePoint(¢er, 2))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("box, but no center; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If reading the center causes a CIF input scale to be redefined, */
|
|
|
|
|
/* then the length and width must also be changed. */
|
|
|
|
|
|
|
|
|
|
if (savescale != cifReadScale1)
|
|
|
|
|
{
|
|
|
|
|
rectangle.r_xtop *= (cifReadScale1 / savescale);
|
|
|
|
|
rectangle.r_ytop *= (cifReadScale1 / savescale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rectangle.r_xbot = -rectangle.r_xtop;
|
|
|
|
|
rectangle.r_ybot = -rectangle.r_ytop;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Optional direction vector: have to build transform to do rotate. */
|
|
|
|
|
|
|
|
|
|
if (CIFParseSInteger(&direction.p_x))
|
|
|
|
|
{
|
|
|
|
|
if (!CIFParseSInteger(&direction.p_y))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("box, direction botched; box ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
GeoTransRect(CIFDirectionToTrans(&direction), &rectangle , &r2);
|
|
|
|
|
}
|
|
|
|
|
else r2 = rectangle;
|
|
|
|
|
|
|
|
|
|
/* Offset by center only now that rotation is complete, and divide by two. */
|
|
|
|
|
|
|
|
|
|
r2.r_xbot = (r2.r_xbot + center.p_x) / 2;
|
|
|
|
|
r2.r_ybot = (r2.r_ybot + center.p_y) / 2;
|
|
|
|
|
r2.r_xtop = (r2.r_xtop + center.p_x) / 2;
|
|
|
|
|
r2.r_ytop = (r2.r_ytop + center.p_y) / 2;
|
|
|
|
|
|
|
|
|
|
DBPaintPlane(cifReadPlane, &r2, CIFPaintTable, (PaintUndoInfo *) NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseFlash --
|
|
|
|
|
*
|
|
|
|
|
* This routine parses and processes a roundflash command. The syntax is:
|
|
|
|
|
* roundflash ::= R diameter center
|
|
|
|
|
*
|
|
|
|
|
* We approximate a roundflash by a box.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Paint is added to the current CIF plane.
|
|
|
|
|
*
|
|
|
|
|
* Corrections: Incorrectly implemented. Now CIFParsePoint returns the
|
|
|
|
|
* center coordinate doubled; in this way, the center can be on the
|
|
|
|
|
* half-lambda grid but the resulting block on-grid, if the diameter
|
|
|
|
|
* is an odd number.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseFlash(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int diameter;
|
|
|
|
|
int savescale;
|
|
|
|
|
Point center;
|
|
|
|
|
Rect rectangle;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Take the 'R'. */
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
if (cifReadPlane == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!CIFParseInteger(&diameter))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("roundflash, but no diameter; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
diameter *= cifReadScale1;
|
|
|
|
|
if (diameter % cifReadScale2 != 0)
|
|
|
|
|
CIFReadWarning("Roundflash diameter snapped to nearest integer boundary.\n");
|
|
|
|
|
|
|
|
|
|
diameter /= cifReadScale2;
|
|
|
|
|
savescale = cifReadScale1;
|
|
|
|
|
if (!CIFParsePoint(¢er, 2))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("roundflash, but no center; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (savescale != cifReadScale1)
|
|
|
|
|
diameter *= (cifReadScale1 / savescale);
|
|
|
|
|
|
|
|
|
|
rectangle.r_xbot = (center.p_x - diameter) / 2;
|
|
|
|
|
rectangle.r_ybot = (center.p_y - diameter) / 2;
|
|
|
|
|
rectangle.r_xtop = (center.p_x + diameter) / 2;
|
|
|
|
|
rectangle.r_ytop = (center.p_y + diameter) / 2;
|
|
|
|
|
DBPaintPlane(cifReadPlane, &rectangle, CIFPaintTable,
|
|
|
|
|
(PaintUndoInfo *) NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-09 17:51:51 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFPropRecordPath --
|
|
|
|
|
*
|
|
|
|
|
* Generate a property in the current edit cell and set it to a string
|
|
|
|
|
* containing the values in the list at pathheadp.
|
|
|
|
|
*
|
|
|
|
|
* If "iswire" is TRUE, then all values in the path are assumed to be
|
|
|
|
|
* double the actual value (because path centerlines can be on half-
|
|
|
|
|
* lambda).
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFPropRecordPath(
|
|
|
|
|
CellDef *def,
|
|
|
|
|
CIFPath *pathheadp,
|
|
|
|
|
bool iswire,
|
|
|
|
|
char *propname)
|
2017-10-09 17:51:51 +02:00
|
|
|
{
|
2024-10-04 12:26:58 +02:00
|
|
|
extern float CIFGetOutputScale(int convert);
|
2017-10-09 17:51:51 +02:00
|
|
|
CIFPath *pathp;
|
|
|
|
|
char *pathstr, *sptr;
|
|
|
|
|
int components;
|
|
|
|
|
float x, y, oscale, mult;
|
|
|
|
|
|
|
|
|
|
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
|
|
|
|
|
if (oscale == 0.0) oscale = 1.0;
|
|
|
|
|
mult = (iswire == TRUE) ? 0.5 : 1.0;
|
|
|
|
|
|
|
|
|
|
pathp = pathheadp;
|
|
|
|
|
components = 0;
|
|
|
|
|
|
|
|
|
|
/* Count the number of components in the path */
|
|
|
|
|
while (pathp != NULL)
|
|
|
|
|
{
|
|
|
|
|
pathp = pathp->cifp_next;
|
|
|
|
|
components++;
|
|
|
|
|
}
|
|
|
|
|
/* Allocate enough space to hold 2 * N points at "infinity" */
|
|
|
|
|
pathstr = (char *)mallocMagic(components * 40);
|
|
|
|
|
|
|
|
|
|
pathp = pathheadp;
|
|
|
|
|
sptr = pathstr;
|
|
|
|
|
while (pathp != NULL)
|
|
|
|
|
{
|
|
|
|
|
x = (float)pathp->cifp_x * oscale * mult;
|
|
|
|
|
y = (float)pathp->cifp_y * oscale * mult;
|
|
|
|
|
sprintf(sptr, "%.3f %.3f ", x, y);
|
|
|
|
|
sptr = sptr + strlen(sptr);
|
|
|
|
|
pathp = pathp->cifp_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reallocate pathstr to be no larger than needed to hold the path contents */
|
|
|
|
|
StrDup(&pathstr, pathstr);
|
2019-06-05 21:03:51 +02:00
|
|
|
DBPropPut(def, propname, (ClientData)pathstr);
|
2017-10-09 17:51:51 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFPaintWirePath --
|
|
|
|
|
*
|
|
|
|
|
* Draw a "wire path" described by the endpoints of a centerline through
|
|
|
|
|
* a series of segments, and a wire width. We pass the plane and paint
|
|
|
|
|
* table information so this routine can be used by the database for
|
|
|
|
|
* painting paths from the command-line.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Paints layout into magic. The original wire path is destroyed
|
|
|
|
|
* (memory free'd).
|
|
|
|
|
*
|
|
|
|
|
* Notes:
|
|
|
|
|
* Path coordinates for wires are always assumed to be twice the
|
|
|
|
|
* actual value to avoid roundoff errors, since the centerline of
|
|
|
|
|
* a path can be halfway between two coordinates of the layout grid
|
|
|
|
|
* and still describe a polygon whose endpoints are all on the grid.
|
|
|
|
|
*
|
|
|
|
|
* Warning:
|
|
|
|
|
* It is still possible to get roundoff problems with different
|
|
|
|
|
* values of segment width at different angles caused by snapping
|
|
|
|
|
* to grid points. While this is "as it should be", it causes
|
|
|
|
|
* problems when process design rules demand geometry at 45 degrees
|
|
|
|
|
* only, and the algorithm produces points that are 1 unit off.
|
|
|
|
|
* A possible solution is to adjust "cwidth" to match the average
|
|
|
|
|
* value of "width" after snapping at entering and exiting angles.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFPaintWirePath(
|
|
|
|
|
CIFPath *pathheadp,
|
|
|
|
|
int width,
|
|
|
|
|
bool endcap,
|
|
|
|
|
Plane *plane,
|
2024-10-04 12:42:25 +02:00
|
|
|
const PaintResultType *ptable,
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
PaintUndoInfo *ui)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *pathp, *previousp, *nextp, *polypath;
|
|
|
|
|
CIFPath *returnpath, *newpath, *savepath;
|
|
|
|
|
LinkedRect *rectp;
|
|
|
|
|
double theta, phi, alpha, delta, cwidth, adjwidth, testmitre, savetheta;
|
|
|
|
|
double xmaxoff, ymaxoff, xminoff, yminoff;
|
|
|
|
|
double xmin, ymin, xmax, ymax, xnext, ynext;
|
|
|
|
|
bool firstpoint;
|
|
|
|
|
|
|
|
|
|
/* Get rid of any repeat points, which just screw up the algorithm */
|
|
|
|
|
|
|
|
|
|
previousp = pathheadp;
|
|
|
|
|
pathp = pathheadp->cifp_next;
|
|
|
|
|
if (pathp != NULL)
|
|
|
|
|
{
|
|
|
|
|
while (pathp->cifp_next != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (pathp->cifp_next->cifp_x == pathp->cifp_x &&
|
|
|
|
|
pathp->cifp_next->cifp_y == pathp->cifp_y)
|
|
|
|
|
{
|
|
|
|
|
previousp->cifp_next = pathp->cifp_next;
|
|
|
|
|
freeMagic(pathp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
previousp = pathp;
|
|
|
|
|
pathp = pathp->cifp_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
previousp = pathheadp;
|
|
|
|
|
polypath = NULL;
|
|
|
|
|
|
|
|
|
|
/* Single-point paths are okay; just set the endpoints equal */
|
|
|
|
|
if (pathheadp->cifp_next == NULL)
|
|
|
|
|
pathp = pathheadp;
|
|
|
|
|
else
|
|
|
|
|
pathp = pathheadp->cifp_next;
|
|
|
|
|
|
|
|
|
|
firstpoint = TRUE;
|
|
|
|
|
theta = 0;
|
|
|
|
|
while (pathp != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Advance to the next point */
|
|
|
|
|
xmin = (double)previousp->cifp_x;
|
|
|
|
|
xmax = (double)pathp->cifp_x;
|
|
|
|
|
ymin = (double)previousp->cifp_y;
|
|
|
|
|
ymax = (double)pathp->cifp_y;
|
|
|
|
|
|
|
|
|
|
/* Angle of this segment */
|
|
|
|
|
savetheta = theta;
|
|
|
|
|
theta = atan2(ymax - ymin, xmax - xmin);
|
|
|
|
|
|
|
|
|
|
/* Look ahead to the next point */
|
|
|
|
|
if (firstpoint)
|
|
|
|
|
{
|
|
|
|
|
/* Back first point up by endcap amount (width, */
|
|
|
|
|
/* which is half the width of the route segment.) */
|
|
|
|
|
|
|
|
|
|
if (endcap)
|
|
|
|
|
{
|
|
|
|
|
xmin -= (double)width * cos(theta);
|
|
|
|
|
ymin -= (double)width * sin(theta);
|
|
|
|
|
}
|
|
|
|
|
xminoff = (double)width * cos(theta - 1.5708); /* 90 degrees */
|
|
|
|
|
yminoff = (double)width * sin(theta - 1.5708);
|
|
|
|
|
firstpoint = FALSE;
|
|
|
|
|
|
|
|
|
|
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
|
|
|
|
|
newpath->cifp_next = polypath;
|
|
|
|
|
polypath = newpath;
|
|
|
|
|
returnpath = polypath; /* returnpath is always at the end */
|
|
|
|
|
newpath->cifp_x = round((xmin + xminoff) / 2);
|
|
|
|
|
newpath->cifp_y = round((ymin + yminoff) / 2);
|
|
|
|
|
|
|
|
|
|
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
|
|
|
|
|
newpath->cifp_next = polypath;
|
|
|
|
|
polypath = newpath;
|
|
|
|
|
newpath->cifp_x = round((xmin - xminoff) / 2);
|
|
|
|
|
newpath->cifp_y = round((ymin - yminoff) / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextp = pathp->cifp_next;
|
|
|
|
|
if (nextp != NULL)
|
|
|
|
|
{
|
|
|
|
|
xnext = (double)nextp->cifp_x;
|
|
|
|
|
ynext = (double)nextp->cifp_y;
|
|
|
|
|
phi = atan2(ynext - ymax, xnext - xmax);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Endpoint: create 1/2 width endcap */
|
|
|
|
|
phi = theta;
|
|
|
|
|
if (endcap)
|
|
|
|
|
{
|
|
|
|
|
xmax += (double)width * cos(theta);
|
|
|
|
|
ymax += (double)width * sin(theta);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
alpha = 0.5 * (phi - theta);
|
|
|
|
|
testmitre = fabs(cos(alpha));
|
|
|
|
|
|
|
|
|
|
/* This routine does not (yet) do mitre limits, so for */
|
|
|
|
|
/* now, we do a sanity check. In the case of an */
|
|
|
|
|
/* extremely acute angle, we generate a warning and */
|
|
|
|
|
/* truncate the route. The mitre limit is arbitrarily */
|
|
|
|
|
/* set at 4 times the route width. Such extreme bends */
|
|
|
|
|
/* are usually DRC violations, anyway. Tighter bends */
|
|
|
|
|
/* than this tend to cause difficulties for the */
|
|
|
|
|
/* CIFMakeManhattanPath() routine. */
|
|
|
|
|
|
|
|
|
|
if (testmitre < 0.25) {
|
|
|
|
|
if (testmitre < 1.0e-10) {
|
|
|
|
|
/* Wire reverses direction. Break wire here, */
|
|
|
|
|
/* draw, and start new polygon. */
|
|
|
|
|
|
|
|
|
|
TxError("Warning: direction reversal in path.\n");
|
|
|
|
|
|
|
|
|
|
phi = theta;
|
|
|
|
|
if (endcap)
|
|
|
|
|
{
|
|
|
|
|
xmax += (double)width * cos(theta);
|
|
|
|
|
ymax += (double)width * sin(theta);
|
|
|
|
|
}
|
|
|
|
|
alpha = 0.5 * (phi - theta);
|
|
|
|
|
firstpoint = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
TxError("Error: mitre limit exceeded at wire junction.\n");
|
|
|
|
|
TxError("Route has been truncated.\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delta = (0.5 * (phi + theta)) - 1.5708;
|
|
|
|
|
cwidth = (double)width / cos(alpha);
|
|
|
|
|
xmaxoff = cwidth * cos(delta);
|
|
|
|
|
ymaxoff = cwidth * sin(delta);
|
|
|
|
|
|
|
|
|
|
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
|
|
|
|
|
newpath->cifp_next = polypath;
|
|
|
|
|
polypath = newpath;
|
|
|
|
|
newpath->cifp_x = round((xmax - xmaxoff) / 2);
|
|
|
|
|
newpath->cifp_y = round((ymax - ymaxoff) / 2);
|
|
|
|
|
|
|
|
|
|
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
|
|
|
|
|
newpath->cifp_next = NULL;
|
|
|
|
|
savepath = returnpath;
|
|
|
|
|
returnpath->cifp_next = newpath;
|
|
|
|
|
returnpath = newpath;
|
|
|
|
|
newpath->cifp_x = round((xmax + xmaxoff) / 2);
|
|
|
|
|
newpath->cifp_y = round((ymax + ymaxoff) / 2);
|
|
|
|
|
|
|
|
|
|
if (firstpoint == TRUE || nextp == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Slow draw for non-Manhattan paths: */
|
|
|
|
|
/* Break the area up into triangles and rectangles */
|
|
|
|
|
|
2023-01-27 17:47:37 +01:00
|
|
|
rectp = CIFPolyToRects(polypath, plane, ptable, ui, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
CIFFreePath(polypath);
|
|
|
|
|
|
|
|
|
|
for (; rectp != NULL ; rectp = rectp->r_next)
|
|
|
|
|
{
|
|
|
|
|
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
|
|
|
|
|
freeMagic((char *) rectp);
|
|
|
|
|
}
|
|
|
|
|
polypath = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Rect r;
|
|
|
|
|
double a1, a2, r2, d1;
|
|
|
|
|
Point newpt;
|
|
|
|
|
|
|
|
|
|
/* Check if either of the two new segments travels opposite */
|
|
|
|
|
/* to theta. If so, then we need to find the intersection */
|
|
|
|
|
/* with the previous point, to avoid creating a cut-out */
|
|
|
|
|
/* wedge in the path. */
|
|
|
|
|
|
|
|
|
|
a1 = fabs(atan2(returnpath->cifp_y - savepath->cifp_y,
|
|
|
|
|
returnpath->cifp_x - savepath->cifp_x) - theta);
|
|
|
|
|
a2 = fabs(atan2(polypath->cifp_y - polypath->cifp_next->cifp_y,
|
|
|
|
|
polypath->cifp_x - polypath->cifp_next->cifp_x) - theta);
|
|
|
|
|
if (a1 > 0.1 && a1 < 6.1)
|
|
|
|
|
{
|
|
|
|
|
/* Find new intersection point */
|
|
|
|
|
d1 = cos(savetheta) * sin(phi) - sin(savetheta) * cos(phi);
|
|
|
|
|
if (fabs(d1) > 1.0e-4)
|
|
|
|
|
{
|
|
|
|
|
r2 = (sin(phi) * (returnpath->cifp_x - savepath->cifp_x)
|
|
|
|
|
- cos(phi) * (returnpath->cifp_y - savepath->cifp_y)) / d1;
|
|
|
|
|
savepath->cifp_x += round(r2 * cos(savetheta));
|
|
|
|
|
savepath->cifp_y += round(r2 * sin(savetheta));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (a2 > 0.1 && a2 < 6.1)
|
|
|
|
|
{
|
|
|
|
|
/* Find new intersection point */
|
|
|
|
|
d1 = cos(savetheta) * sin(phi) - sin(savetheta) * cos(phi);
|
|
|
|
|
if (fabs(d1) > 1.0e-4)
|
|
|
|
|
{
|
|
|
|
|
r2 = (sin(phi) * (polypath->cifp_x - polypath->cifp_next->cifp_x)
|
|
|
|
|
- cos(phi) * (polypath->cifp_y - polypath->cifp_next->cifp_y))
|
|
|
|
|
/ d1;
|
|
|
|
|
polypath->cifp_next->cifp_x += round(r2 * cos(savetheta));
|
|
|
|
|
polypath->cifp_next->cifp_y += round(r2 * sin(savetheta));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
previousp = pathp;
|
|
|
|
|
pathp = pathp->cifp_next;
|
|
|
|
|
}
|
|
|
|
|
CIFFreePath(pathheadp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PaintPolygon --
|
|
|
|
|
*
|
|
|
|
|
* Convert a list of points in the form of an array of type Point to a
|
|
|
|
|
* CIFPath linked structure, and paint them into the database.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Paints tiles into the layout database. Calling routine is
|
|
|
|
|
* responsible for free'ing memory of the pointlist, if necessary.
|
|
|
|
|
*
|
|
|
|
|
* Notes:
|
|
|
|
|
* This is a database routine, not a CIF routine. However, it makes
|
|
|
|
|
* use of the CIFPath structure, so it is included here.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
LinkedRect *
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
PaintPolygon(
|
|
|
|
|
Point *pointlist, /* Array of Point structures */
|
|
|
|
|
int number, /* total number of points */
|
|
|
|
|
Plane *plane, /* Plane structure to paint into */
|
|
|
|
|
PaintResultType *ptable, /* Paint result table */
|
|
|
|
|
PaintUndoInfo *ui, /* Undo record */
|
|
|
|
|
bool keep) /* Return list of rects if true */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
LinkedRect *rectp, *rectlist;
|
|
|
|
|
CIFPath *newpath, *cifpath = (CIFPath *)NULL;
|
|
|
|
|
int i;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < number; i++)
|
|
|
|
|
{
|
|
|
|
|
newpath = (CIFPath *) mallocMagic((unsigned) sizeof (CIFPath));
|
|
|
|
|
newpath->cifp_x = pointlist[i].p_x;
|
|
|
|
|
newpath->cifp_y = pointlist[i].p_y;
|
|
|
|
|
newpath->cifp_next = cifpath;
|
|
|
|
|
cifpath = newpath;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-27 17:47:37 +01:00
|
|
|
rectlist = CIFPolyToRects(cifpath, plane, ptable, ui, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
CIFFreePath(cifpath);
|
|
|
|
|
|
|
|
|
|
for (rectp = rectlist; rectp != NULL ; rectp = rectp->r_next)
|
|
|
|
|
{
|
|
|
|
|
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
|
|
|
|
|
if (!keep) freeMagic((char *) rectp);
|
|
|
|
|
}
|
|
|
|
|
return (keep) ? rectlist : (LinkedRect *)NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PaintWireList --
|
|
|
|
|
*
|
|
|
|
|
* Convert a list of points in the form of an array of type Point to a
|
|
|
|
|
* CIFPath linked structure, and paint them into the database.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Paints tiles into the layout database. Calling routine is
|
|
|
|
|
* responsible for free'ing memory of the pointlist, if necessary.
|
|
|
|
|
*
|
|
|
|
|
* Notes:
|
|
|
|
|
* This is a database routine, not a CIF routine. However, it makes
|
|
|
|
|
* use of the CIFPath structure, so it is included here.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
PaintWireList(
|
|
|
|
|
Point *pointlist, /* Array of Point structures */
|
|
|
|
|
int number, /* total number of points */
|
|
|
|
|
int width, /* Route width of path */
|
|
|
|
|
bool endcap, /* Whether or not to add 1/2 width endcaps */
|
|
|
|
|
Plane *plane, /* Plane structure to paint into */
|
|
|
|
|
PaintResultType *ptable, /* Paint result table */
|
|
|
|
|
PaintUndoInfo *ui) /* Undo record */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *newpath, *cifpath = (CIFPath *)NULL;
|
|
|
|
|
int i;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < number; i++)
|
|
|
|
|
{
|
|
|
|
|
newpath = (CIFPath *) mallocMagic((unsigned) sizeof (CIFPath));
|
|
|
|
|
newpath->cifp_x = pointlist[i].p_x;
|
|
|
|
|
newpath->cifp_y = pointlist[i].p_y;
|
|
|
|
|
newpath->cifp_next = cifpath;
|
|
|
|
|
cifpath = newpath;
|
|
|
|
|
}
|
|
|
|
|
CIFPaintWirePath(cifpath, width, endcap, plane, ptable, ui);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseWire --
|
|
|
|
|
*
|
|
|
|
|
* This procedure parses CIF wire commands, and adds paint
|
|
|
|
|
* to the current CIF cell. A wire command consists of
|
|
|
|
|
* an integer width, then a path.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The current CIF planes are modified.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseWire(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int width;
|
|
|
|
|
CIFPath *pathheadp, *polypath;
|
|
|
|
|
int savescale;
|
|
|
|
|
|
|
|
|
|
/* Take the 'W'. */
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
if (cifReadPlane == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!CIFParseInteger(&width))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("wire, but no width; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
width *= cifReadScale1;
|
|
|
|
|
if (width % cifReadScale2 != 0)
|
|
|
|
|
CIFReadWarning("Wire width snapped to nearest integer boundary.\n");
|
|
|
|
|
|
|
|
|
|
width /= cifReadScale2;
|
|
|
|
|
savescale = cifReadScale1;
|
2025-02-19 10:58:46 +01:00
|
|
|
pathheadp = CIFParsePath(2);
|
|
|
|
|
if (pathheadp == NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFReadError("wire, but improper path; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (savescale != cifReadScale1)
|
|
|
|
|
width *= (cifReadScale1 / savescale);
|
|
|
|
|
|
|
|
|
|
CIFPaintWirePath(pathheadp, width, TRUE, cifReadPlane, CIFPaintTable,
|
|
|
|
|
(PaintUndoInfo *)NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseLayer --
|
|
|
|
|
*
|
|
|
|
|
* This procedure parses layer changes. The syntax is:
|
|
|
|
|
* layer ::= L { blank } processchar layerchars
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Switches the CIF plane where paint is being saved.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseLayer(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
#define MAXCHARS 4
|
|
|
|
|
char name[MAXCHARS+1];
|
|
|
|
|
char c;
|
|
|
|
|
int i;
|
|
|
|
|
TileType type;
|
|
|
|
|
|
|
|
|
|
/* Take the 'L'. */
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
|
|
|
|
|
/* Get the layer name. */
|
|
|
|
|
|
|
|
|
|
for (i=0; i<=MAXCHARS; i++)
|
|
|
|
|
{
|
|
|
|
|
c = PEEK();
|
|
|
|
|
if (isdigit(c) || isupper(c))
|
|
|
|
|
name[i] = TAKE();
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
name[i] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Set current plane for use by the routines that parse geometric
|
|
|
|
|
* elements.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
type = CIFReadNameToType(name, FALSE);
|
|
|
|
|
if (type < 0)
|
|
|
|
|
{
|
|
|
|
|
cifReadPlane = NULL;
|
|
|
|
|
cifCurLabelType = TT_SPACE;
|
|
|
|
|
CIFReadError("layer %s isn't known in the current style.\n",
|
|
|
|
|
name);
|
|
|
|
|
} else {
|
|
|
|
|
cifCurLabelType = cifCurReadStyle->crs_labelLayer[type];
|
|
|
|
|
cifReadPlane = cifCurReadPlanes[type];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParsePoly --
|
|
|
|
|
*
|
|
|
|
|
* This procedure reads and processes a polygon command. The syntax is:
|
|
|
|
|
* polygon ::= path
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Paint is added to the current CIF plane.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParsePoly(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *pathheadp;
|
|
|
|
|
LinkedRect *rectp;
|
|
|
|
|
|
|
|
|
|
/* Take the 'P'. */
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
if (cifReadPlane == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2025-02-19 10:58:46 +01:00
|
|
|
pathheadp = CIFParsePath(1);
|
|
|
|
|
if (pathheadp == NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFReadError("polygon, but improper path; ignored.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert the polygon to rectangles. */
|
|
|
|
|
|
|
|
|
|
rectp = CIFPolyToRects(pathheadp, cifReadPlane, CIFPaintTable,
|
2023-01-27 17:47:37 +01:00
|
|
|
(PaintUndoInfo *)NULL, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
CIFFreePath(pathheadp);
|
|
|
|
|
if (rectp == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* The non-Manhattan geometry polygon parsing algorithm */
|
|
|
|
|
/* typically leaves behind degenerate paths, so they */
|
|
|
|
|
/* should not be considered erroneous. */
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
for (; rectp != NULL ; rectp = rectp->r_next)
|
|
|
|
|
{
|
|
|
|
|
DBPaintPlane(cifReadPlane, &rectp->r_r, CIFPaintTable,
|
|
|
|
|
(PaintUndoInfo *) NULL);
|
|
|
|
|
freeMagic((char *) rectp);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|