← Back to team overview

kicad-developers team mailing list archive

Patch: improved magnetism

 

--/WwmFnJnmDyWGHa4 Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

This patch demonstrates some new improvements of "magnetism":

- if drawing a track in "magnetic if creating tracks" mode, only pads on
the same net are magnetic

- vias are also magnetic

- tracks also get a bit magnetic: if we're drawing a new track, all
tracks on the same net let us connect at the intersection with the
projection of the new track. This means that off-grid tracks can
go straight into other tracks, without adding little acid traps.

- if starting a new track from an old track, the projection of the
next grid point on the track becomes magnetic. This yields properly
grid-aligned perpendicular tracks.

The via hitting algorithm used to look only at the square enclosing the
via's circle. For better results with "magnetic" vias, I changed that.
I hope this doesn't break anything else.

The magnetism logic in GeneralControle was getting a bit convoluted, so
I moved it to a separate set of functions.

I don't know much about C++, so my style is probably quite awful, but I
hope this can still serve as an inspiration. I only played a little bit
with these changes, to make sure they don't break things too horribly,
but didn't use them for any real projects yet.

- Werner

---------------------------------- Changes ------------------------------------

pcbnew/class_track.cpp (HitTest): hit vias only if entering the circle, not the
enclosing square
pcbnew/protos.h, pcbnew/locate.cpp (Locate_Via_Area): new function to find a
via that covers the cursor position
pcbnew/controle.cpp (GeneralControle): to make logic less confusing, moved
handling of "magnetism" to new function "Magnetize"
pcbnew/controle.cpp (Magnetize): if drawing a track, only pads on the same net
are "magnetic" (unless capture_always is set)
pcbnew/controle.cpp (Magnetize): make also vias are "magnetic"
pcbnew/controle.cpp (Magnetize): make also intersection with tracks "magnetic"
 --/WwmFnJnmDyWGHa4 Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="kicad-more-magnetism.patch"

Index: pcbnew/protos.h
===================================================================
--- pcbnew/protos.h	(revision 729)
+++ pcbnew/protos.h	(working copy)
@@ -68,6 +68,8 @@

TRACK * Locate_Via(BOARD * Pcb, const wxPoint & pos, int layer = -1);

+TRACK * Locate_Via_Area(BOARD * Pcb, const wxPoint & pos, int layer = -1);
+
TRACK * Fast_Locate_Via(TRACK *start_adr, TRACK* end_adr,
const wxPoint & pos, int masquelayer);
/* Localise la via de centre le point x,y , sur les couches donnees
Index: pcbnew/controle.cpp
===================================================================
--- pcbnew/controle.cpp	(revision 729)
+++ pcbnew/controle.cpp	(working copy)
@@ -218,7 +218,135 @@
return item;
}

+/*
+ * "Join" finds the point where b0+x*(b1-b0) intersects with a0+y*(a1-a0).
+ * If that point would be outside of a0-a1, the respective endpoint is used.
+ * Join returns the point in "res" and "true" if a suitable point was found,
+ * "false" if both lines are parallel.
+ */

+static bool Join(wxPoint &res, wxPoint a0, wxPoint a1, wxPoint b0, wxPoint b1)
+{
+ int64_t denom;
+ double t;
+
+ a1 -= a0;
+ b1 -= b0;
+ b0 -= a0;
+
+ denom = b1.y*a1.x-b1.x*a1.y;
+ if (!denom)
+	return false; // parallel
+
+ t = (b1.y*b0.x-b1.x*b0.y)/(double) denom;
+ t = min(max(t, 0.0), 1.0);
+
+ res.x = (int) round(a0.x+t*a1.x);
+ res.y = (int) round(a0.y+t*a1.y);
+
+ return true;
+}
+
+/*
+ * "Project" finds the projection of a grid point on a track. This is the point
+ * from where we want to draw new orthogonal tracks when starting on a track.
+ */
+
+static bool Project(wxPoint &res, wxPoint on_grid, const TRACK *track)
+{
+ wxPoint vec;
+ double t;
+
+ if (track->m_Start == track->m_End)
+	return false;
+
+ vec = track->m_End-track->m_Start;
+ t = (on_grid.x-track->m_Start.x)*vec.x+(on_grid.y-track->m_Start.y)*vec.y;
+ t /= vec.x*vec.x+vec.y*vec.y;
+ t = min(max(t, 0.0), 1.0);
+
+ res.x = (int) round(track->m_Start.x+t*vec.x);
+ res.y = (int) round(track->m_Start.y+t*vec.y);
+
+ return true;
+}
+
+static bool Magnetize(BOARD *m_Pcb, WinEDA_PcbFrame *frame,
+ int m_ID_current_state, wxSize grid, wxPoint on_grid, wxPoint &curpos)
+{
+ const D_PAD *pad;
+ const TRACK *curr = NULL;
+ const TRACK *via, *track;
+ int layer, layer_mask;
+ bool sometimes = g_MagneticPadOption != capture_always;
+
+ curr = g_CurrentTrackSegment;
+ if (frame->GetCurItem() != curr)
+	curr = NULL;
+
+ switch (g_MagneticPadOption) {
+ case capture_cursor_in_track_tool:
+	if (m_ID_current_state != ID_TRACK_BUTT)
+	return false;
+	break;
+ case capture_always:
+	break;
+ case no_effect:
+ default:
+	return false;
+ }
+
+ pad = Locate_Any_Pad(m_Pcb, CURSEUR_OFF_GRILLE, TRUE);
+ if (pad) {
+	if (curr && curr->GetNet() != pad->GetNet() && sometimes)
+	return false;
+	curpos = pad->m_Pos;
+	return true;
+ }
+
+ layer = ((PCB_SCREEN *) ActiveScreen)->m_Active_Layer;
+
+ via = Locate_Via_Area(m_Pcb, curpos, layer);
+ if (via) {
+	if (curr && curr->GetNet() != via->GetNet() && sometimes)
+	return false;
+	curpos = via->m_Start;
+	return true;
+ }
+
+ layer_mask = g_TabOneLayerMask[layer];
+
+ if (!curr) {
+	track = Locate_Pistes(m_Pcb->m_Track, layer_mask, CURSEUR_OFF_GRILLE);
+	if (!track || track->Type() != TYPETRACK)
+	return false;
+	return Project(curpos, on_grid, track);
+ }
+
+ /*
+ * In two segment mode, ignore the final segment if it's inside a grid
+ * square.
+ */
+ if (g_TwoSegmentTrackBuild && curr->Pback &&
+ curr->m_Start.x-grid.x < curr->m_End.x &&
+ curr->m_Start.x+grid.x > curr->m_End.x &&
+ curr->m_Start.y-grid.y < curr->m_End.y &&
+ curr->m_Start.y+grid.y > curr->m_End.y)
+	curr = curr->Back();
+
+ track = Locate_Pistes(m_Pcb->m_Track, layer_mask, CURSEUR_OFF_GRILLE);
+ for (; track; track = track->Next()) {
+	if (track->Type() != TYPETRACK)
+	continue;
+	if (curr->GetNet() != track->GetNet() && sometimes)
+	continue;
+	if (Join(curpos, track->m_Start, track->m_End,
+	curr->m_Start, curr->m_End))
+	return true;
+ }
+ return false;
+}
+
/****************************************************************/
void WinEDA_BasePcbFrame::GeneralControle( wxDC* DC, wxPoint Mouse )
/*****************************************************************/
@@ -341,7 +469,6 @@
* But if the tool DELETE is active the cursor is left off grid
* this is better to reach items to delete off grid
*/
- D_PAD* pad;
bool keep_on_grid = TRUE;
if( m_ID_current_state == ID_PCB_DELETE_ITEM_BUTT )
keep_on_grid = FALSE;
@@ -354,34 +481,15 @@
if( DrawStruct && DrawStruct->m_Flags )
keep_on_grid = TRUE;

