Exemple #1
0
/* ---------------------------------------------------------------------------
 * searches a polygon-point on all layers that are switched on
 * in layerstack order
 */
static bool
SearchPointByLocation (int locked, LayerTypePtr * Layer,
		       PolygonTypePtr * Polygon, PointTypePtr * Point)
{
  double d, least;
  bool found = false;

  least = SearchRadius + MAX_POLYGON_POINT_DISTANCE;
  *Layer = SearchLayer;
  POLYGON_LOOP (*Layer);
  {
    POLYGONPOINT_LOOP (polygon);
    {
      d = Distance (point->X, point->Y, PosX, PosY);
      if (d < least)
	{
	  least = d;
	  *Polygon = polygon;
	  *Point = point;
	  found = true;
	}
    }
    END_LOOP;
  }
  END_LOOP;
  if (found)
    return (true);
  return (false);
}
Exemple #2
0
/* ---------------------------------------------------------------------------
 * get next slot for a polygon object, allocates memory if necessary
 */
PolygonTypePtr
GetPolygonMemory (LayerTypePtr Layer)
{
  PolygonTypePtr polygon = Layer->Polygon;

  /* realloc new memory if necessary and clear it */
  if (Layer->PolygonN >= Layer->PolygonMax)
    {
      Layer->PolygonMax += STEP_POLYGON;
      if (Layer->polygon_tree)
	r_destroy_tree (&Layer->polygon_tree);
      polygon = MyRealloc (polygon, Layer->PolygonMax * sizeof (PolygonType),
			   "GetPolygonMemory()");
      Layer->Polygon = polygon;
      memset (polygon + Layer->PolygonN, 0,
	      STEP_POLYGON * sizeof (PolygonType));
      Layer->polygon_tree = r_create_tree (NULL, 0, 0);
      POLYGON_LOOP (Layer);
      {
	r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0);
      }
      END_LOOP;
    }
  return (polygon + Layer->PolygonN++);
}
Exemple #3
0
/* ---------------------------------------------------------------------------
 * draws all visible and attached objects of the pastebuffer
 */
static void
XORDrawBuffer (BufferTypePtr Buffer)
{
  Cardinal i;
  LocationType x, y;

  /* set offset */
  x = Crosshair.X - Buffer->X;
  y = Crosshair.Y - Buffer->Y;

  /* draw all visible layers */
  for (i = 0; i < max_copper_layer + 2; i++)
    if (PCB->Data->Layer[i].On)
      {
	LayerTypePtr layer = &Buffer->Data->Layer[i];

	LINE_LOOP (layer);
	{
/*
				XORDrawAttachedLine(x +line->Point1.X,
					y +line->Point1.Y, x +line->Point2.X,
					y +line->Point2.Y, line->Thickness);
*/
	  gui->draw_line (Crosshair.GC,
			  x + line->Point1.X, y + line->Point1.Y,
			  x + line->Point2.X, y + line->Point2.Y);
	}
	END_LOOP;
	ARC_LOOP (layer);
	{
	  gui->draw_arc (Crosshair.GC,
			 x + arc->X,
			 y + arc->Y,
			 arc->Width,
			 arc->Height, arc->StartAngle, arc->Delta);
	}
	END_LOOP;
	TEXT_LOOP (layer);
	{
	  BoxTypePtr box = &text->BoundingBox;
	  gui->draw_rect (Crosshair.GC,
			  x + box->X1, y + box->Y1, x + box->X2, y + box->Y2);
	}
	END_LOOP;
	/* the tmp polygon has n+1 points because the first
	 * and the last one are set to the same coordinates
	 */
	POLYGON_LOOP (layer);
	{
	  XORPolygon (polygon, x, y);
	}
	END_LOOP;
      }

  /* draw elements if visible */
  if (PCB->PinOn && PCB->ElementOn)
    ELEMENT_LOOP (Buffer->Data);
  {
    if (FRONT (element) || PCB->InvisibleObjectsOn)
      XORDrawElement (element, x, y);
  }
  END_LOOP;

  /* and the vias, move offset by thickness/2 */
  if (PCB->ViaOn)
    VIA_LOOP (Buffer->Data);
  {
    gui->draw_arc (Crosshair.GC,
		   x + via->X, y + via->Y,
		   via->Thickness / 2, via->Thickness / 2, 0, 360);
  }
  END_LOOP;
}
Exemple #4
0
/* ---------------------------------------------------------------------------
 * free memory used by data struct
 */
