1 /* selCreate.c -
2  *
3  *	This file provides routines to make selections by copying
4  *	things into a special cell named "__SELECT__".
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/select/selCreate.c,v 1.10 2010/06/24 12:37:56 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "utils/magic.h"
27 #include "utils/malloc.h"
28 #include "utils/geometry.h"
29 #include "tiles/tile.h"
30 #include "utils/hash.h"
31 #include "database/database.h"
32 #include "windows/windows.h"
33 #include "dbwind/dbwind.h"
34 #include "utils/undo.h"
35 #include "commands/commands.h"
36 #include "select/selInt.h"
37 #include "select/select.h"
38 #include "drc/drc.h"
39 #include "utils/main.h"
40 #include "utils/signals.h"
41 
42 /* Two cells worth of information are kept around by the selection
43  * module.  SelectDef and SelectUse are for the cells whose contents
44  * are the current selection.  Select2Def and Select2Use provide a
45  * temporary working space for procedures that manipulate the selection.
46  * for example, Select2Def is used to hold nets or regions while they
47  * are being extracted by SelectRegion or SelectNet.  Once completely
48  * extracted, information is copied to SelectDef.  Changes to
49  * SelectDef are undo-able and redo-able (so that the undo package
50  * can deal with selection changes), but changes to Select2Def are
51  * not undo-able (undoing is always disabled when the cell is modified).
52  */
53 
54 global CellDef *SelectDef, *Select2Def;
55 global CellUse *SelectUse, *Select2Use;
56 
57 /* The CellDef below points to the definition FROM which the selection
58  * is extracted.  This is the root definition of a window.  Everything
59  * in the selection must have come from the same place, so we clear the
60  * selection whenever the user tries to select from a new hierarchy.
61  */
62 
63 CellDef *SelectRootDef = NULL;
64 
65 /* The CellUse below is the last use selected by SelectUse.  It is
66  * kept around to support the "replace" feature of SelectUse.
67  *
68  * Procedures which deselect a cell must reset this to null if they
69  * happen to deselect this usage.  (Danger Will Robinson)
70  */
71 
72 global CellUse *selectLastUse = NULL;
73 
74 
75 /*
76  * ----------------------------------------------------------------------------
77  *
78  * SelectInit --
79  *
80  * 	This procedure initializes the selection code by creating
81  *	the selection cells.
82  *
83  * Results:
84  *	None.
85  *
86  * Side effects:
87  *	The select cells are created if they don't already exist.
88  *	Selection undo-ing is also initialized.
89  *
90  * ----------------------------------------------------------------------------
91  */
92 
93 void
SelectInit()94 SelectInit()
95 {
96     static bool initialized = FALSE;
97 
98     if (initialized) return;
99     else initialized = TRUE;
100 
101     /* Create the working cells used internally to this module to
102      * hold selected information.  Don't allow any of this to be
103      * undone, or else it could invalidate all the pointers we
104      * keep around to the cells.
105      */
106 
107     UndoDisable();
108     SelectDef = DBCellLookDef("__SELECT__");
109     if (SelectDef == (CellDef *) NULL)
110     {
111 	SelectDef = DBCellNewDef("__SELECT__");
112 	ASSERT(SelectDef != (CellDef *) NULL, "SelectInit");
113 	DBCellSetAvail(SelectDef);
114 	SelectDef->cd_flags |= CDINTERNAL;
115 	TTMaskZero(&SelectDef->cd_types);
116     }
117     SelectUse = DBCellNewUse(SelectDef, (char *) NULL);
118     DBSetTrans(SelectUse, &GeoIdentityTransform);
119     SelectUse->cu_expandMask = CU_DESCEND_SPECIAL;	/* This is always expanded. */
120     SelectUse->cu_flags = 0;	/* never locked down */
121 
122     Select2Def = DBCellLookDef("__SELECT2__");
123     if (Select2Def == (CellDef *) NULL)
124     {
125 	Select2Def = DBCellNewDef("__SELECT2__");
126 	ASSERT(Select2Def != (CellDef *) NULL, "SelectInit");
127 	DBCellSetAvail(Select2Def);
128 	Select2Def->cd_flags |= CDINTERNAL;
129     }
130     Select2Use = DBCellNewUse(Select2Def, (char *) NULL);
131     DBSetTrans(Select2Use, &GeoIdentityTransform);
132     Select2Use->cu_expandMask = CU_DESCEND_SPECIAL;	/* This is always expanded. */
133     Select2Use->cu_flags = 0;	/* never locked down */
134     UndoEnable();
135 
136     SelUndoInit();
137 }
138 
139 /*
140  * ----------------------------------------------------------------------------
141  *
142  * SelectClear --
143  *
144  * 	This procedure clears the current selection.
145  *
146  * Results:
147  *	None.
148  *
149  * Side effects:
150  *	All information is removed from the select cell, and selection
151  *	information is also taken off the screen.
152  *
153  * ----------------------------------------------------------------------------
154  */
155 
156 /* The variables below are used to record information about subcells that
157  * must be cleared from the select cell.
158  */
159 
160 #define MAXUSES 30
161 static CellUse *(selDeleteUses[MAXUSES]);
162 static int selNDelete;
163 
164 void
SelectClear()165 SelectClear()
166 {
167     SearchContext scx;
168     Rect r, expand;
169     extern int selClearFunc();		/* Forward declaration. */
170 
171     if (SelectRootDef == NULL) return;
172 
173     scx.scx_area = SelectDef->cd_bbox;
174     expand = scx.scx_area;
175 
176     /* Special handling when the cell is flagged as a net selection */
177 
178     if (SelectUse->cu_flags & CU_SELECT_NET)
179     {
180 	SelNetRememberForUndo((CellDef *)NULL, (Point *)NULL,
181 			TT_SPACE, FALSE, FALSE);
182 	SelectUse->cu_flags = 0;
183 	DBCellClearDef(SelectDef);
184     }
185     else
186     {
187 	SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
188 	SelectUse->cu_flags = 0;
189 
190 	/* Erase all the paint from the select cell. */
191 	DBEraseMask(SelectDef, &TiPlaneRect, &DBAllButSpaceBits);
192 
193 	/* For the line below to work, paint tables need to be set up correctly! */
194 	/* DBErase(SelectDef, &TiPlaneRect, TT_SPACE); */
195 
196 	/* Erase all of the labels from the select cell. */
197 
198 	(void) DBEraseLabel(SelectDef, &TiPlaneRect, &DBAllTypeBits, &expand);
199 
200 	/* Erase all of the subcells from the select cell.  This is a bit tricky,
201 	 * because we can't erase the subcells while searching for them (it will
202 	 * cause problems for the database).  The code below first grabs up a
203 	 * few subcells, then deletes them, then grabs up a few more, then deletes
204 	 * them, and so on until done.
205 	 */
206 
207 	scx.scx_use = SelectUse;
208 	scx.scx_trans = GeoIdentityTransform;
209 	while (TRUE)
210 	{
211 	    int i;
212 
213 	    selNDelete = 0;
214 	    (void) DBCellSrArea(&scx, selClearFunc, (ClientData) NULL);
215 	    for (i = 0; i < selNDelete; i += 1)
216 	    {
217 		DBUnLinkCell(selDeleteUses[i], SelectDef);
218 		DBDeleteCell(selDeleteUses[i]);
219 		(void) DBCellDeleteUse(selDeleteUses[i]);
220 	    }
221 	    if (selNDelete < MAXUSES) break;
222 	}
223 	selectLastUse = NULL;
224 
225 	SelRememberForUndo(FALSE, SelectRootDef, &scx.scx_area);
226     }
227 
228     TTMaskZero(&SelectDef->cd_types);
229 
230     /* Reset the transform, if we have been moving the selection around */
231     GeoTransRect(&SelectUse->cu_transform, &expand, &r);
232     SelectUse->cu_transform = GeoIdentityTransform;
233 
234     /* Erase the selection from the screen. */
235     DBWHLRedraw(SelectRootDef, &r, TRUE);
236 
237     DBReComputeBbox(SelectDef);
238     DBWAreaChanged(SelectDef, &expand, DBW_ALLWINDOWS,
239 	(TileTypeBitMask *) NULL);
240 }
241 
242 /* Search function to help clear subcells from the selection.  It just
243  * records information about several subcells (up to MAXUSES).
244  */
245 
246 int
selClearFunc(scx)247 selClearFunc(scx)
248     SearchContext *scx;		/* Describes a cell that was found. */
249 {
250     selDeleteUses[selNDelete] = scx->scx_use;
251     selNDelete += 1;
252     if (selNDelete == MAXUSES) return 1;
253     else return 2;
254 }
255 
256 /*
257  * ----------------------------------------------------------------------------
258  *
259  * selIntersectPaintFunc2 ---
260  *
261  * ----------------------------------------------------------------------------
262  */
263 
264 int
selIntersectPaintFunc2(tile,rect)265 selIntersectPaintFunc2(tile, rect)
266     Tile *tile;		/* The tile to copy paint from. */
267     Rect *rect;		/* Area to clip to */
268 {
269     Rect r;
270 
271     TiToRect(tile, &r);
272     GEOCLIP(&r, rect);    /* Clip out the intersection area */
273     DBPaint(SelectDef, &r, TiGetTypeExact(tile));	/* Paint back into SelectDef */
274     return 0;			    /* Keep the search going. */
275 }
276 
277 /*
278  * ----------------------------------------------------------------------------
279  *
280  * selIntersectPaintFunc --
281  *
282  *	Erase paint of types in rMask from the area of the tile.
283  *
284  * ----------------------------------------------------------------------------
285  */
286 
287 int
selIntersectPaintFunc(tile)288 selIntersectPaintFunc(tile)
289     Tile *tile;			/* The tile to copy paint from. */
290 {
291     TileTypeBitMask tMask;
292     Rect r;
293     int pNum;
294 
295     TiToRect(tile, &r);
296 
297     for (pNum = 0; pNum < DBNumPlanes; pNum++)
298     {
299 	DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r,
300 		    &DBAllButSpaceAndDRCBits, selIntersectPaintFunc2,
301 		    (ClientData)&r);
302     }
303     return 0;			    /* Keep the search going. */
304 }
305 
306 /*
307  * ----------------------------------------------------------------------------
308  *
309  * SelectIntersect --
310  *
311  * 	This procedure selects all information that falls in a given area
312  *	and contains the intersection of all the supplied types.
313  *
314  * Results:
315  *	None.
316  *
317  * Side effects:
318  *	The indicated information is added to the select cell, and
319  *	outlined on the screen.  Only information of particular
320  *	types, and in expanded cells (according to xMask) is
321  *	selected.
322  *
323  * ----------------------------------------------------------------------------
324  */
325 
326 void
SelectIntersect(scx,type,xMask,negate)327 SelectIntersect(scx, type, xMask, negate)
328     SearchContext *scx;		/* Describes the area in which material
329 				 * is to be selected.  The resulting
330 				 * coordinates should map to the coordinates
331 				 * of EditRootDef.  The cell use should be
332 				 * the root of a window.
333 				 */
334     TileType type;		/* Indicates which layer to intersect with
335 				 * the current selection.
336 				 */
337     int xMask;			/* Indicates window (or windows) where cells
338 				 * must be expanded for their contents to be
339 				 * considered.  0 means treat everything as
340 				 * expanded.
341 				 */
342     bool negate;		/* If true, search on NOT(type) */
343 {
344     TileTypeBitMask tMask, rMask;
345     TileType s, t;
346     int plane;
347     SearchContext scx2;
348 
349     /* The source definition may not change */
350     if (SelectRootDef != scx->scx_use->cu_def) return;
351 
352     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
353 
354     /* Copy SelectDef contents (paint only) into Select2Def */
355     DBCellClearDef(Select2Def);
356     scx2.scx_use = SelectUse;
357     scx2.scx_area = SelectUse->cu_bbox;
358     GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx2.scx_trans);
359     DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK,
360                 Select2Use);
361 
362     /* Clear the original selection */
363     DBCellClearDef(SelectDef);
364 
365     /* Select all paint of type "type" and copy into SelectDef */
366     TTMaskSetOnlyType(&tMask, type);
367 
368     plane = DBPlane(type);
369     (void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse);
370 
371     /* Scan Select2Def for all geometry inside the area of "type", and  */
372     /* copy back to SelectDef as "type"					*/
373 
374     if (negate)
375     {
376 	TTMaskCom(&tMask);
377 	TTMaskAndMask(&tMask, &DBPlaneTypes[plane]);
378     }
379     DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane],
380 	    &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL);
381 
382     if (negate) TTMaskSetOnlyType(&tMask, type);    /* Restore original mask */
383 
384     DBEraseMask(SelectDef, &TiPlaneRect, &tMask);
385 
386     /* Display the new selection. */
387 
388     SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area);
389     DBReComputeBbox(SelectDef);
390     DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE);
391     DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
392 	    &DBAllButSpaceBits);
393 }
394 
395 /*
396  * ----------------------------------------------------------------------------
397  *
398  * SelectArea --
399  *
400  * 	This procedure selects all information of given types that
401  *	falls in a given area.
402  *
403  * Results:
404  *	None.
405  *
406  * Side effects:
407  *	The indicated information is added to the select cell, and
408  *	outlined on the screen.  Only information of particular
409  *	types, and in expanded cells (according to xMask) is
410  *	selected.
411  *
412  * ----------------------------------------------------------------------------
413  */
414 
415 void
SelectArea(scx,types,xMask,globmatch)416 SelectArea(scx, types, xMask, globmatch)
417     SearchContext *scx;		/* Describes the area in which material
418 				 * is to be selected.  The resulting
419 				 * coordinates should map to the coordinates
420 				 * of EditRootDef.  The cell use should be
421 				 * the root of a window.
422 				 */
423     TileTypeBitMask *types;	/* Indicates which layers to select.  Can
424 				 * include L_CELL and L_LABELS to select
425 				 * labels and unexpanded subcells.  If L_LABELS
426 				 * is specified then all labels touching the
427 				 * area are selected.  If L_LABELS isn't
428 				 * specified, then only labels attached to
429 				 * selected material are selected.
430 				 */
431     int xMask;			/* Indicates window (or windows) where cells
432 				 * must be expanded for their contents to be
433 				 * considered.  0 means treat everything as
434 				 * expanded.
435 				 */
436     char *globmatch;		/* If non-NULL, and if L_LABELS is among the
437 				 * selection types, then do glob-style matching
438 				 * of any labels against this string.
439 				 */
440 {
441     Rect labelArea, cellArea;
442 
443     /* If the source definition is changing, clear the old selection. */
444 
445     if (SelectRootDef != scx->scx_use->cu_def)
446     {
447 	if (SelectRootDef != NULL)
448 	    SelectClear();
449 	SelectRootDef = scx->scx_use->cu_def;
450 	SelSetDisplay(SelectUse, SelectRootDef);
451     }
452 
453     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
454 
455     /* Select paint. */
456 
457     (void) DBCellCopyAllPaint(scx, types, xMask, SelectUse);
458 
459     SelectDef->cd_types = *types;	/* Remember what types were requested */
460 
461     /* Select labels. */
462 
463     if (TTMaskHasType(types, L_LABEL))
464     {
465 	if (globmatch != NULL)
466 	    DBCellCopyGlobLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea,
467 		    globmatch);
468 	else
469 	    DBCellCopyAllLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea);
470     }
471     else (void) DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
472 
473     /* Select unexpanded cell uses. */
474 
475     if (TTMaskHasType(types, L_CELL))
476         (void) DBCellCopyAllCells(scx, xMask, SelectUse, &cellArea);
477     else
478     {
479 	cellArea.r_xbot = 0;
480 	cellArea.r_xtop = -1;
481     }
482 
483     /* Display the new selection. */
484 
485     (void) GeoIncludeAll(&scx->scx_area, &labelArea);
486     (void) GeoIncludeAll(&cellArea, &labelArea);
487     SelRememberForUndo(FALSE, SelectRootDef, &labelArea);
488     DBReComputeBbox(SelectDef);
489     DBWHLRedraw(SelectRootDef, &labelArea, TRUE);
490     DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
491 	&DBAllButSpaceBits);
492 }
493 
494 
495 /*
496  * ----------------------------------------------------------------------------
497  *
498  * selFindChunk --
499  *
500  * 	This is a recursive procedure to find the largest chunk of
501  *	material in a particular area.  It locates a rectangular
502  *	area of given materials whose minimum dimension is as
503  *	large as possible, and whose maximum dimension is also as
504  *	large as possible (but minimum dimension is more important).
505  *	Furthermore, the chunk must lie within a particular area and
506  *	must contain a given area.
507  *
508  * Results:
509  *	None.
510  *
511  * Side effects:
512  *	None.
513  *
514  * ----------------------------------------------------------------------------
515  */
516 
517 #define MAX_RECURSION_LEVEL 22
518 
519 void
selFindChunk(plane,wrongTypes,searchArea,containedArea,bestMin,bestMax,bestChunk,level)520 selFindChunk(plane, wrongTypes, searchArea, containedArea, bestMin,
521 	bestMax, bestChunk, level)
522     Plane *plane;			/* Plane on which to hunt for chunk. */
523     TileTypeBitMask *wrongTypes;	/* Types that are not allowed to be
524 					 * part of the chunk.
525 					 */
526     Rect *searchArea;			/* Largest allowable size for the
527 					 * chunk.  Note:  don't overestimate
528 					 * this or the procedure will take a
529 					 * long time!  (it processes every
530 					 * tile in this area).
531 					 */
532     Rect *containedArea;		/* The chunk returned must contain
533 					 * this entire area.
534 					 */
535     int *bestMin;			/* Largest minimum dimension seen so
536 					 * far: skip any chunks that can't
537 					 * match this.  Updated by this
538 					 * procedure.
539 					 */
540     int *bestMax;			/* Largest maximum dimension seen
541 					 * so far.
542 					 */
543     Rect *bestChunk;			/* Filled in with largest chunk seen
544 					 * so far, if we find one better than
545 					 * bestMin and bestMax.
546 					 */
547     int level;				/* Recursion level (to avoid worst-
548 					 * case scenarios)
549 					 */
550 {
551     Rect smaller;
552     int min, max;
553     extern int selChunkFunc();
554     Rect wrong;
555 
556     if (level == MAX_RECURSION_LEVEL) return;
557 
558     /* If the search area is already smaller than the chunk to beat,
559      * there's no point in even examining this chunk.
560      */
561 
562     min = searchArea->r_xtop - searchArea->r_xbot;
563     max = searchArea->r_ytop - searchArea->r_ybot;
564     if (min > max)
565     {
566 	int tmp;
567 	tmp = min; min = max; max = tmp;
568     }
569 
570     if (min < *bestMin) return;
571     if ((min == *bestMin) && (max <= *bestMax)) return;
572 
573     /* At each stage, search the area that's left for material of the
574      * wrong type.
575      */
576 
577     if (DBSrPaintArea((Tile *) NULL, plane, searchArea, wrongTypes,
578 	    selChunkFunc, (ClientData) &wrong) == 0)
579     {
580 	/* The area contains nothing but material of the right type,
581 	 * so it is now the "chunk to beat".
582 	 */
583 
584 	*bestMin = min;
585 	*bestMax = max;
586 	*bestChunk = *searchArea;
587 	return;
588     }
589 
590     if (SigInterruptPending)
591 	return;
592 
593     /* At this point the current search area contains some material of
594      * the wrong type.  We have to reduce the search area to exclude this
595      * material.  There are two ways that this can be done while still
596      * producing areas that contain containedArea.  Try both of those,
597      * and repeat the whole thing recursively on the smaller areas.
598      */
599 
600     /* First, try reducing the x-range. */
601 
602     smaller = *searchArea;
603     if (wrong.r_xbot >= containedArea->r_xtop)
604 	smaller.r_xtop = wrong.r_xbot;
605     else if (wrong.r_xtop <= containedArea->r_xbot)
606 	smaller.r_xbot = wrong.r_xtop;
607     else goto tryY;  /* Bad material overlaps containedArea in x. */
608     selFindChunk(plane, wrongTypes, &smaller, containedArea,
609 	    bestMin, bestMax, bestChunk, level + 1);
610 
611 
612     /* Also try reducing the y-range to see if that works better. */
613 
614     tryY: smaller = *searchArea;
615     if (wrong.r_ybot >= containedArea->r_ytop)
616 	smaller.r_ytop = wrong.r_ybot;
617     else if (wrong.r_ytop <= containedArea->r_ybot)
618 	smaller.r_ybot = wrong.r_ytop;
619     else return;  /* Bad material overlaps containedArea in y. */
620     selFindChunk(plane, wrongTypes, &smaller, containedArea,
621 	    bestMin, bestMax, bestChunk, level + 1);
622 }
623 
624 /* Search function to find split tiles in the area of interest.
625  */
626 
627 int
selSplitFunc(tile,cxp)628 selSplitFunc(tile, cxp)
629    Tile *tile;
630    TreeContext *cxp;
631 {
632     SearchContext *scx = cxp->tc_scx;
633     Rect *area = (Rect *) cxp->tc_filter->tf_arg;
634     Rect locarea;
635 
636     if (IsSplit(tile))
637     {
638         TiToRect(tile, &locarea);
639 	GeoTransRect(&scx->scx_trans, &locarea, area);
640         return 1;
641     }
642     return 0;
643 }
644 
645 /* This procedure is called for each tile of the wrong type in an
646  * area that is supposed to contain only tiles of other types.  It
647  * just returns the area of the wrong material and aborts the search.
648  */
649 
650 int
selChunkFunc(tile,wrong)651 selChunkFunc(tile, wrong)
652     Tile *tile;			/* The offending tile. */
653     Rect *wrong;		/* Place to store the tile's area. */
654 {
655     TiToRect(tile, wrong);
656     return 1;			/* Abort the search. */
657 }
658 
659 
660 /*
661  * ----------------------------------------------------------------------------
662  *
663  * SelectChunk --
664  *
665  * 	This procedure selects a single rectangular chunk of
666  *	homogeneous material.
667  *
668  * Results:
669  *	None.
670  *
671  * Side effects:
672  *	More material is added to the select cell and displayed
673  *	on the screen.  This procedure finds the largest rectangular
674  *	chunk of material "type" that contains the area given in
675  *	in scx.  The material need not all be in one cell, but it
676  *	must all be in cells that are expanded according to "xMask".
677  *	If pArea is given, the rectangle it points to is filled in
678  *	with the area of the chunk that was selected.
679  *
680  * ----------------------------------------------------------------------------
681  */
682 
683 void
SelectChunk(scx,type,xMask,pArea,less)684 SelectChunk(scx, type, xMask, pArea, less)
685     SearchContext *scx;		/* Area to tree-search for material.  The
686 				 * transform must map to root coordinates
687 				 * of the edit cell.
688 				 */
689     TileType type;		/* The type of material to be considered. */
690     int xMask;			/* Indicates window (or windows) where cells
691 				 * must be expanded for their contents to be
692 				 * considered.  0 means treat everything as
693 				 * expanded.
694 				 */
695     Rect *pArea;		/* If non-NULL, gets filled in with the area
696 				 * of the selection.
697 				 */
698     bool less;
699 {
700 #define INITIALSIZE 10
701     SearchContext newscx;
702     TileTypeBitMask wrongTypes, typeMask;
703     TileType ttype;
704     Rect bestChunk;
705     int bestMin, bestMax, width, height;
706     extern int selSplitFunc();		/* Forward reference. */
707 
708     /* If the source definition is changing, clear the old selection. */
709 
710     if (SelectRootDef != scx->scx_use->cu_def)
711     {
712 	if (SelectRootDef != NULL)
713 	    SelectClear();
714 	SelectRootDef = scx->scx_use->cu_def;
715 	SelSetDisplay(SelectUse, SelectRootDef);
716     }
717 
718     /* The chunk is computed iteratively.  First extract a small
719      * region (defined by INITIALSIZE) into Select2Def.  Then find
720      * the largest chunk in the region.  If the chunk touches a
721      * side of the region, then extract a larger region and try
722      * again.  Keep making the region larger and larger until we
723      * eventually find a region that completely contains the chunk
724      * with space left over around the edges.
725      */
726 
727     UndoDisable();
728     TTMaskSetOnlyType(&typeMask, type);
729 
730     /* Stacked types containing "type" need to be added to the mask */
731     if (DBIsContact(type)) DBMaskAddStacking(&typeMask);
732 
733     TTMaskCom2(&wrongTypes, &typeMask);
734 
735     newscx = *scx;
736 
737     /* If the tile under the area of interest is a split tile, 	*/
738     /* then we use that tile as the chunk.  This routine should	*/
739     /* work like the while() loop underneath, looking for the	*/
740     /* largest split tile, but this is a minor enhancement.	*/
741     /* *However*, if it is done, the functions			*/
742     /* DBCellCopyManhattanPaint()/dbCopyManhattanPaint() should */
743     /* be reconsidered.						*/
744 
745     if (DBTreeSrTiles(&newscx, &typeMask, 0, selSplitFunc,
746 	    (ClientData)&bestChunk) != 0)
747     {
748         goto chunkdone;
749     }
750 
751     bestMin = bestMax = 0;
752     bestChunk = GeoNullRect;
753 
754     GEO_EXPAND(&newscx.scx_area, INITIALSIZE, &newscx.scx_area);
755     while (TRUE)
756     {
757 	/* Extract a bunch of junk. */
758 
759 	DBCellClearDef(Select2Def);
760 	DBCellCopyManhattanPaint(&newscx, &typeMask, xMask, Select2Use);
761 
762 	/* Now find the best chunk in the area. */
763 
764 	selFindChunk(Select2Def->cd_planes[DBPlane(type)],
765 	    &wrongTypes, &newscx.scx_area, &scx->scx_area,
766 	    &bestMin, &bestMax, &bestChunk, 0);
767 	if (GEO_RECTNULL(&bestChunk))
768 	{
769 	    /* No chunk was found, so return. */
770 
771 	    UndoEnable();
772 	    if (pArea != NULL) *pArea = bestChunk;
773 	    return;
774 	}
775 
776 	/* If the chunk is completely inside the area we yanked, then we're
777 	 * done.
778 	 */
779 
780 	if (GEO_SURROUND_STRONG(&newscx.scx_area, &bestChunk)) break;
781 
782 	/* The chunk extends to the edge of the area.  Any place that the
783 	 * chunk touches an edge, move that edge out by a factor of two.
784 	 * Any place it doesn't touch, move the edge in to be just one
785 	 * unit out from the chunk.
786 	 */
787 
788 	width = newscx.scx_area.r_xtop - newscx.scx_area.r_xbot;
789 	height = newscx.scx_area.r_ytop - newscx.scx_area.r_ybot;
790 
791 	if (bestChunk.r_xbot == newscx.scx_area.r_xbot)
792 	    newscx.scx_area.r_xbot -= width;
793 	else newscx.scx_area.r_xbot = bestChunk.r_xbot - 1;
794 	if (bestChunk.r_ybot == newscx.scx_area.r_ybot)
795 	    newscx.scx_area.r_ybot -= height;
796 	else newscx.scx_area.r_ybot= bestChunk.r_ybot - 1;
797 	if (bestChunk.r_xtop == newscx.scx_area.r_xtop)
798 	    newscx.scx_area.r_xtop += width;
799 	else newscx.scx_area.r_xtop = bestChunk.r_xtop + 1;
800 	if (bestChunk.r_ytop == newscx.scx_area.r_ytop)
801 	    newscx.scx_area.r_ytop += height;
802 	else newscx.scx_area.r_ytop = bestChunk.r_ytop + 1;
803     }
804 
805 chunkdone:
806 
807     /* Flag the cell as a chunk selection so we can treat	*/
808     /* the contents differently when doing a move op.		*/
809 
810     SelectUse->cu_flags |= CU_SELECT_CHUNK;
811     UndoEnable();
812 
813     if (less)
814       {
815 	SelRemoveArea(&bestChunk, &typeMask, NULL);
816       }
817     else
818       {
819 	newscx.scx_area = bestChunk;
820 
821 	/* Remove any stacked contact types for SelectArea */
822 	if (DBIsContact(type))
823 	    TTMaskSetOnlyType(&typeMask, type);
824 
825 	SelectArea(&newscx, &typeMask, xMask, NULL);
826       }
827 
828     if (pArea != NULL) *pArea = bestChunk;
829 }
830 
831 /*
832  * ----------------------------------------------------------------------------
833  *
834  * SelectRegion --
835  *
836  * 	Select an entire region of material, no matter what its
837  *	shape.
838  *
839  * Results:
840  *	None.
841  *
842  * Side effects:
843  *	This procedure traces out the region consisting entirely
844  *	of type "type", and selects all that material.  The search
845  *	starts from "type" material under scx and continues outward
846  *	to get all material in all cells connected to the area under
847  *	scx by material of type "type".  If pArea is specified, then
848  *	the rectangle that it points to is filled in with the bounding
849  *	box of the region that was selected.
850  *
851  * ----------------------------------------------------------------------------
852  */
853 
854 void
SelectRegion(scx,type,xMask,pArea,less)855 SelectRegion(scx, type, xMask, pArea, less)
856     SearchContext *scx;		/* Area to tree-search for material.  The
857 				 * transform must map to EditRoot coordinates.
858 				 */
859     TileType type;		/* The type of material to be considered. */
860     int xMask;			/* Indicates window (or windows) where cells
861 				 * must be expanded for their contents to be
862 				 * considered.  0 means treat everything as
863 				 * expanded.
864 				 */
865     Rect *pArea;		/* If non-NULL, points to rectangle to be
866 				 * filled in with region's bounding box.
867 				 */
868     bool less;
869 {
870     TileTypeBitMask connections[TT_MAXTYPES];
871     int i;
872     SearchContext scx2;
873 
874     /* If the source definition is changing, clear the old selection. */
875 
876     if (SelectRootDef != scx->scx_use->cu_def)
877     {
878 	if (SelectRootDef != NULL)
879 	    SelectClear();
880 	SelectRootDef = scx->scx_use->cu_def;
881 	SelSetDisplay(SelectUse, SelectRootDef);
882     }
883 
884     /* Set up a connection table that allows only a particular type
885      * of material to be considered in the region.
886      */
887 
888     for (i=0; i<DBNumTypes; i+=1)
889 	TTMaskZero(&connections[i]);
890     TTMaskSetType(&connections[type], type);
891 
892     /* Clear out the temporary selection cell and yank all of the
893      * connected paint into it.
894      */
895 
896     UndoDisable();
897     DBCellClearDef(Select2Def);
898     DBTreeCopyConnect(scx, &connections[type], xMask, connections,
899 	    &TiPlaneRect, SelectDoLabels, Select2Use);
900     UndoEnable();
901 
902     /* Now transfer what we found into the main selection cell.  Pick
903      * up all the labels that correspond to the selected material.
904      */
905 
906     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
907     if (less)
908       {
909 	(void) SelRemoveSel2();
910       }
911     else
912       {
913 	scx2.scx_use = Select2Use;
914 	scx2.scx_area = Select2Def->cd_bbox;
915 	scx2.scx_trans = GeoIdentityTransform;
916 	DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits,
917 			0, SelectUse);
918 	DBCellCopyAllLabels(&scx2, &DBAllTypeBits, CU_DESCEND_SPECIAL, SelectUse,
919 			(Rect *) NULL);
920       }
921 
922     /* Display the new selection. */
923 
924     SelRememberForUndo(FALSE, SelectRootDef, &Select2Def->cd_bbox);
925 
926     DBReComputeBbox(SelectDef);
927     DBComputeUseBbox(SelectUse);
928 
929     DBWHLRedraw(SelectRootDef, &Select2Def->cd_extended, TRUE);
930     DBWAreaChanged(SelectDef, &Select2Def->cd_extended, DBW_ALLWINDOWS,
931 	 &DBAllButSpaceBits);
932 
933     if (pArea != NULL) *pArea = Select2Def->cd_extended;
934 }
935 
936 /*
937  * ----------------------------------------------------------------------------
938  *
939  * SelectNet --
940  *
941  * 	This procedure selects an entire electrically-connected net.
942  *
943  * Results:
944  *	None.
945  *
946  * Side effects:
947  *	Starting from material of type "type" under scx, this procedure
948  *	finds and highlights all material in all expanded cells that
949  *	is electrically-connected to the starting material through a
950  *	chain of expanded cells.  If pArea is specified, then the
951  *	rectangle that it points to is filled in with the bounding box
952  *	of the net that was selected.
953  *
954  * ----------------------------------------------------------------------------
955  */
956 
957 void
SelectNet(scx,type,xMask,pArea,less)958 SelectNet(scx, type, xMask, pArea, less)
959     SearchContext *scx;		/* Area to tree-search for material.  The
960 				 * transform must map to EditRoot coordinates.
961 				 */
962     TileType type;		/* The type of material to be considered. */
963     int xMask;			/* Indicates window (or windows) where cells
964 				 * must be expanded for their contents to be
965 				 * considered.  0 means treat everything as
966 				 * expanded.
967 				 */
968     Rect *pArea;		/* If non-NULL, points to rectangle to be
969 				 * filled in with net's bounding box.
970 				 */
971     bool less;			/* Whether to remove material from the
972 				 * selection using SelDeleteSel2
973 				 */
974 {
975     TileTypeBitMask mask;
976     SearchContext scx2;
977     Point savePoint = scx->scx_area.r_ll;
978 
979     /* If the source definition is changing, clear the old selection. */
980 
981     if (SelectRootDef != scx->scx_use->cu_def)
982     {
983 	if (SelectRootDef != NULL)
984 	    SelectClear();
985 	SelectRootDef = scx->scx_use->cu_def;
986 	SelSetDisplay(SelectUse, SelectRootDef);
987     }
988 
989     TTMaskZero(&mask);
990 
991     // Make sure that SelectNet() matches connection-compatible
992     // types with the type passed to the routine.
993 
994     // TTMaskSetType(&mask, type);
995     TTMaskSetMask(&mask, &DBConnectTbl[type]);
996 
997     UndoDisable();
998     DBCellClearDef(Select2Def);
999     DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
1000 	    &TiPlaneRect, SelectDoLabels, Select2Use);
1001     UndoEnable();
1002 
1003     /* Network undo method added by Nishit and Tim, July 8-10, 2004 */
1004     SelNetRememberForUndo(SelectRootDef, &savePoint, type, less, TRUE);
1005 
1006     /* Now transfer what we found into the main selection cell.  Pick
1007      * up all the labels that correspond to the selected material.
1008      */
1009 
1010     UndoDisable();
1011     if (less)
1012     {
1013 	(void) SelRemoveSel2();
1014     }
1015     else
1016     {
1017 	scx2.scx_use = Select2Use;
1018 	scx2.scx_area = Select2Def->cd_bbox;
1019 	scx2.scx_trans = GeoIdentityTransform;
1020 	DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits,
1021 			   0, SelectUse);
1022 	DBCellCopyAllLabels(&scx2, &DBAllTypeBits, CU_DESCEND_SPECIAL, SelectUse,
1023 			(Rect *) NULL);
1024     }
1025 
1026     /* Set the cell use flags to mark this as a net selection,	*/
1027     /* so we can treat it differently when it comes time to	*/
1028     /* unselect it.						*/
1029 
1030     SelectUse->cu_flags |= CU_SELECT_NET;
1031     UndoEnable();
1032 
1033     DBReComputeBbox(SelectDef);
1034     DBComputeUseBbox(SelectUse);
1035 
1036     DBWHLRedraw(SelectRootDef, &Select2Def->cd_extended, TRUE);
1037     DBWAreaChanged(SelectDef, &Select2Def->cd_extended, DBW_ALLWINDOWS,
1038 	&DBAllButSpaceBits);
1039 
1040     if (pArea != NULL) *pArea = Select2Def->cd_extended;
1041 }
1042 
1043 /*
1044  * ----------------------------------------------------------------------------
1045  *
1046  * SelectCell --
1047  *
1048  * 	Select a subcell by making a copy of it in the __SELECT__ cell.
1049  *
1050  * Results:
1051  *	None.
1052  *
1053  * Side effects:
1054  *	The given use is copied into the selection.  If replace is TRUE,
1055  *	then the last subcell to be selected via this procedure is
1056  *	deselected.
1057  *
1058  * ----------------------------------------------------------------------------
1059  */
1060 
1061 void
SelectCell(use,rootDef,trans,replace)1062 SelectCell(use, rootDef, trans, replace)
1063     CellUse *use;		/* Cell use to be selected. */
1064     CellDef *rootDef;		/* Root definition of window in which selection
1065 				 * is being made.
1066 				 */
1067     Transform *trans;		/* Transform from the coordinates of use's
1068 				 * definition to the coordinates of rootDef.
1069 				 */
1070     bool replace;		/* TRUE means deselect the last cell selected
1071 				 * by this procedure, if it's still selected.
1072 				 */
1073 {
1074     CellUse *newUse;
1075 
1076     /* If the source definition is changing, clear the old selection. */
1077 
1078     if (SelectRootDef != rootDef)
1079     {
1080 	if (SelectRootDef != NULL)
1081 	    SelectClear();
1082 	SelectRootDef = rootDef;
1083 	SelSetDisplay(SelectUse, SelectRootDef);
1084     }
1085 
1086     /* Deselect the last cell selected, if requested. */
1087 
1088     if (replace && (selectLastUse != NULL))
1089     {
1090 	Rect area;
1091 
1092 	SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1093 	area = selectLastUse->cu_bbox;
1094 	DBUnLinkCell(selectLastUse, SelectDef);
1095 	DBDeleteCell(selectLastUse);
1096 	(void) DBCellDeleteUse(selectLastUse);
1097 	SelRememberForUndo(FALSE, SelectRootDef, &area);
1098 	DBWHLRedraw(SelectRootDef, &area, TRUE);
1099 	selectLastUse = (CellUse *)NULL;
1100     }
1101 
1102     /* When creating a new use, try to re-use the id from the old
1103      * one.  Only create a new one if the old id can't be used.
1104      */
1105 
1106     newUse = DBCellNewUse(use->cu_def, (char *) use->cu_id);
1107     if (!DBLinkCell(newUse, SelectDef))
1108     {
1109 	freeMagic((char *) newUse->cu_id);
1110 	newUse->cu_id = NULL;
1111 	(void) DBLinkCell(newUse, SelectDef);
1112     }
1113 
1114     DBSetArray(use, newUse);
1115     DBSetTrans(newUse, trans);
1116     newUse->cu_expandMask = use->cu_expandMask;
1117     newUse->cu_flags = use->cu_flags;
1118 
1119     /* If this cell is already selected, there's nothing more to do.
1120      * Since we didn't change the selection here, be sure NOT to remember
1121      * it for future deselection!
1122      */
1123 
1124     if (DBCellFindDup(newUse, SelectDef) != NULL)
1125     {
1126 	DBUnLinkCell(newUse, SelectDef);
1127 	(void) DBCellDeleteUse(newUse);
1128 	selectLastUse = (CellUse *) NULL;
1129 	return;
1130     }
1131 
1132     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1133     DBPlaceCell(newUse, SelectDef);
1134     selectLastUse = newUse;
1135 
1136     SelRememberForUndo(FALSE, SelectRootDef, &newUse->cu_bbox);
1137     DBReComputeBbox(SelectDef);
1138     DBWHLRedraw(SelectRootDef, &newUse->cu_bbox, TRUE);
1139     DBWAreaChanged(SelectDef, &newUse->cu_bbox, DBW_ALLWINDOWS,
1140 	&DBAllButSpaceBits);
1141 }
1142 
1143 /*
1144  * ----------------------------------------------------------------------------
1145  *
1146  * SelectAndCopy1 --
1147  *
1148  *	This procedure takes the contents of SelectDef,  and makes a
1149  *	copy of them in the edit cell.  Unlike SelectAndCopy2, the
1150  *	original selection is unchanged, and SelectDef is not cleared.
1151  *	This allows the implementation of "drag and drop" selections.
1152  *
1153  * Results:
1154  *	None.
1155  *
1156  * Side effects:
1157  *	The selection is augmented with what's in Select2Def.  The caller
1158  *	should normally have cleared the selection before calling us.
1159  *	The edit cell is modified to include everything that was in
1160  *	Select2Def.
1161  *
1162  * ----------------------------------------------------------------------------
1163  */
1164 
1165 void
SelectAndCopy1()1166 SelectAndCopy1()
1167 {
1168     SearchContext scx;
1169     Rect editArea;
1170     TileTypeBitMask mask;
1171 
1172     /* Just copy the information in Select2Def twice, once into the
1173      * edit cell and once into the main selection cell.
1174      */
1175 
1176     scx.scx_use = SelectUse;
1177     scx.scx_area = SelectUse->cu_bbox;
1178     GeoTransTrans(&SelectUse->cu_transform, &RootToEditTransform, &scx.scx_trans);
1179     TTMaskAndMask3(&mask, &DBAllButSpaceAndDRCBits, &DBActiveLayerBits);
1180     (void) DBCellCopyAllPaint(&scx, &mask, CU_DESCEND_SPECIAL, EditCellUse);
1181     (void) DBCellCopyAllLabels(&scx, &DBActiveLayerBits, CU_DESCEND_SPECIAL,
1182 		EditCellUse, (Rect *) NULL);
1183     (void) DBCellCopyAllCells(&scx, CU_DESCEND_SPECIAL, EditCellUse, (Rect *) NULL);
1184     GeoTransRect(&scx.scx_trans, &scx.scx_area, &editArea);
1185     DBAdjustLabels(EditCellUse->cu_def, &editArea);
1186     DBWAreaChanged(EditCellUse->cu_def, &editArea, DBW_ALLWINDOWS,
1187 	(TileTypeBitMask *) NULL);
1188     DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editArea);
1189     DBReComputeBbox(EditCellUse->cu_def);
1190 }
1191 
1192 /*
1193  * ----------------------------------------------------------------------------
1194  *
1195  * SelectAndCopy2 --
1196  *
1197  * 	This procedure is intended for use only within the selection
1198  *	module.  It takes what's in Select2Def, makes a copy of it in the
1199  *	edit cell, and makes the copy the selection.  It's used, for
1200  *	example, by the transformation and copying routines.
1201  *
1202  * Results:
1203  *	None.
1204  *
1205  * Side effects:
1206  *	The selection is augmented with what's in Select2Def.  The caller
1207  *	should normally have cleared the selection before calling us.
1208  *	The edit cell is modified to include everything that was in
1209  *	Select2Def.
1210  *
1211  * ----------------------------------------------------------------------------
1212  */
1213 
1214 void
SelectAndCopy2(newSourceDef)1215 SelectAndCopy2(newSourceDef)
1216     CellDef *newSourceDef;		/* The new selection is to be
1217 					 * associated with this cell in the
1218 					 * user's layout.
1219 					 */
1220 {
1221     SearchContext scx;
1222     Rect editArea, labelArea, expanded;
1223     int plane;
1224     int (*savedPaintPlane)();
1225     extern int selACPaintFunc();	/* Forward reference. */
1226     extern int selACCellFunc();
1227 
1228     /* Just copy the information in Select2Def twice, once into the
1229      * edit cell and once into the main selection cell.
1230      */
1231 
1232     scx.scx_use = Select2Use;
1233     scx.scx_area = Select2Use->cu_bbox;
1234     scx.scx_trans = RootToEditTransform;
1235     savedPaintPlane = DBNewPaintPlane(DBPaintPlaneActive);
1236     (void) DBCellCopyAllPaint(&scx, &DBAllButSpaceAndDRCBits, CU_DESCEND_SPECIAL,
1237 		EditCellUse);
1238     DBNewPaintPlane(savedPaintPlane);
1239     (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL, EditCellUse,
1240 		(Rect *) NULL);
1241     (void) DBCellCopyAllCells(&scx, CU_DESCEND_SPECIAL, EditCellUse, (Rect *) NULL);
1242     GeoTransRect(&scx.scx_trans, &scx.scx_area, &editArea);
1243 
1244     DBAdjustLabels(EditCellUse->cu_def, &editArea);
1245     DBWAreaChanged(EditCellUse->cu_def, &editArea, DBW_ALLWINDOWS,
1246 	(TileTypeBitMask *) NULL);
1247     DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editArea);
1248     DBReComputeBbox(EditCellUse->cu_def);
1249 
1250     SelectRootDef = newSourceDef;
1251     SelSetDisplay(SelectUse, SelectRootDef);
1252 
1253     SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
1254     scx.scx_trans = GeoIdentityTransform;
1255 
1256     /* In copying stuff into SelectUse, we have to be careful.  The problem
1257      * is that the stuff now in the edit cell may have switched layers.
1258      * (for example, Select2Def might have diff, which got painted
1259      * over poly in the edit cell to form transistor).  As a result, we
1260      * use Select2Def to figure out what areas of what planes to put into
1261      * SelectUse, but use the actual tile types from the edit cell.
1262      */
1263 
1264     for (plane = PL_SELECTBASE; plane < DBNumPlanes; plane++)
1265     {
1266 	(void) DBSrPaintArea((Tile *) NULL, Select2Def->cd_planes[plane],
1267 		&TiPlaneRect, &DBAllButSpaceAndDRCBits, selACPaintFunc,
1268 		(ClientData) plane);
1269 	DBMergeNMTiles(Select2Def->cd_planes[plane], &TiPlaneRect,
1270 		(PaintUndoInfo *)NULL);
1271     }
1272 
1273     (void) DBCellCopyAllLabels(&scx, &DBAllTypeBits, CU_DESCEND_SPECIAL,
1274 		SelectUse, NULL);
1275 
1276     /* We also have to be careful about copying subcells into the
1277      * main selection cell.  It might not have been possible to copy
1278      * a subcell into the edit cell (above), because the copying
1279      * would have formed a circularity.  In that case, we need to
1280      * drop that subcell from the new selection.  The code below just
1281      * copies those that are still in the edit cell.
1282      */
1283 
1284     (void) SelEnumCells(TRUE, (bool *) NULL, &scx, selACCellFunc,
1285 	    (ClientData) NULL);
1286 
1287     DBReComputeBbox(SelectDef);
1288     DBComputeUseBbox(SelectUse);
1289 
1290     /* A little hack here:  don't do explicit redisplay of the selection,
1291      * or record a very large redisplay area for undo-ing.  It's not
1292      * necessary since the layout redisplay also redisplays the highlights.
1293      * If we do it too, then we're just double-displaying and wasting
1294      * time.  (note: must record something for undo-ing in order to get
1295      * SelectRootDef set right... just don't pass a redisplay area).
1296      */
1297 
1298     SelRememberForUndo(FALSE, SelectRootDef, (Rect *) NULL);
1299     DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS,
1300 	(TileTypeBitMask *) NULL);
1301 }
1302 
1303 /* Structure to hold information about an edit area, which may be
1304  * a triangular region.
1305  */
1306 typedef struct {
1307     Rect *editClip;
1308     TileType ttype;
1309 } acparg;
1310 
1311 /* Utility function: for each tile, copy information over its area from
1312  * the given edit cell plane to SelectDef.  Always return 0 to keep the
1313  * search alive.
1314  */
1315 
1316 int
selACPaintFunc(tile,plane)1317 selACPaintFunc(tile, plane)
1318     Tile *tile;			/* Tile in Select2Def. */
1319     int plane;			/* Index of plane this tile came from. */
1320 {
1321     Rect area, editArea;
1322     acparg selACarg;
1323     int selACPaintFunc2();	/* Forward reference. */
1324 
1325     TiToRect(tile, &area);
1326     /* we want editClip in root coordinates. . . */
1327     selACarg.editClip = &area;
1328     GeoTransRect(&RootToEditTransform, &area, &editArea);
1329 
1330     selACarg.ttype = TiGetTypeExact(tile);
1331 
1332     if (IsSplit(tile))
1333     {
1334 	DBSrPaintNMArea((Tile *) NULL, EditCellUse->cu_def->cd_planes[plane],
1335 		selACarg.ttype, &editArea, &DBAllButSpaceAndDRCBits,
1336 		selACPaintFunc2, (ClientData) &selACarg);
1337     }
1338     else
1339 	(void) DBSrPaintArea((Tile *) NULL, EditCellUse->cu_def->cd_planes[plane],
1340 		&editArea, &DBAllButSpaceAndDRCBits, selACPaintFunc2,
1341 		(ClientData) &selACarg);
1342     return 0;
1343 }
1344 
1345 /* Second-level paint function:  just paint the overlap between
1346  * tile and editClip into SelectDef.
1347  *
1348  * This function is like dbCopyAllPaint() but differs just enough
1349  * that a separate function is required.  However, much of the code
1350  * could be shared between the two functions if it were properly
1351  * broken out into subroutines.
1352  */
1353 
1354 int
selACPaintFunc2(tile,selACarg)1355 selACPaintFunc2(tile, selACarg)
1356     Tile *tile;			/* Tile in edit cell. */
1357     acparg *selACarg;		/* Contains edit-cell area to clip to
1358 				 * before painting into selection.
1359 				 */
1360 {
1361     Rect *editClip = selACarg->editClip;
1362     Rect area, selArea;
1363     TileType type = TiGetTypeExact(tile);
1364     TileTypeBitMask tmask, *rmask;
1365     TileType ttype, rtype;
1366     TileType dinfo = selACarg->ttype & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE);
1367 
1368     TiToRect(tile, &area);
1369     GeoTransRect(&EditToRootTransform, &area, &selArea);
1370 
1371     if ((dinfo & TT_DIAGONAL) || (type & TT_DIAGONAL))
1372     {
1373 	/* If the select area is triangular, then we need to	*/
1374 	/* clip in a more complicated manner.			*/
1375 	/* Likewise if the edit cell tile is triangular and	*/
1376 	/* the select area not.					*/
1377 
1378 	Point points[5];
1379 	Rect rrect, orect;
1380 	int np, i, j;
1381 
1382 	ttype = (selACarg->ttype & TT_SIDE) ? ((selACarg->ttype & TT_RIGHTMASK) >> 14) :
1383 		selACarg->ttype & TT_LEFTMASK;
1384 
1385 	if (type & TT_DIAGONAL)
1386 	    rtype = (type & TT_SIDE) ? SplitRightType(tile) :
1387 			SplitLeftType(tile);
1388 	else
1389 	    rtype = type;
1390 
1391 	if (rtype >= DBNumUserLayers)
1392 	{
1393 	    rmask = DBResidueMask(rtype);
1394 	    if (TTMaskHasType(rmask, ttype))
1395 		rtype = ttype;
1396 	}
1397 
1398 	TTMaskSetOnlyType(&tmask, rtype);
1399 
1400 	type = (dinfo & TT_SIDE) ? (rtype << 14) : rtype;
1401 	type |= dinfo;
1402 
1403 	if (dinfo & TT_DIAGONAL)
1404 	    GrClipTriangle(editClip, &selArea, TRUE, dinfo, points, &np);
1405 	else
1406 	    GrClipTriangle(&selArea, editClip, TRUE, type, points, &np);
1407 
1408 	if (np == 0)
1409 	    return 0;
1410 	if (np >= 3)
1411 	{
1412 	    for (i = 0; i < np; i++)
1413 	    {
1414 		j = (i + 1) % np;
1415 		if (points[i].p_x != points[j].p_x && points[i].p_y !=
1416 				points[j].p_y)
1417 		{
1418 		    /* Break out the triangle */
1419 		    rrect.r_xbot = points[i].p_x;
1420 		    rrect.r_xtop = points[j].p_x;
1421 		    rrect.r_ybot = points[i].p_y;
1422 		    rrect.r_ytop = points[j].p_y;
1423 		    GeoCanonicalRect(&rrect, &selArea);
1424 		    break;
1425 		}
1426 	    }
1427 	    if (i == np)  /* Exactly one Manhattan rectangle */
1428 	    {
1429 		rrect.r_xbot = points[0].p_x;
1430 		rrect.r_xtop = points[2].p_x;
1431 		rrect.r_ybot = points[0].p_y;
1432 		rrect.r_ytop = points[2].p_y;
1433 		GeoCanonicalRect(&rrect, &selArea);
1434 		type = rtype;
1435 	    }
1436 	    else if (np >= 4) /* Process extra rectangles in the area */
1437 	    {
1438 		/* "orect" is the bounding box of the polygon returned	*/
1439 		/* by ClipTriangle.					*/
1440 
1441 		orect.r_xtop = orect.r_xbot = points[0].p_x;
1442 		orect.r_ytop = orect.r_ybot = points[0].p_y;
1443 		for (i = 0; i < np; i++)
1444 		    GeoIncludePoint(&points[i], &orect);
1445 
1446 		/* Rectangle to left or right */
1447 		rrect.r_ybot = orect.r_ybot;
1448 		rrect.r_ytop = orect.r_ytop;
1449 		if (selArea.r_xbot > orect.r_xbot)
1450 		{
1451 		    rrect.r_xbot = orect.r_xbot;
1452 		    rrect.r_xtop = selArea.r_xbot;
1453 		}
1454 		else if (selArea.r_xtop < orect.r_xtop)
1455 		{
1456 		    rrect.r_xtop = orect.r_xtop;
1457 		    rrect.r_xbot = selArea.r_xtop;
1458 		}
1459 		else
1460 		    goto topbottom;
1461 
1462 		DBPaintValid(SelectDef, &rrect, &tmask, 0);
1463 topbottom:
1464 		/* Rectangle to top or bottom */
1465 		rrect.r_xbot = selArea.r_xbot;
1466 		rrect.r_xtop = selArea.r_xtop;
1467 		if (selArea.r_ybot > orect.r_ybot)
1468 		{
1469 		    rrect.r_ybot = orect.r_ybot;
1470 		    rrect.r_ytop = selArea.r_ybot;
1471 		}
1472 		else if (selArea.r_ytop < orect.r_ytop)
1473 		{
1474 		    rrect.r_ytop = orect.r_ytop;
1475 		    rrect.r_ybot = selArea.r_ytop;
1476 		}
1477 		else
1478 		    goto splitdone;
1479 
1480 		DBPaintValid(SelectDef, &rrect, &tmask, 0);
1481 	    }
1482 	}
1483     }
1484     else
1485     {
1486 	ttype = selACarg->ttype;
1487 
1488 	if (type & TT_DIAGONAL)
1489 	    rtype = (type & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
1490 	else
1491 	    rtype = type;
1492 
1493 	if (rtype >= DBNumUserLayers)
1494 	{
1495 	    rmask = DBResidueMask(rtype);
1496 	    if (TTMaskHasType(rmask, ttype))
1497 		rtype = ttype;
1498 	}
1499 	TTMaskSetOnlyType(&tmask, rtype);
1500     }
1501     GeoClip(&selArea, editClip);	/* editClip already in root coords */
1502 
1503 splitdone:
1504     DBPaintValid(SelectDef, &selArea, &tmask, type);
1505     return 0;
1506 }
1507 
1508 /* Cell search function:  invoked for each subcell in Select2Def that's
1509  * also in the edit cell.  Make a copy of the cell in SelectDef.
1510  */
1511 
1512 int
selACCellFunc(selUse,realUse)1513 selACCellFunc(selUse, realUse)
1514     CellUse *selUse;		/* Use to be copied into SelectDef.  This
1515 				 * is the instance inside Select2Def.
1516 				 */
1517     CellUse *realUse;		/* The cellUse (in the edit cell) corresponding
1518 				 * to selUse.  We need this in order to use its
1519 				 * instance id and expand mask in the selection.
1520 				 */
1521 {
1522     CellUse *newUse;
1523 
1524     newUse = DBCellNewUse(selUse->cu_def, realUse->cu_id);
1525     if (!DBLinkCell(newUse, SelectDef))
1526     {
1527 	freeMagic((char *) newUse->cu_id);
1528 	newUse->cu_id = NULL;
1529 	(void) DBLinkCell(newUse, SelectDef);
1530     }
1531     newUse->cu_expandMask = realUse->cu_expandMask;
1532     newUse->cu_flags = realUse->cu_flags;
1533     DBSetArray(selUse, newUse);
1534     DBSetTrans(newUse, &selUse->cu_transform);
1535     DBPlaceCell(newUse, SelectDef);
1536     return 0;
1537 }
1538 
1539