- switch( g_MagneticPadOption )
- {
- case capture_cursor_in_track_tool:
- case capture_always:
- pad = Locate_Any_Pad( m_Pcb, CURSEUR_OFF_GRILLE, TRUE );
- if( (m_ID_current_state != ID_TRACK_BUTT )
- && (g_MagneticPadOption == capture_cursor_in_track_tool) )
- pad = NULL;
- 
- if( keep_on_grid )
- {
- if( pad ) // Put cursor on the pad
- GetScreen()->m_Curseur = curpos = pad->m_Pos;
- else
- // Put cursor on grid
- PutOnGrid( &GetScreen()->m_Curseur );
- }
- break;
+ if (keep_on_grid) {
+	wxPoint on_grid = curpos;

- case no_effect:
- default:
-
- // If we are not in delete function, put cursor on grid
- if( keep_on_grid )
- {
- PutOnGrid( &GetScreen()->m_Curseur );
- }
- break;
+	PutOnGrid(&on_grid);
+	if (Magnetize(m_Pcb, (WinEDA_PcbFrame *) this, m_ID_current_state,
+	GetScreen()->GetGrid(), on_grid, curpos))
+	GetScreen()->m_Curseur = curpos;
+	else
+	GetScreen()->m_Curseur = on_grid;
}

if( oldpos != GetScreen()->m_Curseur )
Index: pcbnew/locate.cpp
===================================================================
--- pcbnew/locate.cpp	(revision 729)
+++ pcbnew/locate.cpp	(working copy)
@@ -111,6 +111,34 @@
}

+/*******************************************************************/
+TRACK* Locate_Via_Area( BOARD* Pcb, const wxPoint& pos, int layer )
+/*******************************************************************/
+
+/*
+ * Like Locate_Via, but finds any via covering the cursor position
+ */
+{
+ TRACK* Track;
+
+ for( Track = Pcb->m_Track; Track != NULL; Track = Track->Next() )
+ {
+ if( Track->Type() != TYPEVIA )
+ continue;
+ if(!Track->HitTest(pos))
+ continue;
+ if( Track->GetState( BUSY | DELETED ) )
+ continue;
+ if( layer < 0 )
+ return Track;
+ if( Track->IsOnLayer( layer ) )
+ return Track;
+ }
+
+ return NULL;
+}
+
+
/********************************************************************/
D_PAD* Locate_Pad_Connecte( BOARD* Pcb, TRACK* ptr_piste, int extr )
/********************************************************************/
Index: pcbnew/class_track.cpp
===================================================================
--- pcbnew/class_track.cpp	(revision 729)
+++ pcbnew/class_track.cpp	(working copy)
@@ -886,10 +886,7 @@

if( Type() == TYPEVIA ) /* VIA rencontree */
{
- if( (abs( spot_cX ) <= l_piste ) && (abs( spot_cY ) <=l_piste) )
- return true;
- else
- return false;
+ return spot_cX*spot_cX+spot_cY*spot_cY <= l_piste*l_piste;
}
else
{
 --/WwmFnJnmDyWGHa4-- 




Follow ups