2 * \file src/crosshair.c
4 * \brief Crosshair stuff.
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996 Thomas Nau
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 * Contact addresses for paper mail and Email:
29 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
30 * Thomas.Nau@rz.uni-ulm.de
43 #include "crosshair.h"
53 #ifdef HAVE_LIBDMALLOC
64 * \brief Make a copy of the pin structure, moved to the correct
68 thindraw_moved_pv (hidGC gc
, PinType
*pv
, Coord x
, Coord y
)
70 PinType moved_pv
= *pv
;
74 gui
->graphics
->thindraw_pcb_pv (gc
, gc
, &moved_pv
, true, false);
78 * \brief Draw a dashed line.
81 draw_dashed_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
83 /*! \todo we need a real geometrical library, using double here is
87 double len_squared
= dx
*dx
+ dy
*dy
;
89 const int segs
= 11; /* must be odd */
91 if (len_squared
< 1000000)
93 /*! \todo line too short, just draw it -> magic value;
94 * with a proper geo lib this would be gone anyway. */
95 gui
->graphics
->draw_line (gc
, x1
, y1
, x2
, y2
);
99 /* first seg is drawn from x1, y1 with no rounding error due to n-1 == 0 */
100 for (n
= 1; n
< segs
; n
+= 2)
101 gui
->graphics
->draw_line (gc
,
102 x1
+ (dx
* (double) (n
-1) / (double) segs
),
103 y1
+ (dy
* (double) (n
-1) / (double) segs
),
104 x1
+ (dx
* (double) n
/ (double) segs
),
105 y1
+ (dy
* (double) n
/ (double) segs
));
107 /* make sure the last segment is drawn properly to x2 and y2,
108 * don't leave room for rounding errors. */
109 gui
->graphics
->draw_line (gc
,
110 x2
- (dx
/ (double) segs
),
111 y2
- (dy
/ (double) segs
),
117 * \brief Creates a tmp polygon with coordinates converted to screen
121 XORPolygon (hidGC gc
, PolygonType
*polygon
, Coord dx
, Coord dy
, int dash_last
)
124 for (i
= 0; i
< polygon
->PointN
; i
++)
126 Cardinal next
= next_contour_point (polygon
, i
);
129 { /* last line: sometimes the implicit closing line */
130 if (i
== 1) /* corner case: don't draw two lines on top of
131 * each other - with XOR it looks bad */
136 draw_dashed_line (gc
,
137 polygon
->Points
[i
].X
+ dx
,
138 polygon
->Points
[i
].Y
+ dy
,
139 polygon
->Points
[next
].X
+ dx
,
140 polygon
->Points
[next
].Y
+ dy
);
141 break; /* skip normal line draw below */
145 /* normal contour line */
146 gui
->graphics
->draw_line (gc
,
147 polygon
->Points
[i
].X
+ dx
,
148 polygon
->Points
[i
].Y
+ dy
,
149 polygon
->Points
[next
].X
+ dx
,
150 polygon
->Points
[next
].Y
+ dy
);
155 * \brief Draws the outline of an arc.
158 XORDrawAttachedArc (hidGC gc
, Coord thick
)
164 Coord wid
= thick
/ 2;
166 wx
= Crosshair
.X
- Crosshair
.AttachedBox
.Point1
.X
;
167 wy
= Crosshair
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
168 if (wx
== 0 && wy
== 0)
170 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
;
171 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
;
172 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
174 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
175 sa
= (wx
>= 0) ? 0 : 180;
177 if (abs (wy
) >= 2 * abs (wx
))
178 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
181 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
185 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
186 sa
= (wy
>= 0) ? -90 : 90;
188 if (abs (wx
) >= 2 * abs (wy
))
189 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
192 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
198 arc
.Width
= arc
.Height
= wy
;
199 bx
= GetArcEnds (&arc
);
201 gui
->graphics
->draw_arc (gc
, arc
.X
, arc
.Y
, wy
+ wid
, wy
+ wid
, sa
, dir
);
202 if (wid
> pixel_slop
)
204 gui
->graphics
->draw_arc (gc
, arc
.X
, arc
.Y
, wy
- wid
, wy
- wid
, sa
, dir
);
205 gui
->graphics
->draw_arc (gc
, bx
->X1
, bx
->Y1
, wid
, wid
, sa
, -180 * SGN (dir
));
206 gui
->graphics
->draw_arc (gc
, bx
->X2
, bx
->Y2
, wid
, wid
, sa
+ dir
, 180 * SGN (dir
));
211 * \brief Draws the outline of a line.
214 XORDrawAttachedLine (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord thick
)
216 Coord dx
, dy
, ox
, oy
;
221 if (dx
!= 0 || dy
!= 0)
222 h
= 0.5 * thick
/ hypot (dx
, dy
);
225 ox
= dy
* h
+ 0.5 * SGN (dy
);
226 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
227 gui
->graphics
->draw_line (gc
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
228 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
230 Angle angle
= atan2 (dx
, dy
) * 57.295779;
231 gui
->graphics
->draw_line (gc
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
232 gui
->graphics
->draw_arc (gc
, x1
, y1
, thick
/ 2, thick
/ 2, angle
- 180, 180);
233 gui
->graphics
->draw_arc (gc
, x2
, y2
, thick
/ 2, thick
/ 2, angle
, 180);
238 * \brief Draws the elements of a loaded circuit which is to be merged
242 XORDrawElement (hidGC gc
, ElementType
*Element
, Coord DX
, Coord DY
)
244 /* if no silkscreen, draw the bounding box */
245 if (Element
->ArcN
== 0 && Element
->LineN
== 0)
247 gui
->graphics
->draw_line (gc
,
248 DX
+ Element
->BoundingBox
.X1
,
249 DY
+ Element
->BoundingBox
.Y1
,
250 DX
+ Element
->BoundingBox
.X1
,
251 DY
+ Element
->BoundingBox
.Y2
);
252 gui
->graphics
->draw_line (gc
,
253 DX
+ Element
->BoundingBox
.X1
,
254 DY
+ Element
->BoundingBox
.Y2
,
255 DX
+ Element
->BoundingBox
.X2
,
256 DY
+ Element
->BoundingBox
.Y2
);
257 gui
->graphics
->draw_line (gc
,
258 DX
+ Element
->BoundingBox
.X2
,
259 DY
+ Element
->BoundingBox
.Y2
,
260 DX
+ Element
->BoundingBox
.X2
,
261 DY
+ Element
->BoundingBox
.Y1
);
262 gui
->graphics
->draw_line (gc
,
263 DX
+ Element
->BoundingBox
.X2
,
264 DY
+ Element
->BoundingBox
.Y1
,
265 DX
+ Element
->BoundingBox
.X1
,
266 DY
+ Element
->BoundingBox
.Y1
);
270 ELEMENTLINE_LOOP (Element
);
272 gui
->graphics
->draw_line (gc
,
276 DY
+ line
->Point2
.Y
);
280 /* arc coordinates and angles have to be converted to X11 notation */
283 gui
->graphics
->draw_arc (gc
,
286 arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
290 /* pin coordinates and angles have to be converted to X11 notation */
293 thindraw_moved_pv (gc
, pin
, DX
, DY
);
300 if (PCB
->InvisibleObjectsOn
||
301 (TEST_FLAG (ONSOLDERFLAG
, pad
) != 0) == Settings
.ShowBottomSide
)
303 /* Make a copy of the pad structure, moved to the correct position */
304 PadType moved_pad
= *pad
;
305 moved_pad
.Point1
.X
+= DX
; moved_pad
.Point1
.Y
+= DY
;
306 moved_pad
.Point2
.X
+= DX
; moved_pad
.Point2
.Y
+= DY
;
308 gui
->graphics
->thindraw_pcb_pad (gc
, &moved_pad
, false, false);
313 gui
->graphics
->draw_line (gc
,
314 Element
->MarkX
+ DX
- EMARK_SIZE
,
317 Element
->MarkY
+ DY
- EMARK_SIZE
);
318 gui
->graphics
->draw_line (gc
,
319 Element
->MarkX
+ DX
+ EMARK_SIZE
,
322 Element
->MarkY
+ DY
- EMARK_SIZE
);
323 gui
->graphics
->draw_line (gc
,
324 Element
->MarkX
+ DX
- EMARK_SIZE
,
327 Element
->MarkY
+ DY
+ EMARK_SIZE
);
328 gui
->graphics
->draw_line (gc
,
329 Element
->MarkX
+ DX
+ EMARK_SIZE
,
332 Element
->MarkY
+ DY
+ EMARK_SIZE
);
336 * \brief Draws all visible and attached objects of the pastebuffer.
339 XORDrawBuffer (hidGC gc
, BufferType
*Buffer
)
345 x
= Crosshair
.X
- Buffer
->X
;
346 y
= Crosshair
.Y
- Buffer
->Y
;
348 /* draw all visible layers */
349 for (i
= 0; i
< max_copper_layer
+ SILK_LAYER
; i
++)
350 if (PCB
->Data
->Layer
[i
].On
)
352 LayerType
*layer
= &Buffer
->Data
->Layer
[i
];
357 XORDrawAttachedLine(x +line->Point1.X,
358 y +line->Point1.Y, x +line->Point2.X,
359 y +line->Point2.Y, line->Thickness);
361 gui
->graphics
->draw_line (gc
,
362 x
+ line
->Point1
.X
, y
+ line
->Point1
.Y
,
363 x
+ line
->Point2
.X
, y
+ line
->Point2
.Y
);
368 gui
->graphics
->draw_arc (gc
,
372 arc
->Height
, arc
->StartAngle
, arc
->Delta
);
377 BoxType
*box
= &text
->BoundingBox
;
378 gui
->graphics
->draw_rect (gc
,
379 x
+ box
->X1
, y
+ box
->Y1
, x
+ box
->X2
, y
+ box
->Y2
);
382 /* the tmp polygon has n+1 points because the first
383 * and the last one are set to the same coordinates
385 POLYGON_LOOP (layer
);
387 XORPolygon (gc
, polygon
, x
, y
, 0);
392 /* draw elements if visible */
393 if (PCB
->PinOn
&& PCB
->ElementOn
)
394 ELEMENT_LOOP (Buffer
->Data
);
396 if (FRONT (element
) || PCB
->InvisibleObjectsOn
)
397 XORDrawElement (gc
, element
, x
, y
);
403 VIA_LOOP (Buffer
->Data
);
405 thindraw_moved_pv (gc
, via
, x
, y
);
411 * \brief Draws the rubberband to insert points into polygons/lines/...
414 XORDrawInsertPointObject (hidGC gc
)
416 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
417 PointType
*point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
419 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
421 gui
->graphics
->draw_line (gc
, point
->X
, point
->Y
, line
->Point1
.X
, line
->Point1
.Y
);
422 gui
->graphics
->draw_line (gc
, point
->X
, point
->Y
, line
->Point2
.X
, line
->Point2
.Y
);
427 * \brief Draws the attached object while in MOVE_MODE or COPY_MODE.
430 XORDrawMoveOrCopyObject (hidGC gc
)
434 Coord dx
= Crosshair
.X
- Crosshair
.AttachedObject
.X
,
435 dy
= Crosshair
.Y
- Crosshair
.AttachedObject
.Y
;
437 switch (Crosshair
.AttachedObject
.Type
)
441 PinType
*via
= (PinType
*) Crosshair
.AttachedObject
.Ptr1
;
442 thindraw_moved_pv (gc
, via
, dx
, dy
);
448 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
450 XORDrawAttachedLine (gc
, line
->Point1
.X
+ dx
, line
->Point1
.Y
+ dy
,
451 line
->Point2
.X
+ dx
, line
->Point2
.Y
+ dy
,
458 ArcType
*Arc
= (ArcType
*) Crosshair
.AttachedObject
.Ptr2
;
460 gui
->graphics
->draw_arc (gc
,
463 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
);
469 PolygonType
*polygon
=
470 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
472 /* the tmp polygon has n+1 points because the first
473 * and the last one are set to the same coordinates
475 XORPolygon (gc
, polygon
, dx
, dy
, 0);
484 line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
485 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
486 if (point
== &line
->Point1
)
487 XORDrawAttachedLine (gc
, point
->X
+ dx
, point
->Y
+ dy
,
488 line
->Point2
.X
, line
->Point2
.Y
, line
->Thickness
);
490 XORDrawAttachedLine (gc
, point
->X
+ dx
, point
->Y
+ dy
,
491 line
->Point1
.X
, line
->Point1
.Y
, line
->Thickness
);
495 case POLYGONPOINT_TYPE
:
497 PolygonType
*polygon
;
499 Cardinal point_idx
, prev
, next
;
501 polygon
= (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
502 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
503 point_idx
= polygon_point_idx (polygon
, point
);
505 /* get previous and following point */
506 prev
= prev_contour_point (polygon
, point_idx
);
507 next
= next_contour_point (polygon
, point_idx
);
509 /* draw the two segments */
510 gui
->graphics
->draw_line (gc
,
511 polygon
->Points
[prev
].X
, polygon
->Points
[prev
].Y
,
512 point
->X
+ dx
, point
->Y
+ dy
);
513 gui
->graphics
->draw_line (gc
,
514 point
->X
+ dx
, point
->Y
+ dy
,
515 polygon
->Points
[next
].X
, polygon
->Points
[next
].Y
);
519 case ELEMENTNAME_TYPE
:
521 /* locate the element "mark" and draw an association line from crosshair to it */
522 ElementType
*element
=
523 (ElementType
*) Crosshair
.AttachedObject
.Ptr1
;
525 gui
->graphics
->draw_line (gc
,
527 element
->MarkY
, Crosshair
.X
, Crosshair
.Y
);
528 /* fall through to move the text as a box outline */
532 TextType
*text
= (TextType
*) Crosshair
.AttachedObject
.Ptr2
;
533 BoxType
*box
= &text
->BoundingBox
;
534 gui
->graphics
->draw_rect (gc
,
536 box
->Y1
+ dy
, box
->X2
+ dx
, box
->Y2
+ dy
);
540 /* pin/pad movements result in moving an element */
544 XORDrawElement (gc
, (ElementType
*) Crosshair
.AttachedObject
.Ptr2
, dx
, dy
);
548 /* draw the attached rubberband lines too */
549 i
= Crosshair
.AttachedObject
.RubberbandN
;
550 ptr
= Crosshair
.AttachedObject
.Rubberband
;
553 PointType
*point1
, *point2
;
555 if (TEST_FLAG (VIAFLAG
, ptr
->Line
))
557 /* this is a rat going to a polygon. do not draw for rubberband */;
559 else if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
561 /* 'point1' is always the fix-point */
562 if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
564 point1
= &ptr
->Line
->Point2
;
565 point2
= &ptr
->Line
->Point1
;
569 point1
= &ptr
->Line
->Point1
;
570 point2
= &ptr
->Line
->Point2
;
572 XORDrawAttachedLine (gc
, point1
->X
, point1
->Y
,
573 point2
->X
+ dx
, point2
->Y
+ dy
,
574 ptr
->Line
->Thickness
);
576 else if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
577 XORDrawAttachedLine (gc
,
578 ptr
->Line
->Point1
.X
+ dx
,
579 ptr
->Line
->Point1
.Y
+ dy
,
580 ptr
->Line
->Point2
.X
+ dx
,
581 ptr
->Line
->Point2
.Y
+ dy
, ptr
->Line
->Thickness
);
589 * \brief Draws additional stuff that follows the crosshair.
592 DrawAttached (hidGC gc
)
594 gui
->graphics
->set_color (gc
, Settings
.CrosshairColor
);
595 gui
->graphics
->set_draw_xor (gc
, 1);
596 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
597 gui
->graphics
->set_line_width (gc
, 1);
599 switch (Settings
.Mode
)
603 /* Make a dummy via structure to draw from */
607 via
.Thickness
= Settings
.ViaThickness
;
608 via
.Clearance
= 2 * Settings
.Keepaway
;
609 via
.DrillingHole
= Settings
.ViaDrillingHole
;
611 via
.Flags
= NoFlags ();
613 gui
->graphics
->thindraw_pcb_pv (gc
, gc
, &via
, true, false);
615 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
617 Coord mask_r
= Settings
.ViaThickness
/ 2 + PCB
->Bloat
;
618 gui
->graphics
->set_color (gc
, Settings
.CrossColor
);
619 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
620 gui
->graphics
->set_line_width (gc
, 0);
621 gui
->graphics
->draw_arc (gc
, via
.X
, via
.Y
, mask_r
, mask_r
, 0, 360);
622 gui
->graphics
->set_color (gc
, Settings
.CrosshairColor
);
627 /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
629 case POLYGONHOLE_MODE
:
630 /* draw only if starting point is set */
631 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
632 gui
->graphics
->draw_line (gc
,
633 Crosshair
.AttachedLine
.Point1
.X
,
634 Crosshair
.AttachedLine
.Point1
.Y
,
635 Crosshair
.AttachedLine
.Point2
.X
,
636 Crosshair
.AttachedLine
.Point2
.Y
);
638 /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
639 if (Crosshair
.AttachedPolygon
.PointN
> 1)
641 XORPolygon (gc
, &Crosshair
.AttachedPolygon
, 0, 0, 1);
646 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
648 XORDrawAttachedArc (gc
, Settings
.LineThickness
);
649 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
651 gui
->graphics
->set_color (gc
, Settings
.CrossColor
);
652 XORDrawAttachedArc (gc
, Settings
.LineThickness
+ 2 * PCB
->Bloat
);
653 gui
->graphics
->set_color (gc
, Settings
.CrosshairColor
);
660 /* draw only if starting point exists and the line has length */
661 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
&&
662 Crosshair
.AttachedLine
.draw
)
664 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point1
.X
,
665 Crosshair
.AttachedLine
.Point1
.Y
,
666 Crosshair
.AttachedLine
.Point2
.X
,
667 Crosshair
.AttachedLine
.Point2
.Y
,
668 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
669 /* draw two lines ? */
671 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point2
.X
,
672 Crosshair
.AttachedLine
.Point2
.Y
,
673 Crosshair
.X
, Crosshair
.Y
,
674 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
675 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
677 gui
->graphics
->set_color (gc
, Settings
.CrossColor
);
678 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point1
.X
,
679 Crosshair
.AttachedLine
.Point1
.Y
,
680 Crosshair
.AttachedLine
.Point2
.X
,
681 Crosshair
.AttachedLine
.Point2
.Y
,
682 PCB
->RatDraw
? 10 : Settings
.LineThickness
685 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point2
.X
,
686 Crosshair
.AttachedLine
.Point2
.Y
,
687 Crosshair
.X
, Crosshair
.Y
,
688 PCB
->RatDraw
? 10 : Settings
.
689 LineThickness
+ 2 * PCB
->Bloat
);
690 gui
->graphics
->set_color (gc
, Settings
.CrosshairColor
);
695 case PASTEBUFFER_MODE
:
696 XORDrawBuffer (gc
, PASTEBUFFER
);
701 XORDrawMoveOrCopyObject (gc
);
704 case INSERTPOINT_MODE
:
705 XORDrawInsertPointObject (gc
);
709 /* an attached box does not depend on a special mode */
710 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
||
711 Crosshair
.AttachedBox
.State
== STATE_THIRD
)
713 Coord x1
, y1
, x2
, y2
;
715 x1
= Crosshair
.AttachedBox
.Point1
.X
;
716 y1
= Crosshair
.AttachedBox
.Point1
.Y
;
717 x2
= Crosshair
.AttachedBox
.Point2
.X
;
718 y2
= Crosshair
.AttachedBox
.Point2
.Y
;
719 gui
->graphics
->draw_rect (gc
, x1
, y1
, x2
, y2
);
725 * \brief Draw the marker position.
730 gui
->graphics
->set_color (gc
, Settings
.CrosshairColor
);
731 gui
->graphics
->set_draw_xor (gc
, 1);
732 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
733 gui
->graphics
->set_line_width (gc
, 1);
735 /* Mark is not drawn when it is not set */
739 gui
->graphics
->draw_line (gc
,
740 Marked
.X
- MARK_SIZE
,
741 Marked
.Y
- MARK_SIZE
,
742 Marked
.X
+ MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
743 gui
->graphics
->draw_line (gc
,
744 Marked
.X
+ MARK_SIZE
,
745 Marked
.Y
- MARK_SIZE
,
746 Marked
.X
- MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
750 * \brief Returns the nearest grid-point to the given Coord.
753 GridFit (Coord x
, Coord grid_spacing
, Coord grid_offset
)
756 x
= grid_spacing
* round ((double) x
/ grid_spacing
);
763 * \brief Notify the GUI that data relating to the crosshair is being
766 * The argument passed is false to notify "changes are about to happen",
767 * and true to notify "changes have finished".
769 * Each call with a 'false' parameter must be matched with a following one
770 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
771 * but might be allowed in the future.
773 * GUIs should not complain if they receive extra calls with 'true' as parameter.
774 * They should initiate a redraw of the crosshair attached objects - which may
775 * (if necessary) mean repainting the whole screen if the GUI hasn't tracked the
776 * location of existing attached drawing.
779 notify_crosshair_change (bool changes_complete
)
781 if (gui
->notify_crosshair_change
)
782 gui
->notify_crosshair_change (changes_complete
);
787 * \brief Notify the GUI that data relating to the mark is being changed.
789 * The argument passed is false to notify "changes are about to happen",
790 * and true to notify "changes have finished".
792 * Each call with a 'false' parameter must be matched with a following one
793 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
794 * but might be allowed in the future.
796 * GUIs should not complain if they receive extra calls with 'true' as parameter.
797 * They should initiate a redraw of the mark - which may (if necessary) mean
798 * repainting the whole screen if the GUI hasn't tracked the mark's location.
801 notify_mark_change (bool changes_complete
)
803 if (gui
->notify_mark_change
)
804 gui
->notify_mark_change (changes_complete
);
809 * \brief Convenience for plugins using the old {Hide,Restore}Crosshair
812 * This links up to notify the GUI of the expected changes using the new APIs.
814 * Use of this old API is deprecated, as the names don't necessarily reflect
815 * what all GUIs may do in response to the notifications. Keeping these APIs
816 * is aimed at easing transition to the newer API, they will emit a harmless
817 * warning at the time of their first use.
823 static bool warned_old_api
= false;
826 Message (_("WARNING: A plugin is using the deprecated API HideCrosshair().\n"
827 " This API may be removed in a future release of PCB.\n"));
828 warned_old_api
= true;
831 notify_crosshair_change (false);
832 notify_mark_change (false);
836 RestoreCrosshair (void)
838 static bool warned_old_api
= false;
841 Message (_("WARNING: A plugin is using the deprecated API RestoreCrosshair().\n"
842 " This API may be removed in a future release of PCB.\n"));
843 warned_old_api
= true;
846 notify_crosshair_change (true);
847 notify_mark_change (true);
851 * \brief Returns the square of the given number.
860 crosshair_sq_dist (CrosshairType
*crosshair
, Coord x
, Coord y
)
862 return square (x
- crosshair
->X
) + square (y
- crosshair
->Y
);
866 CrosshairType
*crosshair
;
867 double nearest_sq_dist
;
868 bool nearest_is_grid
;
873 * \brief Snap to a given location if it is the closest thing we found
876 * If "prefer_to_grid" is set, the passed location will take preference
877 * over a closer grid points we already snapped to UNLESS the user is
878 * pressing the SHIFT key. If the SHIFT key is pressed, the closest object
879 * (including grid points), is always preferred.
882 check_snap_object (struct snap_data
*snap_data
, Coord x
, Coord y
,
887 sq_dist
= crosshair_sq_dist (snap_data
->crosshair
, x
, y
);
888 if (sq_dist
<= snap_data
->nearest_sq_dist
||
889 (prefer_to_grid
&& snap_data
->nearest_is_grid
&& !gui
->shift_is_pressed()))
893 snap_data
->nearest_sq_dist
= sq_dist
;
894 snap_data
->nearest_is_grid
= false;
899 check_snap_offgrid_line (struct snap_data
*snap_data
,
900 Coord nearest_grid_x
,
901 Coord nearest_grid_y
)
903 void *ptr1
, *ptr2
, *ptr3
;
910 if (!TEST_FLAG (SNAPPINFLAG
, PCB
))
913 /* Code to snap at some sensible point along a line */
914 /* Pick the nearest grid-point in the x or y direction
915 * to align with, then adjust until we hit the line
917 ans
= SearchObjectByLocation (LINE_TYPE
, &ptr1
, &ptr2
, &ptr3
,
918 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
924 line
= (LineType
*)ptr2
;
926 /* Allow snapping to off-grid lines when drawing new lines (on
927 * the same layer), and when moving a line end-point
928 * (but don't snap to the same line)
930 if ((Settings
.Mode
!= LINE_MODE
|| CURRENT
!= ptr1
) &&
931 (Settings
.Mode
!= MOVE_MODE
||
932 Crosshair
.AttachedObject
.Ptr1
!= ptr1
||
933 Crosshair
.AttachedObject
.Type
!= LINEPOINT_TYPE
||
934 Crosshair
.AttachedObject
.Ptr2
== line
))
937 dx
= line
->Point2
.X
- line
->Point1
.X
;
938 dy
= line
->Point2
.Y
- line
->Point1
.Y
;
940 /* Try snapping along the X axis */
943 /* Move in the X direction until we hit the line */
944 try_x
= (nearest_grid_y
- line
->Point1
.Y
) / dy
* dx
+ line
->Point1
.X
;
945 try_y
= nearest_grid_y
;
946 check_snap_object (snap_data
, try_x
, try_y
, true);
949 /* Try snapping along the Y axis */
952 try_x
= nearest_grid_x
;
953 try_y
= (nearest_grid_x
- line
->Point1
.X
) / dx
* dy
+ line
->Point1
.Y
;
954 check_snap_object (snap_data
, try_x
, try_y
, true);
957 if (dx
!= dy
) /* If line not parallel with dX = dY direction.. */
959 /* Try snapping diagonally towards the line in the dX = dY direction */
962 dist
= line
->Point1
.Y
- nearest_grid_y
;
964 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
965 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 - dx
/ dy
);
967 try_x
= nearest_grid_x
+ dist
;
968 try_y
= nearest_grid_y
+ dist
;
970 check_snap_object (snap_data
, try_x
, try_y
, true);
973 if (dx
!= -dy
) /* If line not parallel with dX = -dY direction.. */
975 /* Try snapping diagonally towards the line in the dX = -dY direction */
978 dist
= nearest_grid_y
- line
->Point1
.Y
;
980 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
981 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 + dx
/ dy
);
983 try_x
= nearest_grid_x
+ dist
;
984 try_y
= nearest_grid_y
- dist
;
986 check_snap_object (snap_data
, try_x
, try_y
, true);
991 * \brief Recalculates the passed coordinates to fit the current grid
995 FitCrosshairIntoGrid (Coord X
, Coord Y
)
997 Coord nearest_grid_x
, nearest_grid_y
;
998 void *ptr1
, *ptr2
, *ptr3
;
999 struct snap_data snap_data
;
1002 Crosshair
.X
= CLAMP (X
, Crosshair
.MinX
, Crosshair
.MaxX
);
1003 Crosshair
.Y
= CLAMP (Y
, Crosshair
.MinY
, Crosshair
.MaxY
);
1007 nearest_grid_x
= -MIL_TO_COORD (6);
1008 nearest_grid_y
= -MIL_TO_COORD (6);
1012 nearest_grid_x
= GridFit (Crosshair
.X
, PCB
->Grid
, PCB
->GridOffsetX
);
1013 nearest_grid_y
= GridFit (Crosshair
.Y
, PCB
->Grid
, PCB
->GridOffsetY
);
1015 if (Marked
.status
&& TEST_FLAG (ORTHOMOVEFLAG
, PCB
))
1017 Coord dx
= Crosshair
.X
- Marked
.X
;
1018 Coord dy
= Crosshair
.Y
- Marked
.Y
;
1019 if (ABS (dx
) > ABS (dy
))
1020 nearest_grid_y
= Marked
.Y
;
1022 nearest_grid_x
= Marked
.X
;
1027 snap_data
.crosshair
= &Crosshair
;
1028 snap_data
.nearest_sq_dist
=
1029 crosshair_sq_dist (&Crosshair
, nearest_grid_x
, nearest_grid_y
);
1030 snap_data
.nearest_is_grid
= true;
1031 snap_data
.x
= nearest_grid_x
;
1032 snap_data
.y
= nearest_grid_y
;
1036 ans
= SearchObjectByLocation (ELEMENT_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1037 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1039 if (ans
& ELEMENT_TYPE
)
1041 ElementType
*el
= (ElementType
*) ptr1
;
1042 check_snap_object (&snap_data
, el
->MarkX
, el
->MarkY
, false);
1046 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
1047 ans
= SearchObjectByLocation (PAD_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1048 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1050 /* Avoid self-snapping when moving */
1051 if (ans
!= NO_TYPE
&&
1052 Settings
.Mode
== MOVE_MODE
&&
1053 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
1054 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
1057 if (ans
!= NO_TYPE
&&
1058 ( Settings
.Mode
== LINE_MODE
||
1059 (Settings
.Mode
== MOVE_MODE
&&
1060 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)))
1062 PadType
*pad
= (PadType
*) ptr2
;
1063 LayerType
*desired_layer
;
1064 Cardinal desired_group
;
1065 Cardinal bottom_group
, top_group
;
1066 int found_our_layer
= false;
1068 desired_layer
= CURRENT
;
1069 if (Settings
.Mode
== MOVE_MODE
&&
1070 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)
1072 desired_layer
= (LayerType
*)Crosshair
.AttachedObject
.Ptr1
;
1075 /* find layer groups of the top and bottom sides */
1076 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
1077 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
1078 desired_group
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? bottom_group
: top_group
;
1080 GROUP_LOOP (PCB
->Data
, desired_group
);
1082 if (layer
== desired_layer
)
1084 found_our_layer
= true;
1090 if (found_our_layer
== false)
1096 PadType
*pad
= (PadType
*)ptr2
;
1097 check_snap_object (&snap_data
, pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2,
1098 pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2,
1103 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
1104 ans
= SearchObjectByLocation (PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1105 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1107 /* Avoid self-snapping when moving */
1108 if (ans
!= NO_TYPE
&&
1109 Settings
.Mode
== MOVE_MODE
&&
1110 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
1111 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
1116 PinType
*pin
= (PinType
*)ptr2
;
1117 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1121 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1122 ans
= SearchObjectByLocation (VIA_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1123 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1125 /* Avoid snapping vias to any other vias */
1126 if (Settings
.Mode
== MOVE_MODE
&&
1127 Crosshair
.AttachedObject
.Type
== VIA_TYPE
&&
1133 PinType
*pin
= (PinType
*)ptr2
;
1134 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1138 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1139 ans
= SearchObjectByLocation (LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1140 &ptr1
, &ptr2
, &ptr3
,
1141 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1145 PointType
*pnt
= (PointType
*)ptr3
;
1146 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1149 check_snap_offgrid_line (&snap_data
, nearest_grid_x
, nearest_grid_y
);
1152 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1153 ans
= SearchObjectByLocation (POLYGONPOINT_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1154 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1158 PointType
*pnt
= (PointType
*)ptr3
;
1159 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1162 if (snap_data
.x
>= 0 && snap_data
.y
>= 0)
1164 Crosshair
.X
= snap_data
.x
;
1165 Crosshair
.Y
= snap_data
.y
;
1168 if (Settings
.Mode
== ARROW_MODE
)
1170 ans
= SearchObjectByLocation (LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1171 &ptr1
, &ptr2
, &ptr3
,
1172 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1174 hid_action("PointCursor");
1175 else if (!TEST_FLAG(SELECTEDFLAG
, (LineType
*)ptr2
))
1176 hid_actionl("PointCursor","True", NULL
);
1179 if (Settings
.Mode
== LINE_MODE
1180 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
1181 && TEST_FLAG (AUTODRCFLAG
, PCB
))
1184 gui
->set_crosshair (Crosshair
.X
, Crosshair
.Y
, HID_SC_DO_NOTHING
);
1188 * \brief Move crosshair absolute.
1190 * \return true if the crosshair was moved from its existing position.
1193 MoveCrosshairAbsolute (Coord X
, Coord Y
)
1195 Coord old_x
= Crosshair
.X
;
1196 Coord old_y
= Crosshair
.Y
;
1198 FitCrosshairIntoGrid (X
, Y
);
1200 if (Crosshair
.X
!= old_x
|| Crosshair
.Y
!= old_y
)
1202 Coord new_x
= Crosshair
.X
;
1203 Coord new_y
= Crosshair
.Y
;
1205 /* back up to old position to notify the GUI
1206 * (which might want to erase the old crosshair) */
1207 Crosshair
.X
= old_x
;
1208 Crosshair
.Y
= old_y
;
1209 notify_crosshair_change (false); /* Our caller notifies when it has done */
1211 /* now move forward again */
1212 Crosshair
.X
= new_x
;
1213 Crosshair
.Y
= new_y
;
1220 * \brief Sets the valid range for the crosshair cursor.
1223 SetCrosshairRange (Coord MinX
, Coord MinY
, Coord MaxX
, Coord MaxY
)
1225 Crosshair
.MinX
= MAX (0, MinX
);
1226 Crosshair
.MinY
= MAX (0, MinY
);
1227 Crosshair
.MaxX
= MIN (PCB
->MaxWidth
, MaxX
);
1228 Crosshair
.MaxY
= MIN (PCB
->MaxHeight
, MaxY
);
1230 /* force update of position */
1231 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
1235 * \brief Initializes crosshair stuff.
1237 * Clears the struct, allocates to graphical contexts.
1240 InitCrosshair (void)
1242 /* set initial shape */
1243 Crosshair
.shape
= Basic_Crosshair_Shape
;
1245 /* set default limits */
1246 Crosshair
.MinX
= Crosshair
.MinY
= 0;
1247 Crosshair
.MaxX
= PCB
->MaxWidth
;
1248 Crosshair
.MaxY
= PCB
->MaxHeight
;
1250 /* clear the mark */
1251 Marked
.status
= false;
1255 * \brief Exits crosshair routines, release GCs.
1258 DestroyCrosshair (void)
1260 FreePolygonMemory (&Crosshair
.AttachedPolygon
);