/* --------------------------------------------------------------------------- * moves an element */ static void * MoveElement (ElementTypePtr Element) { bool didDraw = false; if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn)) { EraseElement (Element); MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY); DrawElementName (Element); DrawElementPackage (Element); didDraw = true; } else { if (PCB->PinOn) EraseElementPinsAndPads (Element); MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY); } if (PCB->PinOn) { DrawElementPinsAndPads (Element); didDraw = true; } if (didDraw) Draw (); return (Element); }
static void replace_one_footprint_aux(ElementTypePtr old_element, PadOrPinType* old1_pp, PadOrPinType* old2_pp, ElementTypePtr copy_element, PadOrPinType* copy1_pp, PadOrPinType* copy2_pp) { Boolean two_points = (old2_pp && copy2_pp); Boolean reflect = IS_REFLECTED(copy_element, old_element); debug_log("Reflect?: %s\n", (reflect ? "yes" : "no")); if (reflect) { /* Change side of board */ ChangeElementSide(copy_element, 0); } CheapPointType copy1_pt = pad_or_pin_center(copy1_pp); CheapPointType old1_pt = pad_or_pin_center(old1_pp); BYTE rot_steps = 0; if (two_points) { /* Calculate nearest rotation steps */ CheapPointType copy2_pt = pad_or_pin_center(copy2_pp); CheapPointType old2_pt = pad_or_pin_center(old2_pp); rot_steps = calculate_rotation_steps(copy1_pt, copy2_pt, old1_pt, old2_pt); } if (rot_steps) { /* Rotate copy */ RotateElementLowLevel(PCB->Data, copy_element, 0, 0, rot_steps); /* Recalculate since copy_element has changed. */ copy1_pt = pad_or_pin_center(copy1_pp); } /* Calculate translation */ LocationType dx = old1_pt.X - copy1_pt.X; LocationType dy = old1_pt.Y - copy1_pt.Y; /* Move element */ MoveElementLowLevel(PCB->Data, copy_element, dx, dy); /* Transfer pad/pin text and names. */ transfer_text(old_element, copy_element); transfer_names(old_element, copy_element); transfer_flags(old_element, copy_element); SetElementBoundingBox(PCB->Data, copy_element, &PCB->Font); AddObjectToCreateUndoList(ELEMENT_TYPE, copy_element, copy_element, copy_element); /* Remove old element. */ MoveObjectToRemoveUndoList(ELEMENT_TYPE, old_element, old_element, old_element); }
/*! * \brief Move everything. * * Call our own 'MyMove*LowLevel' where they don't exist in move.c. * This gets very slow if there are large polygons present, since every * element move re-clears the poly, followed by the polys moving and * re-clearing everything again. */ static void MoveAll(Coord dx, Coord dy) { ELEMENT_LOOP (PCB->Data); { MoveElementLowLevel (PCB->Data, element, dx, dy); AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); } END_LOOP; VIA_LOOP (PCB->Data); { MyMoveViaLowLevel (PCB->Data, via, dx, dy); AddObjectToMoveUndoList (VIA_TYPE, NULL, NULL, via, dx, dy); } END_LOOP; ALLLINE_LOOP (PCB->Data); { MyMoveLineLowLevel (PCB->Data, layer, line, dx, dy); AddObjectToMoveUndoList (LINE_TYPE, NULL, NULL, line, dx, dy); } ENDALL_LOOP; ALLARC_LOOP (PCB->Data); { MyMoveArcLowLevel (PCB->Data, layer, arc, dx, dy); AddObjectToMoveUndoList (ARC_TYPE, NULL, NULL, arc, dx, dy); } ENDALL_LOOP; ALLTEXT_LOOP (PCB->Data); { MyMoveTextLowLevel (layer, text, dx, dy); AddObjectToMoveUndoList (TEXT_TYPE, NULL, NULL, text, dx, dy); } ENDALL_LOOP; ALLPOLYGON_LOOP (PCB->Data); { /* * XXX MovePolygonLowLevel does not mean "no gui" like * XXX MoveElementLowLevel, it doesn't even handle layer * XXX tree activity. */ MyMovePolygonLowLevel (PCB->Data, layer, polygon, dx, dy); AddObjectToMoveUndoList (POLYGON_TYPE, NULL, NULL, polygon, dx, dy); } ENDALL_LOOP; }
/*! * \brief Place one element. * * Must initialize statics above before calling for the first time. * * This is taken almost entirely from ActionDisperseElements, with cleanup */ static void place (ElementType *element) { Coord dx, dy; /* figure out how much to move the element */ dx = minx - element->BoundingBox.X1; dy = miny - element->BoundingBox.Y1; /* snap to the grid */ dx -= (element->MarkX + dx) % (long) (PCB->Grid); dx += (long) (PCB->Grid); dy -= (element->MarkY + dy) % (long) (PCB->Grid); dy += (long) (PCB->Grid); /* * and add one grid size so we make sure we always space by GAP or * more */ dx += (long) (PCB->Grid); /* Figure out if this row has room. If not, start a new row */ if (minx != GAP && GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth) { miny = maxy + GAP; minx = GAP; place(element); /* recurse can't loop, now minx==GAP */ return; } /* move the element */ MoveElementLowLevel (PCB->Data, element, dx, dy); /* and add to the undo list so we can undo this operation */ AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); /* keep track of how tall this row is */ minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP; if (maxy < element->BoundingBox.Y2) { maxy = element->BoundingBox.Y2; } }
void PostLoadElementPCB () { PCBTypePtr pcb_save = PCB; ElementTypePtr e; if (!yyPCB) return; CreateNewPCBPost (yyPCB, 0); ParseGroupString("1,c:2,s", &yyPCB->LayerGroups, yyData->LayerN); e = yyPCB->Data->Element; /* we know there's only one */ PCB = yyPCB; MoveElementLowLevel (yyPCB->Data, e, -e->BoundingBox.X1, -e->BoundingBox.Y1); PCB = pcb_save; yyPCB->MaxWidth = e->BoundingBox.X2; yyPCB->MaxHeight = e->BoundingBox.Y2; }
void doPerturb (PerturbationType * pt, bool undo) { LocationType bbcx, bbcy; /* compute center of element bounding box */ bbcx = (pt->element->VBox.X1 + pt->element->VBox.X2) / 2; bbcy = (pt->element->VBox.Y1 + pt->element->VBox.Y2) / 2; /* do exchange, shift or flip/rotate */ switch (pt->which) { case SHIFT: { LocationType DX = pt->DX, DY = pt->DY; if (undo) { DX = -DX; DY = -DY; } MoveElementLowLevel (PCB->Data, pt->element, DX, DY); return; } case ROTATE: { BYTE b = pt->rotate; if (undo) b = (4 - b) & 3; /* 0 - flip; 1-3, rotate. */ if (b) RotateElementLowLevel (PCB->Data, pt->element, bbcx, bbcy, b); else { LocationType y = pt->element->VBox.Y1; MirrorElementCoordinates (PCB->Data, pt->element, 0); /* mirroring moves the element. move it back. */ MoveElementLowLevel (PCB->Data, pt->element, 0, y - pt->element->VBox.Y1); } return; } case EXCHANGE: { /* first exchange positions */ LocationType x1 = pt->element->VBox.X1; LocationType y1 = pt->element->VBox.Y1; LocationType x2 = pt->other->BoundingBox.X1; LocationType y2 = pt->other->BoundingBox.Y1; MoveElementLowLevel (PCB->Data, pt->element, x2 - x1, y2 - y1); MoveElementLowLevel (PCB->Data, pt->other, x1 - x2, y1 - y2); /* then flip both elements if they are on opposite sides */ if (TEST_FLAG (ONSOLDERFLAG, pt->element) != TEST_FLAG (ONSOLDERFLAG, pt->other)) { PerturbationType mypt; mypt.element = pt->element; mypt.which = ROTATE; mypt.rotate = 0; /* flip */ doPerturb (&mypt, undo); mypt.element = pt->other; doPerturb (&mypt, undo); } /* done */ return; } default: assert (0); } }
static void pinout_set_data (GhidPinoutPreview * pinout, ElementType * element) { gint tx, ty, x_min = 0, y_min = 0; if (element == NULL) { FreeElementMemory (&pinout->element); pinout->w_pixels = 0; pinout->h_pixels = 0; return; } /* * copy element data * enable output of pin and padnames * move element to a 5% offset from zero position * set all package lines/arcs to zero width */ CopyElementLowLevel (NULL, &pinout->element, element, FALSE, 0, 0); PIN_LOOP (&pinout->element); { tx = abs (pinout->element.Pin[0].X - pin->X); ty = abs (pinout->element.Pin[0].Y - pin->Y); if (x_min == 0 || (tx != 0 && tx < x_min)) x_min = tx; if (y_min == 0 || (ty != 0 && ty < y_min)) y_min = ty; SET_FLAG (DISPLAYNAMEFLAG, pin); } END_LOOP; PAD_LOOP (&pinout->element); { tx = abs (pinout->element.Pad[0].Point1.X - pad->Point1.X); ty = abs (pinout->element.Pad[0].Point1.Y - pad->Point1.Y); if (x_min == 0 || (tx != 0 && tx < x_min)) x_min = tx; if (y_min == 0 || (ty != 0 && ty < y_min)) y_min = ty; SET_FLAG (DISPLAYNAMEFLAG, pad); } END_LOOP; MoveElementLowLevel (NULL, &pinout->element, Settings.PinoutOffsetX - pinout->element.BoundingBox.X1, Settings.PinoutOffsetY - pinout->element.BoundingBox.Y1); if (!pinout_zoom_fit (pinout, 2)) pinout_zoom_fit (pinout, 3); ELEMENTLINE_LOOP (&pinout->element); { line->Thickness = 0; } END_LOOP; ARC_LOOP (&pinout->element); { /* * for whatever reason setting a thickness of 0 causes the arcs to * not display so pick 1 which does display but is still quite * thin. */ arc->Thickness = 1; } END_LOOP; }
/* * Distribute(X, [Lefts/Rights/Centers/Marks/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]]) * Distribute(Y, [Tops/Bottoms/Centers/Marks/Gaps, [First/Last/Crosshair, First/Last/Crosshair[, Gridless]]]) * * As with align, plus: * * Gaps - Make gaps even rather than spreading points evenly * First, Last, * Crosshair - Two arguments specifying both ends of the * distribution, they can't both be the same. * * Defaults are Marks, First, Last * * Distributed elements always retain the same relative order they had * before they were distributed. */ static int distribute(int argc, char **argv, Coord x, Coord y) { int dir; int point; int refa, refb; int gridless; Coord s, e, slack; int divisor; int changed = 0; int i; if (argc < 1 || argc == 3 || argc > 4) { AFAIL(distribute); } /* parse direction arg */ switch ((dir = keyword(ARG(0)))) { case K_X: case K_Y: break; default: AFAIL(distribute); } /* parse point (within each element) which will be distributed */ switch ((point = keyword(ARG(1)))) { case K_Centers: case K_Marks: case K_Gaps: break; case K_Lefts: case K_Rights: if (dir == K_Y) { AFAIL(distribute); } break; case K_Tops: case K_Bottoms: if (dir == K_X) { AFAIL(distribute); } break; case K_none: point = K_Marks; /* default value */ break; default: AFAIL(distribute); } /* parse reference which will determine first distribution coordinate */ switch ((refa = keyword(ARG(2)))) { case K_First: case K_Last: case K_Average: case K_Crosshair: break; case K_none: refa = K_First; /* default value */ break; default: AFAIL(distribute); } /* parse reference which will determine final distribution coordinate */ switch ((refb = keyword(ARG(3)))) { case K_First: case K_Last: case K_Average: case K_Crosshair: break; case K_none: refb = K_Last; /* default value */ break; default: AFAIL(distribute); } if (refa == refb) { AFAIL(distribute); } /* optionally work off the grid (solar cells!) */ switch (keyword(ARG(4))) { case K_Gridless: gridless = 1; break; case K_none: gridless = 0; break; default: AFAIL(distribute); } /* build list of elements in orthogonal axis order */ sort_elements_by_pos(K_distribute, dir, point); /* find the endpoints given the above options */ s = reference_coord(K_distribute, x, y, dir, point, refa); e = reference_coord(K_distribute, x, y, dir, point, refb); slack = e - s; /* use this divisor to calculate spacing (for 1 elt, avoid 1/0) */ divisor = (nelements_by_pos > 1) ? (nelements_by_pos - 1) : 1; /* even the gaps instead of the edges or whatnot */ /* find the "slack" in the row */ if (point == K_Gaps) { Coord w; /* subtract all the "widths" from the slack */ for (i = 0; i < nelements_by_pos; ++i) { ElementType *element = elements_by_pos[i].element; /* coord doesn't care if I mix Lefts/Tops */ w = elements_by_pos[i].width = coord(element, dir, K_Rights) - coord(element, dir, K_Lefts); /* Gaps distribution is on centers, so half of * first and last element don't count */ if (i == 0 || i == nelements_by_pos - 1) { w /= 2; } slack -= w; } /* slack could be negative */ } /* move all selected elements to the new coordinate */ for (i = 0; i < nelements_by_pos; ++i) { ElementType *element = elements_by_pos[i].element; Coord p, q, dp, dx, dy; /* find reference point for this element */ q = s + slack * i / divisor; /* find delta from reference point to reference point */ p = coord(element, dir, point); dp = q - p; /* ...but if we're gridful, keep the mark on the grid */ if (! gridless) { dp -= (coord(element, dir, K_Marks) + dp) % (long) (PCB->Grid); } if (dp) { /* move from generic to X or Y */ dx = dy = dp; if (dir == K_X) dy = 0; else dx = 0; MoveElementLowLevel(PCB->Data, element, dx, dy); AddObjectToMoveUndoList(ELEMENT_TYPE, NULL, NULL, element, dx, dy); changed = 1; } /* in gaps mode, accumulate part widths */ if (point == K_Gaps) { /* move remaining half of our element */ s += elements_by_pos[i].width / 2; /* move half of next element */ if (i < nelements_by_pos - 1) s += elements_by_pos[i + 1].width / 2; } } if (changed) { IncrementUndoSerialNumber(); Redraw(); SetChangedFlag(1); } free_elements_by_pos(); return 0; }
/* * Align(X, [Lefts/Rights/Centers/Marks, [First/Last/Crosshair/Average[, Gridless]]]) * Align(Y, [Tops/Bottoms/Centers/Marks, [First/Last/Crosshair/Average[, Gridless]]]) * * X or Y - Select which axis will move, other is untouched * Lefts, Rights, * Tops, Bottoms, * Centers, Marks - Pick alignment point within each element * First, Last, * Crosshair, * Average - Alignment reference, First=Topmost/Leftmost, * Last=Bottommost/Rightmost, Average or Crosshair point * Gridless - Do not force results to align to prevailing grid * * Defaults are Marks, First */ static int align(int argc, char **argv, Coord x, Coord y) { int dir; int point; int reference; int gridless; Coord q; int changed = 0; if (argc < 1 || argc > 4) { AFAIL(align); } /* parse direction arg */ switch ((dir = keyword(ARG(0)))) { case K_X: case K_Y: break; default: AFAIL(align); } /* parse point (within each element) which will be aligned */ switch ((point = keyword(ARG(1)))) { case K_Centers: case K_Marks: break; case K_Lefts: case K_Rights: if (dir == K_Y) { AFAIL(align); } break; case K_Tops: case K_Bottoms: if (dir == K_X) { AFAIL(align); } break; case K_none: point = K_Marks; /* default value */ break; default: AFAIL(align); } /* parse reference which will determine alignment coordinates */ switch ((reference = keyword(ARG(2)))) { case K_First: case K_Last: case K_Average: case K_Crosshair: break; case K_none: reference = K_First; /* default value */ break; default: AFAIL(align); } /* optionally work off the grid (solar cells!) */ switch (keyword(ARG(3))) { case K_Gridless: gridless = 1; break; case K_none: gridless = 0; break; default: AFAIL(align); } /* find the final alignment coordinate using the above options */ q = reference_coord(K_align, Crosshair.X, Crosshair.Y, dir, point, reference); /* move all selected elements to the new coordinate */ ELEMENT_LOOP(PCB->Data); { Coord p, dp, dx, dy; if (! TEST_FLAG (SELECTEDFLAG, element)) continue; /* find delta from reference point to reference point */ p = coord(element, dir, point); dp = q - p; /* ...but if we're gridful, keep the mark on the grid */ if (! gridless) { dp -= (coord(element, dir, K_Marks) + dp) % (long) (PCB->Grid); } if (dp) { /* move from generic to X or Y */ dx = dy = dp; if (dir == K_X) dy = 0; else dx = 0; MoveElementLowLevel(PCB->Data, element, dx, dy); AddObjectToMoveUndoList(ELEMENT_TYPE, NULL, NULL, element, dx, dy); changed = 1; } } END_LOOP; if (changed) { IncrementUndoSerialNumber(); Redraw(); SetChangedFlag(1); } free_elements_by_pos(); return 0; }