void
FreeDataMemory (DataType *data)
{
  LayerType *layer;
  int i;

  if (data == NULL)
    return;

  VIA_LOOP (data);
  {
    free (via->Name);
  }
  END_LOOP;
  g_list_free_full (data->Via, (GDestroyNotify)FreeVia);
  ELEMENT_LOOP (data);
  {
    FreeElementMemory (element);
  }
  END_LOOP;
  g_list_free_full (data->Element, (GDestroyNotify)FreeElement);
  g_list_free_full (data->Rat, (GDestroyNotify)FreeRat);

  for (layer = data->Layer, i = 0; i < MAX_LAYER + 2; layer++, i++)
    {
      FreeAttributeListMemory (&layer->Attributes);
      TEXT_LOOP (layer);
      {
        free (text->TextString);
      }
      END_LOOP;
      if (layer->Name)
        free (layer->Name);
      LINE_LOOP (layer);
      {
        if (line->Number)
          free (line->Number);
      }
      END_LOOP;
      g_list_free_full (layer->Line, (GDestroyNotify)FreeLine);
      g_list_free_full (layer->Arc, (GDestroyNotify)FreeArc);
      g_list_free_full (layer->Text, (GDestroyNotify)FreeText);
      POLYGON_LOOP (layer);
      {
        FreePolygonMemory (polygon);
      }
      END_LOOP;
      g_list_free_full (layer->Polygon, (GDestroyNotify)FreePolygon);
      if (layer->line_tree)
        r_destroy_tree (&layer->line_tree);
      if (layer->arc_tree)
        r_destroy_tree (&layer->arc_tree);
      if (layer->text_tree)
        r_destroy_tree (&layer->text_tree);
      if (layer->polygon_tree)
        r_destroy_tree (&layer->polygon_tree);
    }

  if (data->element_tree)
    r_destroy_tree (&data->element_tree);
  for (i = 0; i < MAX_ELEMENTNAMES; i++)
    if (data->name_tree[i])
      r_destroy_tree (&data->name_tree[i]);
  if (data->via_tree)
    r_destroy_tree (&data->via_tree);
  if (data->pin_tree)
    r_destroy_tree (&data->pin_tree);
  if (data->pad_tree)
    r_destroy_tree (&data->pad_tree);
  if (data->rat_tree)
    r_destroy_tree (&data->rat_tree);
  /* clear struct */
  memset (data, 0, sizeof (DataType));
}
Exemple #5
0
/* ---------------------------------------------------------------------------
 * pastes the contents of the buffer to the layout. Only visible objects
 * are handled by the routine.
 */
