[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: gEDA-user: Logos and graphics.. [WAS: Re: Where is pcb-20100929 for Win32 ?]



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