On Wed, 2011-05-11 at 11:43 +0100, Peter Clifton wrote: > I've attached it here in case it helps you get started. (Now attached!) -- Peter Clifton Electrical Engineering Division, Engineering Department, University of Cambridge, 9, JJ Thomson Avenue, Cambridge CB3 0FA Tel: +44 (0)7729 980173 - (No signal in the lab!) Tel: +44 (0)1223 748328 - (Shared lab phone, ask for me)
/* PolyCombine plug-in for PCB
Copyright (C) 2010 Peter Clifton <pcjc2@xxxxxxxxx>
Licensed under the terms of the GNU General Public License, version 2.
Compile like this:
gcc -I$HOME/pcbsrc/git/src -I$HOME/pcbsrc/git -O2 -shared polycombine.c -o polycombine.so
The resulting polycombine.so goes in $HOME/.pcb/plugins/polycombine.so.
Usage: PolyCombine()
The selected polygons are combined together according to the ordering of their points.
*/
#include <stdio.h>
#include <math.h>
#include "global.h"
#include "data.h"
#include "macro.h"
#include "create.h"
#include "remove.h"
#include "hid.h"
#include "error.h"
#include "rtree.h"
#include "polygon.h"
#include "polyarea.h"
#include "assert.h"
#include "strflags.h"
#include "find.h"
#include "misc.h"
#include "draw.h"
static POLYAREA *
original_poly (PolygonType * p, bool *forward)
{
PLINE *contour = NULL;
POLYAREA *np = NULL;
Cardinal n;
Vector v;
int hole = 0;
*forward = true;
if ((np = poly_Create ()) == NULL)
return NULL;
/* first make initial polygon contour */
for (n = 0; n < p->PointN; n++)
{
/* No current contour? Make a new one starting at point */
/* (or) Add point to existing contour */
v[0] = p->Points[n].X;
v[1] = p->Points[n].Y;
if (contour == NULL)
{
if ((contour = poly_NewContour (v)) == NULL)
return NULL;
}
else
{
poly_InclVertex (contour->head.prev, poly_CreateNode (v));
}
/* Is current point last in contour? If so process it. */
if (n == p->PointN - 1 ||
(hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1))
{
poly_PreContour (contour, TRUE);
/* Log the direction in which the outer contour was specified */
if (hole == 0)
*forward = (contour->Flags.orient == PLF_DIR);
/* make sure it is a positive contour (outer) or negative (hole) */
if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR))
poly_InvContour (contour);
assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR));
poly_InclContour (np, contour);
contour = NULL;
assert (poly_Valid (np));
hole++;
}
}
return np;
}
typedef struct poly_tree poly_tree;
struct poly_tree {
PolygonType *polygon;
bool forward;
POLYAREA *polyarea;
poly_tree *parent;
poly_tree *child;
poly_tree *prev;
poly_tree *next;
};
/* ______
* ___________________|_ P6 | +P1 ____ +P6
* | P1 | | | |
* | _____ ____ |_|____| -P2 ____ -P4 ____ -P5
* | |P2 | |P5 | | |
* | | [] | |____| | +P3
* | | P3 | |
* | |_____| |
* | |
* | ___ |
* | |P4 | |
* | |___| |
* | |
* |_____________________|
*
* As we encounter each polygon, it gets a record. We need to check
* whether it contains any of the polygons existing in our tree. If
* it does, it will become the parent of them. (Check breadth first).
*
* When processing, work top down (breadth first), although if the
* contours can be assumed not to overlap, we can drill down in this
* order: P1, P2, P3, P4, P5, P6.
*/
static bool
PolygonContainsPolygon (POLYAREA *outer, POLYAREA *inner)
{
// int contours_isect;
/* Should check outer contours don't intersect? */
// contours_isect = Touching (outer, inner);
/* Cheat and assume simple single contour polygons for now */
// return contours_isect ?
// 0 : poly_ContourInContour (outer->contours, inner->contours);
return poly_ContourInContour (outer->contours, inner->contours);
}
static poly_tree *
insert_node_recursive (poly_tree *start_point, poly_tree *to_insert)
{
poly_tree *cur_node, *next = NULL;
// bool to_insert_isects_cur_node; /* Intersection */
bool to_insert_contains_cur_node; /* Containment */
bool cur_node_contains_to_insert; /* Containment */
bool placed_to_insert = false;
poly_tree *return_root = start_point;
if (start_point == NULL)
{
// printf ("start_point is NULL, so returning to_insert\n");
//to_insert->parent = !!; UNDEFINED
return to_insert;
}
/* Investigate the start point and its peers first */
for (cur_node = start_point; cur_node != NULL; cur_node = next)
{
next = cur_node->next;
// to_insert_isects_cur_node = IsPolygonInPolygon (to_insert->polygon, cur_node->polygon);
to_insert_contains_cur_node = PolygonContainsPolygon (to_insert->polyarea, cur_node->polyarea);
#if 0
printf ("Inspecting polygon %ld %s, curnode is %ld %s: to_insert_isects_cur_node = %d, to_insert_contains_cur_node = %i\n",
to_insert->polygon->ID,
to_insert->forward ? "FWD" : "BWD",
cur_node->polygon->ID,
cur_node->forward ? "FWD" : "BWD",
to_insert_isects_cur_node,
to_insert_contains_cur_node);
if (to_insert_isects_cur_node) /* Place as peer of this node? */
{
}
#endif
if (to_insert_contains_cur_node) /* Should be a parent of this node */
{
/* Remove cur_node from its peers */
if (cur_node->prev)
cur_node->prev->next = cur_node->next;
if (cur_node->next)
cur_node->next->prev = cur_node->prev;
/* If we've not yet got a home, insert the to_insert node where cur_node was previously */
if (!placed_to_insert)
{
to_insert->parent = cur_node->parent;
to_insert->next = cur_node->next;
to_insert->prev = cur_node->prev;
if (to_insert->prev)
to_insert->prev->next = to_insert;
if (to_insert->next)
to_insert->next->prev = to_insert;
placed_to_insert = true;
if (cur_node == start_point)
return_root = to_insert;
}
/* Prepend cur_node to our list of children */
cur_node->parent = to_insert;
cur_node->prev = NULL;
cur_node->next = to_insert->child;
if (to_insert->child)
to_insert->child->prev = cur_node;
to_insert->child = cur_node;
}
}
if (placed_to_insert)
{
// printf ("Returning new root %ld\n", return_root->polygon->ID);
return return_root;
}
// return (to_insert->parent == NULL) ? to_insert : to_insert->parent;
/* Ok, so we still didn't find anywhere which the to_insert contour contained,
* we need to start looking at the children of the start_point and its peers.
*/
// printf ("Looking at child nodes of the start_point\n");
/* Investigate the start point and its peers first */
for (cur_node = start_point; cur_node != NULL; cur_node = next)
{
next = cur_node->next;
cur_node_contains_to_insert = PolygonContainsPolygon (cur_node->polyarea, to_insert->polyarea);
#if 0
printf ("Inspecting polygon %ld, curnode is %ld: cur_node_contains_to_insert = %d\n",
to_insert->polygon->ID, cur_node->polygon->ID,
cur_node_contains_to_insert);
#endif
/* Need to look at the child, ONLY if we know it engulfs our to_insert polygon */
if (cur_node_contains_to_insert)
{
/* Can't set the parent within the call, so: */
to_insert->parent = cur_node;
cur_node->child = insert_node_recursive (cur_node->child, to_insert);
return start_point;
//return cur_node->parent;
}
}
// if (!placed_to_insert)
/* prepend to_insert polygon to peer of start_point ? */
// printf ("Prepending as peer to start_poly\n");
to_insert->parent = start_point->parent;
to_insert->prev = NULL;
to_insert->next = start_point;
to_insert->next->prev = to_insert;
return to_insert;
}
static POLYAREA *
compute_polygon_recursive (poly_tree *root, POLYAREA *accumulate)
{
POLYAREA *res;
poly_tree *cur_node;
for (cur_node = root; cur_node != NULL; cur_node = cur_node->next)
{
/* Process this element */
// printf ("Processing node %ld %s\n", cur_node->polygon->ID, cur_node->forward ? "FWD" : "BWD");
poly_Boolean_free (accumulate, cur_node->polyarea, &res, cur_node->forward ? PBO_UNITE : PBO_SUB);
accumulate = res;
/* And its children if it has them */
if (cur_node->child)
{
// printf ("Processing children\n");
accumulate = compute_polygon_recursive (cur_node->child, accumulate);
}
}
return accumulate;
}
static int
polycombine (int argc, char **argv, int x, int y)
{
POLYAREA *res;
bool forward;
bool outer;
POLYAREA *np;
POLYAREA *pa;
PLINE *pline;
VNODE *node;
PolygonType *Polygon;
LayerType *Layer = NULL;
poly_tree *root = NULL;
poly_tree *this_node;
/* First pass to combine the forward and backward contours */
VISIBLEPOLYGON_LOOP (PCB->Data);
{
if (!TEST_FLAG (SELECTEDFLAG, polygon))
continue;
/* Pick the layer of the first polygon we find selected */
if (Layer == NULL)
Layer = layer;
/* Only combine polygons on the same layer */
if (Layer != layer)
continue;
np = original_poly (polygon, &forward);
/* Build a poly_tree record */
this_node = calloc (1, sizeof (poly_tree));
this_node->polygon = polygon;
this_node->forward = forward;
this_node->polyarea = np;
/* Check where we should place the node in the tree */
root = insert_node_recursive (root, this_node);
//RemovePolygon (layer, polygon);
}
ENDALL_LOOP;
/* Now perform a traversal of the tree, computing a polygon */
res = compute_polygon_recursive (root, NULL);
SaveUndoSerialNumber ();
/* Second pass to remove the input polygons */
VISIBLEPOLYGON_LOOP (PCB->Data);
{
if (!TEST_FLAG (SELECTEDFLAG, polygon))
continue;
/* Only combine polygons on the same layer */
if (Layer != layer)
continue;
RemovePolygon (layer, polygon);
}
ENDALL_LOOP;
/* Now de-construct the resulting polygon into raw PCB polygons */
PolyToPolygonsOnLayer (PCB->Data, Layer, res,
string_to_pcbflags ("clearpoly", NULL));
RestoreUndoSerialNumber ();
IncrementUndoSerialNumber ();
Draw ();
return 0;
}
static HID_Action polycombine_action_list[] = {
{"PolyCombine", "???", polycombine,
NULL, NULL}
};
REGISTER_ACTIONS (polycombine_action_list)
void
pcb_plugin_init()
{
register_polycombine_action_list();
}
Attachment:
signature.asc
Description: This is a digitally signed message part
_______________________________________________ geda-user mailing list geda-user@xxxxxxxxxxxxxx http://www.seul.org/cgi-bin/mailman/listinfo/geda-user