bool
CopyPastebufferToLayout (Coord X, Coord Y)
{
  Cardinal i;
  bool changed = false;

#ifdef DEBUG
  printf("Entering CopyPastebufferToLayout.....\n");
#endif

  /* set movement vector */
  DeltaX = X - PASTEBUFFER->X, DeltaY = Y - PASTEBUFFER->Y;

  /* paste all layers */
  for (i = 0; i < max_copper_layer + 2; i++)
    {
      LayerType *sourcelayer = &PASTEBUFFER->Data->Layer[i];
      LayerType *destlayer = LAYER_PTR (i);

      if (destlayer->On)
	{
	  changed = changed ||
	    (sourcelayer->LineN != 0) ||
	    (sourcelayer->ArcN != 0) ||
	    (sourcelayer->PolygonN != 0) || (sourcelayer->TextN != 0);
	  LINE_LOOP (sourcelayer);
	  {
	    CopyLine (destlayer, line);
	  }
	  END_LOOP;
	  ARC_LOOP (sourcelayer);
	  {
	    CopyArc (destlayer, arc);
	  }
	  END_LOOP;
	  TEXT_LOOP (sourcelayer);
	  {
	    CopyText (destlayer, text);
	  }
	  END_LOOP;
	  POLYGON_LOOP (sourcelayer);
	  {
	    CopyPolygon (destlayer, polygon);
	  }
	  END_LOOP;
	}
    }

  /* paste elements */
  if (PCB->PinOn && PCB->ElementOn)
    {
      ELEMENT_LOOP (PASTEBUFFER->Data);
      {
#ifdef DEBUG
	printf("In CopyPastebufferToLayout, pasting element %s\n",
	      element->Name[1].TextString);
#endif
	if (FRONT (element) || PCB->InvisibleObjectsOn)
	  {
	    CopyElement (element);
	    changed = true;
	  }
      }
      END_LOOP;
    }

  /* finally the vias */
  if (PCB->ViaOn)
    {
      changed |= (PASTEBUFFER->Data->ViaN != 0);
      VIA_LOOP (PASTEBUFFER->Data);
      {
	CopyVia (via);
      }
      END_LOOP;
    }

  if (changed)
    {
      Draw ();
      IncrementUndoSerialNumber ();
    }

#ifdef DEBUG
  printf("  .... Leaving CopyPastebufferToLayout.\n");
#endif

  return (changed);
}
Exemple #6
0
/*---------------------------------------------------------------------------
 *
 * convert buffer contents into an element
 */
bool
ConvertBufferToElement (BufferType *Buffer)
{
  ElementType *Element;
  Cardinal group;
  Cardinal pin_n = 1;
  bool hasParts = false, crooked = false;
  int onsolder;
  bool warned = false;

  if (Buffer->Data->pcb == 0)
    Buffer->Data->pcb = PCB;

  Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (),
			      NULL, NULL, NULL, PASTEBUFFER->X,
			      PASTEBUFFER->Y, 0, 100,
			      MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
			      false);
  if (!Element)
    return (false);
  VIA_LOOP (Buffer->Data);
  {
    char num[8];
    if (via->Mask < via->Thickness)
      via->Mask = via->Thickness + 2 * MASKFRAME;
    if (via->Name)
      CreateNewPin (Element, via->X, via->Y, via->Thickness,
		    via->Clearance, via->Mask, via->DrillingHole,
		    NULL, via->Name, MaskFlags (via->Flags,
						VIAFLAG | NOCOPY_FLAGS |
						SELECTEDFLAG | WARNFLAG));
    else
      {
	sprintf (num, "%d", pin_n++);
	CreateNewPin (Element, via->X, via->Y, via->Thickness,
		      via->Clearance, via->Mask, via->DrillingHole,
		      NULL, num, MaskFlags (via->Flags,
					    VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG
					    | WARNFLAG));
      }
    hasParts = true;
  }
  END_LOOP;

  for (onsolder = 0; onsolder < 2; onsolder ++)
    {
      int silk_layer;
      int onsolderflag;

      if ((!onsolder) == (!SWAP_IDENT))
	{
	  silk_layer = component_silk_layer;
	  onsolderflag = NOFLAG;
	}
      else
	{
	  silk_layer = solder_silk_layer;
	  onsolderflag = ONSOLDERFLAG;
	}

#define MAYBE_WARN() \
	  if (onsolder && !hasParts && !warned) \
	    { \
	      warned = true; \
	      Message \
		(_("Warning: All of the pads are on the opposite\n" \
		   "side from the component - that's probably not what\n" \
		   "you wanted\n")); \
	    } \

      /* get the component-side SM pads */
      group = GetLayerGroupNumberByNumber (silk_layer);
      GROUP_LOOP (Buffer->Data, group);
      {
	char num[8];
	LINE_LOOP (layer);
	{
	  sprintf (num, "%d", pin_n++);
	  CreateNewPad (Element, line->Point1.X,
			line->Point1.Y, line->Point2.X,
			line->Point2.Y, line->Thickness,
			line->Clearance,
			line->Thickness + line->Clearance, NULL,
			line->Number ? line->Number : num,
			MakeFlags (onsolderflag));
	  MAYBE_WARN();
	  hasParts = true;
	}
	END_LOOP;
	POLYGON_LOOP (layer);
	{
	  Coord x1, y1, x2, y2, w, h, t;

	  if (! polygon_is_rectangle (polygon))
	    {
	      crooked = true;
	      continue;
	    }

	  w = polygon->Points[2].X - polygon->Points[0].X;
	  h = polygon->Points[1].Y - polygon->Points[0].Y;
	  t = (w < h) ? w : h;
	  x1 = polygon->Points[0].X + t/2;
	  y1 = polygon->Points[0].Y + t/2;
	  x2 = x1 + (w-t);
	  y2 = y1 + (h-t);

	  sprintf (num, "%d", pin_n++);
	  CreateNewPad (Element,
			x1, y1, x2, y2, t,
			2 * Settings.Keepaway,
			t + Settings.Keepaway,
			NULL, num,
			MakeFlags (SQUAREFLAG | onsolderflag));
	  MAYBE_WARN();
	  hasParts = true;
	}
	END_LOOP;
      }
      END_LOOP;
    }

  /* now add the silkscreen. NOTE: elements must have pads or pins too */
  LINE_LOOP (&Buffer->Data->SILKLAYER);
  {
    if (line->Number && !NAMEONPCB_NAME (Element))
      NAMEONPCB_NAME (Element) = strdup (line->Number);
    CreateNewLineInElement (Element, line->Point1.X,
			    line->Point1.Y, line->Point2.X,
			    line->Point2.Y, line->Thickness);
    hasParts = true;
  }
  END_LOOP;
  ARC_LOOP (&Buffer->Data->SILKLAYER);
  {
    CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
			   arc->Height, arc->StartAngle, arc->Delta,
			   arc->Thickness);
    hasParts = true;
  }
  END_LOOP;
  if (!hasParts)
    {
      DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
      Message (_("There was nothing to convert!\n"
		 "Elements must have some silk, pads or pins.\n"));
      return (false);
    }
  if (crooked)
     Message (_("There were polygons that can't be made into pins!\n"
                "So they were not included in the element\n"));
  Element->MarkX = Buffer->X;
  Element->MarkY = Buffer->Y;
  if (SWAP_IDENT)
    SET_FLAG (ONSOLDERFLAG, Element);
  SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
  ClearBuffer (Buffer);
  MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
		      Element);
  SetBufferBoundingBox (Buffer);
  return (true);
}
Exemple #7
0
/* ---------------------------------------------------------------------------
 * free memory used by data struct
 */
void
FreeDataMemory (DataTypePtr Data)
{
  LayerTypePtr layer;
  int i;

  if (Data)
    {
      VIA_LOOP (Data);
      {
	MYFREE (via->Name);
      }
      END_LOOP;
      ELEMENT_LOOP (Data);
      {
	FreeElementMemory (element);
      }
      END_LOOP;

      for (layer = Data->Layer, i = 0; i < MAX_LAYER + 2; layer++, i++)
	{
	  FreeAttributeListMemory (&layer->Attributes);
	  TEXT_LOOP (layer);
	  {
	    MYFREE (text->TextString);
	  }
	  END_LOOP;
	  if (layer->Name)
	    MYFREE (layer->Name);
	  LINE_LOOP (layer);
	  {
	    if (line->Number)
	      MYFREE (line->Number);
	  }
	  END_LOOP;
	  MYFREE (layer->Line);
	  MYFREE (layer->Arc);
	  MYFREE (layer->Text);
	  POLYGON_LOOP (layer);
	  {
	    FreePolygonMemory (polygon);
	  }
	  END_LOOP;
	  MYFREE (layer->Polygon);
	  if (layer->line_tree)
	    r_destroy_tree (&layer->line_tree);
	  if (layer->arc_tree)
	    r_destroy_tree (&layer->arc_tree);
	  if (layer->text_tree)
	    r_destroy_tree (&layer->text_tree);
	  if (layer->polygon_tree)
	    r_destroy_tree (&layer->polygon_tree);
	}

      if (Data->element_tree)
	r_destroy_tree (&Data->element_tree);
      for (i = 0; i < MAX_ELEMENTNAMES; i++)
	if (Data->name_tree[i])
	  r_destroy_tree (&Data->name_tree[i]);
      if (Data->via_tree)
	r_destroy_tree (&Data->via_tree);
      if (Data->pin_tree)
	r_destroy_tree (&Data->pin_tree);
      if (Data->pad_tree)
	r_destroy_tree (&Data->pad_tree);
      if (Data->rat_tree)
	r_destroy_tree (&Data->rat_tree);
      /* clear struct */
      memset (Data, 0, sizeof (DataType));
    }
  else
    {
      fprintf (stderr, "Warning:  Tried to FreeDataMemory(null)\n");
    }
}
Exemple #8
0
/* ----------------------------------------------------------------------
 * selects/unselects all visible objects within the passed box
 * Flag determines if the block is to be selected or unselected
 * returns true if the state of any object has changed
 */
bool
SelectBlock (BoxTypePtr Box, bool Flag)
{
  bool changed = false;

  if (PCB->RatOn || !Flag)
    RAT_LOOP (PCB->Data);
  {
    if (LINE_IN_BOX ((LineTypePtr) line, Box) &&
	!TEST_FLAG (LOCKFLAG, line) && TEST_FLAG (SELECTEDFLAG, line) != Flag)
      {
	AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	if (PCB->RatOn)
	  DrawRat (line, 0);
	changed = true;
      }
  }
  END_LOOP;

  /* check layers */
  LAYER_LOOP(PCB->Data, max_copper_layer + 2);
  {
    if (layer == & PCB->Data->SILKLAYER)
      {
	if (! (PCB->ElementOn || !Flag))
	  continue;
      }
    else if (layer == & PCB->Data->BACKSILKLAYER)
      {
	if (! (PCB->InvisibleObjectsOn || !Flag))
	  continue;
      }
    else
      if (! (layer->On || !Flag))
	continue;

    LINE_LOOP (layer);
    {
      if (LINE_IN_BOX (line, Box)
	  && !TEST_FLAG (LOCKFLAG, line)
	  && TEST_FLAG (SELECTEDFLAG, line) != Flag)
	{
	  AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	  if (layer->On)
	    DrawLine (layer, line, 0);
	  changed = true;
	}
    }
    END_LOOP;
    ARC_LOOP (layer);
    {
      if (ARC_IN_BOX (arc, Box)
	  && !TEST_FLAG (LOCKFLAG, arc)
	  && TEST_FLAG (SELECTEDFLAG, arc) != Flag)
	{
	  AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, arc);
	  if (layer->On)
	    DrawArc (layer, arc, 0);
	  changed = true;
	}
    }
    END_LOOP;
    TEXT_LOOP (layer);
    {
      if (!Flag || TEXT_IS_VISIBLE(PCB, layer, text))
	{
	  if (TEXT_IN_BOX (text, Box)
	      && !TEST_FLAG (LOCKFLAG, text)
	      && TEST_FLAG (SELECTEDFLAG, text) != Flag)
	    {
	      AddObjectToFlagUndoList (TEXT_TYPE, layer, text, text);
	      ASSIGN_FLAG (SELECTEDFLAG, Flag, text);
	      if (TEXT_IS_VISIBLE(PCB, layer, text))
		DrawText (layer, text, 0);
	      changed = true;
	    }
	}
    }
    END_LOOP;
    POLYGON_LOOP (layer);
    {
      if (POLYGON_IN_BOX (polygon, Box)
	  && !TEST_FLAG (LOCKFLAG, polygon)
	  && TEST_FLAG (SELECTEDFLAG, polygon) != Flag)
	{
	  AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, polygon);
	  if (layer->On)
	    DrawPolygon (layer, polygon, 0);
	  changed = true;
	}
    }
    END_LOOP;
  }
  END_LOOP;

  /* elements */
  ELEMENT_LOOP (PCB->Data);
  {
    {
      bool gotElement = false;
      if ((PCB->ElementOn || !Flag)
	  && !TEST_FLAG (LOCKFLAG, element)
	  && ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT
	      || PCB->InvisibleObjectsOn))
	{
	  if (BOX_IN_BOX
	      (&ELEMENT_TEXT (PCB, element).BoundingBox, Box)
	      && !TEST_FLAG (LOCKFLAG, &ELEMENT_TEXT (PCB, element))
	      && TEST_FLAG (SELECTEDFLAG,
			    &ELEMENT_TEXT (PCB, element)) != Flag)
	    {
	      /* select all names of element */
	      ELEMENTTEXT_LOOP (element);
	      {
		AddObjectToFlagUndoList (ELEMENTNAME_TYPE,
					 element, text, text);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, text);
	      }
	      END_LOOP;
	      if (PCB->ElementOn)
		DrawElementName (element, 0);
	      changed = true;
	    }
	  if ((PCB->PinOn || !Flag) && ELEMENT_IN_BOX (element, Box))
	    if (TEST_FLAG (SELECTEDFLAG, element) != Flag)
	      {
		AddObjectToFlagUndoList (ELEMENT_TYPE,
					 element, element, element);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, element);
		PIN_LOOP (element);
		{
		  if (TEST_FLAG (SELECTEDFLAG, pin) != Flag)
		    {
		      AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
		      ASSIGN_FLAG (SELECTEDFLAG, Flag, pin);
		      if (PCB->PinOn)
			DrawPin (pin, 0);
		      changed = true;
		    }
		}
		END_LOOP;
		PAD_LOOP (element);
		{
		  if (TEST_FLAG (SELECTEDFLAG, pad) != Flag)
		    {
		      AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
		      ASSIGN_FLAG (SELECTEDFLAG, Flag, pad);
		      if (PCB->PinOn)
			DrawPad (pad, 0);
		      changed = true;
		    }
		}
		END_LOOP;
		if (PCB->PinOn)
		  DrawElement (element, 0);
		changed = true;
		gotElement = true;
	      }
	}
      if ((PCB->PinOn || !Flag) && !TEST_FLAG (LOCKFLAG, element) && !gotElement)
	{
	  PIN_LOOP (element);
	  {
	    if ((VIA_OR_PIN_IN_BOX (pin, Box)
		 && TEST_FLAG (SELECTEDFLAG, pin) != Flag))
	      {
		AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, pin);
		if (PCB->PinOn)
		  DrawPin (pin, 0);
		changed = true;
	      }
	  }
	  END_LOOP;
	  PAD_LOOP (element);
	  {
	    if (PAD_IN_BOX (pad, Box)
		&& TEST_FLAG (SELECTEDFLAG, pad) != Flag)
	      {
		AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, pad);
		if (PCB->PinOn)
		  DrawPad (pad, 0);
		changed = true;
	      }
	  }
	  END_LOOP;
	}
    }
  }
  END_LOOP;
  /* end with vias */
  if (PCB->ViaOn || !Flag)
    VIA_LOOP (PCB->Data);
  {
    if (VIA_OR_PIN_IN_BOX (via, Box)
	&& !TEST_FLAG (LOCKFLAG, via)
	&& TEST_FLAG (SELECTEDFLAG, via) != Flag)
      {
	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, via);
	if (PCB->ViaOn)
	  DrawVia (via, 0);
	changed = true;
      }
  }
  END_LOOP;
  if (changed)
    {
      Draw ();
      IncrementUndoSerialNumber ();
    }
  return (changed);
}