2011-10-17 20:01:27 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2012-06-08 09:56:42 +00:00
|
|
|
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
|
|
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
|
|
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
|
|
|
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
2011-10-17 20:01:27 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2011-09-24 18:33:28 +00:00
|
|
|
/**
|
|
|
|
* @file editrack.cpp
|
|
|
|
*/
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <class_drawpanel.h>
|
|
|
|
#include <trigo.h>
|
|
|
|
#include <pcbcommon.h>
|
|
|
|
#include <wxPcbStruct.h>
|
|
|
|
#include <colors_selection.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <pcbnew.h>
|
|
|
|
#include <drc_stuff.h>
|
|
|
|
#include <protos.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <class_board.h>
|
|
|
|
#include <class_track.h>
|
|
|
|
#include <class_zone.h>
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
|
2011-04-14 18:44:46 +00:00
|
|
|
static void Abort_Create_Track( EDA_DRAW_PANEL* panel, wxDC* DC );
|
2011-02-03 19:27:28 +00:00
|
|
|
void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
|
|
|
|
const wxPoint& aPosition, bool aErase );
|
2009-06-18 20:51:01 +00:00
|
|
|
static void ComputeBreakPoint( TRACK* track, int n, wxPoint end );
|
|
|
|
static void DeleteNullTrackSegments( BOARD* pcb, DLIST<TRACK>& aTrackList );
|
|
|
|
static void EnsureEndTrackOnPad( D_PAD* Pad );
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-02-04 20:30:00 +00:00
|
|
|
// A PICKED_ITEMS_LIST to store tracks which are modified/added/deleted
|
|
|
|
// during a track edition:
|
2009-08-08 06:07:08 +00:00
|
|
|
static PICKED_ITEMS_LIST s_ItemsListPicker;
|
2007-06-05 12:10:51 +00:00
|
|
|
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
/* Function called to abort a track creation
|
2007-06-05 12:10:51 +00:00
|
|
|
*/
|
2011-04-14 18:44:46 +00:00
|
|
|
static void Abort_Create_Track( EDA_DRAW_PANEL* Panel, wxDC* DC )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2011-03-01 19:26:17 +00:00
|
|
|
PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Panel->GetParent();
|
2011-12-04 17:57:03 +00:00
|
|
|
BOARD* pcb = frame->GetBoard();
|
|
|
|
TRACK* track = (TRACK*) frame->GetCurItem();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
if( track && ( track->Type()==PCB_VIA_T || track->Type()==PCB_TRACE_T ) )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// Erase the current drawing
|
2011-02-03 19:27:28 +00:00
|
|
|
ShowNewTrackWhenMovingCursor( Panel, DC, wxDefaultPosition, false );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
if( pcb->IsHighLightNetON() )
|
2011-10-17 20:01:27 +00:00
|
|
|
frame->HighLight( DC );
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
pcb->PopHighLight();
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
if( pcb->IsHighLightNetON() )
|
|
|
|
pcb->DrawHighLight( Panel, DC, pcb->GetHighLightNetCode() );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-12 14:02:37 +00:00
|
|
|
frame->ClearMsgPanel();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-04-14 18:44:46 +00:00
|
|
|
// Undo pending changes (mainly a lock point creation) and clear the
|
2009-11-14 22:15:22 +00:00
|
|
|
// undo picker list:
|
2009-10-14 18:14:58 +00:00
|
|
|
frame->PutDataInPreviousState( &s_ItemsListPicker, false, false );
|
2009-08-08 06:07:08 +00:00
|
|
|
s_ItemsListPicker.ClearListAndDeleteItems();
|
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
// Delete current (new) track
|
2008-12-04 04:28:11 +00:00
|
|
|
g_CurrentTrackList.DeleteAll();
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2007-09-12 02:14:07 +00:00
|
|
|
frame->SetCurItem( NULL );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
/*
|
|
|
|
* This function starts a new track segment.
|
|
|
|
* If a new track segment is in progress, ends this current new segment,
|
|
|
|
* and created a new one.
|
|
|
|
*/
|
2011-09-15 17:58:35 +00:00
|
|
|
TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2009-06-18 20:51:01 +00:00
|
|
|
TRACK* TrackOnStartPoint = NULL;
|
2011-12-06 08:35:13 +00:00
|
|
|
int layerMask = GetLayerMask( GetScreen()->m_Active_Layer );
|
2011-11-08 16:18:46 +00:00
|
|
|
BOARD_CONNECTED_ITEM* LockPoint;
|
2011-02-11 20:48:13 +00:00
|
|
|
wxPoint pos = GetScreen()->GetCrossHairPosition();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( aTrack == NULL ) // Starting a new track segment
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-12-22 13:28:11 +00:00
|
|
|
m_canvas->SetMouseCapture( ShowNewTrackWhenMovingCursor, Abort_Create_Track );
|
2011-04-14 18:44:46 +00:00
|
|
|
|
2009-08-08 06:07:08 +00:00
|
|
|
// Prepare the undo command info
|
2011-09-07 19:41:04 +00:00
|
|
|
s_ItemsListPicker.ClearListAndDeleteItems(); // Should not be necessary, but...
|
2009-08-08 06:07:08 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->PushHighLight();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-04-05 17:49:14 +00:00
|
|
|
// erase old highlight
|
2011-09-14 20:04:58 +00:00
|
|
|
if( GetBoard()->IsHighLightNetON() )
|
2011-10-17 20:01:27 +00:00
|
|
|
HighLight( aDC );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-01-05 05:21:35 +00:00
|
|
|
g_CurrentTrackList.PushBack( new TRACK( GetBoard() ) );
|
2011-12-21 13:42:02 +00:00
|
|
|
g_CurrentTrackSegment->SetFlags( IS_NEW );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->SetHighLightNet( 0 );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
// Search for a starting point of the new track, a track or pad
|
2011-09-17 01:22:26 +00:00
|
|
|
LockPoint = GetBoard()->GetLockPoint( pos, layerMask );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
D_PAD* pad = NULL;
|
2008-01-28 18:44:14 +00:00
|
|
|
if( LockPoint ) // An item (pad or track) is found
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
if( LockPoint->Type() == PCB_PAD_T )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
pad = (D_PAD*) LockPoint;
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// A pad is found: put the starting point on pad center
|
|
|
|
pos = pad->GetPosition();
|
2011-12-04 17:57:03 +00:00
|
|
|
GetBoard()->SetHighLightNet( pad->GetNet() );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2012-02-19 04:02:19 +00:00
|
|
|
else // A track segment is found
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-01-28 18:44:14 +00:00
|
|
|
TrackOnStartPoint = (TRACK*) LockPoint;
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->SetHighLightNet( TrackOnStartPoint->GetNet() );
|
2011-09-17 01:22:26 +00:00
|
|
|
GetBoard()->CreateLockPoint( pos, TrackOnStartPoint, &s_ItemsListPicker );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-15 17:58:35 +00:00
|
|
|
else
|
2008-11-27 10:12:46 +00:00
|
|
|
{
|
2011-09-15 17:58:35 +00:00
|
|
|
// Not a starting point, but a filled zone area can exist. This is also a
|
|
|
|
// good starting point.
|
2011-03-01 19:26:17 +00:00
|
|
|
ZONE_CONTAINER* zone;
|
|
|
|
zone = GetBoard()->HitTestForAnyFilledArea( pos, GetScreen()-> m_Active_Layer );
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
if( zone )
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->SetHighLightNet( zone->GetNet() );
|
2008-11-27 10:12:46 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2011-11-08 16:18:46 +00:00
|
|
|
BuildAirWiresTargetsList( LockPoint, wxPoint( 0, 0 ), true );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->HighLightON();
|
2011-12-22 13:28:11 +00:00
|
|
|
GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-10-03 17:18:08 +00:00
|
|
|
// Display info about track Net class, and init track and vias sizes:
|
2011-09-14 20:04:58 +00:00
|
|
|
g_CurrentTrackSegment->SetNet( GetBoard()->GetHighLightNetCode() );
|
2009-10-03 17:18:08 +00:00
|
|
|
GetBoard()->SetCurrentNetClass( g_CurrentTrackSegment->GetNetClassName() );
|
|
|
|
|
2009-09-27 11:00:21 +00:00
|
|
|
g_CurrentTrackSegment->SetLayer( GetScreen()->m_Active_Layer );
|
2009-10-30 17:58:15 +00:00
|
|
|
g_CurrentTrackSegment->m_Width = GetBoard()->GetCurrentTrackWidth();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
if( GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
|
2008-01-28 18:44:14 +00:00
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
if( TrackOnStartPoint && TrackOnStartPoint->Type() == PCB_TRACE_T )
|
2009-10-03 17:18:08 +00:00
|
|
|
g_CurrentTrackSegment->m_Width = TrackOnStartPoint->m_Width;
|
2008-01-28 18:44:14 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-01-28 18:44:14 +00:00
|
|
|
g_CurrentTrackSegment->m_Start = pos;
|
2008-12-04 04:28:11 +00:00
|
|
|
g_CurrentTrackSegment->m_End = pos;
|
2009-09-27 11:00:21 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( pad )
|
2011-12-17 21:21:03 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
g_CurrentTrackSegment->m_PadsConnected.push_back( pad );
|
2011-12-17 21:21:03 +00:00
|
|
|
// Useful to display track length, if the pad has a die length:
|
|
|
|
g_CurrentTrackSegment->SetState( BEGIN_ONPAD, ON );
|
|
|
|
g_CurrentTrackSegment->start = pad;
|
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
if( g_TwoSegmentTrackBuild )
|
2008-01-28 18:44:14 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
// Create 2nd segment
|
2012-01-14 19:50:32 +00:00
|
|
|
g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
g_CurrentTrackSegment->start = g_FirstTrackSegment;
|
2008-12-04 04:28:11 +00:00
|
|
|
g_FirstTrackSegment->end = g_CurrentTrackSegment;
|
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
g_FirstTrackSegment->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
|
|
|
|
}
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
g_CurrentTrackSegment->DisplayInfoBase( this );
|
|
|
|
SetCurItem( g_CurrentTrackSegment, false );
|
2011-12-29 20:11:42 +00:00
|
|
|
m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2007-12-01 03:42:52 +00:00
|
|
|
if( Drc_On )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-09-07 19:41:04 +00:00
|
|
|
if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
|
2007-12-01 03:42:52 +00:00
|
|
|
{
|
|
|
|
return g_CurrentTrackSegment;
|
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-03 19:27:28 +00:00
|
|
|
else // Track in progress : segment coordinates are updated by ShowNewTrackWhenMovingCursor.
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// Test for a D.R.C. error:
|
2007-08-20 01:20:48 +00:00
|
|
|
if( Drc_On )
|
|
|
|
{
|
2011-09-07 19:41:04 +00:00
|
|
|
if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
|
2007-08-20 01:20:48 +00:00
|
|
|
return NULL;
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
// We must handle 2 segments
|
|
|
|
if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->Back() )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-09-07 19:41:04 +00:00
|
|
|
if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment->Back(), GetBoard()->m_Track ) )
|
2007-08-20 01:20:48 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
/* Current track is Ok: current segment is kept, and a new one is
|
|
|
|
* created unless the current segment is null, or 2 last are null
|
2011-12-04 17:57:03 +00:00
|
|
|
* if this is a 2 segments track build.
|
2007-08-20 01:20:48 +00:00
|
|
|
*/
|
2009-10-01 16:46:13 +00:00
|
|
|
bool CanCreateNewSegment = true;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( !g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() )
|
2009-10-01 16:46:13 +00:00
|
|
|
CanCreateNewSegment = false;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull()
|
2011-09-15 17:58:35 +00:00
|
|
|
&& g_CurrentTrackSegment->Back()
|
|
|
|
&& g_CurrentTrackSegment->Back()->IsNull() )
|
2009-10-01 16:46:13 +00:00
|
|
|
CanCreateNewSegment = false;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( CanCreateNewSegment )
|
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// Erase old track on screen
|
2008-12-04 04:28:11 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2011-12-22 13:28:11 +00:00
|
|
|
ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( g_Raccord_45_Auto )
|
2011-09-15 17:58:35 +00:00
|
|
|
Add45DegreeSegment( aDC );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
TRACK* previousTrack = g_CurrentTrackSegment;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2012-01-14 19:50:32 +00:00
|
|
|
TRACK* newTrack = (TRACK*)g_CurrentTrackSegment->Clone();
|
2008-12-04 04:28:11 +00:00
|
|
|
g_CurrentTrackList.PushBack( newTrack );
|
2011-12-21 13:42:02 +00:00
|
|
|
newTrack->SetFlags( IS_NEW );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
newTrack->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
|
|
|
|
|
2012-07-25 18:46:25 +00:00
|
|
|
D_PAD* pad = GetBoard()->GetPad( previousTrack, FLG_END );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( pad )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
newTrack->m_PadsConnected.push_back( pad );
|
|
|
|
previousTrack->m_PadsConnected.push_back( pad );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
newTrack->start = previousTrack->end;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
|
|
|
newTrack->m_Start = newTrack->m_End;
|
|
|
|
|
2011-12-06 08:35:13 +00:00
|
|
|
newTrack->SetLayer( GetScreen()->m_Active_Layer );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
if( !GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
|
2009-10-30 17:58:15 +00:00
|
|
|
newTrack->m_Width = GetBoard()->GetCurrentTrackWidth();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Show the new position
|
2011-12-22 13:28:11 +00:00
|
|
|
ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
|
2009-10-14 18:14:58 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
SetCurItem( g_CurrentTrackSegment, false );
|
2007-08-20 01:20:48 +00:00
|
|
|
return g_CurrentTrackSegment;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
bool PCB_EDIT_FRAME::Add45DegreeSegment( wxDC* aDC )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2009-06-18 20:51:01 +00:00
|
|
|
int dx0, dy0, dx1, dy1;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
if( g_CurrentTrackList.GetCount() < 2 )
|
2012-02-19 04:02:19 +00:00
|
|
|
return false; // There must be 2 segments.
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
TRACK* curTrack = g_CurrentTrackSegment;
|
|
|
|
TRACK* prevTrack = curTrack->Back();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-06-12 16:38:43 +00:00
|
|
|
// Test if we have 2 consecutive track segments ( not via ) to connect.
|
2011-10-01 19:24:27 +00:00
|
|
|
if( curTrack->Type() != PCB_TRACE_T || prevTrack->Type() != PCB_TRACE_T )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
int segm_step_45 = KiROUND( GetScreen()->GetGridSize().x / 2 );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-06-16 19:52:12 +00:00
|
|
|
if( segm_step_45 < ( curTrack->m_Width * 2 ) )
|
|
|
|
segm_step_45 = curTrack->m_Width * 2;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
// Test if the segments are horizontal or vertical.
|
2008-12-04 04:28:11 +00:00
|
|
|
dx0 = prevTrack->m_End.x - prevTrack->m_Start.x;
|
|
|
|
dy0 = prevTrack->m_End.y - prevTrack->m_Start.y;
|
|
|
|
|
|
|
|
dx1 = curTrack->m_End.x - curTrack->m_Start.x;
|
|
|
|
dy1 = curTrack->m_End.y - curTrack->m_Start.y;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2012-01-10 20:12:46 +00:00
|
|
|
// Segments should have a min length.
|
2012-08-03 15:43:15 +00:00
|
|
|
if( std::max( abs( dx0 ), abs( dy0 ) ) < ( segm_step_45 * 2 ) )
|
2008-12-04 04:28:11 +00:00
|
|
|
return false;
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2012-08-03 15:43:15 +00:00
|
|
|
if( std::max( abs( dx1 ), abs( dy1 ) ) < ( segm_step_45 * 2 ) )
|
2008-12-04 04:28:11 +00:00
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Create a new segment and connect it with the previous 2 segments.
|
2012-01-14 19:50:32 +00:00
|
|
|
TRACK* newTrack = (TRACK*)curTrack->Clone();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
newTrack->m_Start = prevTrack->m_End;
|
|
|
|
newTrack->m_End = curTrack->m_Start;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-06-12 16:38:43 +00:00
|
|
|
if( dx0 == 0 ) // Previous segment is Vertical
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2009-11-14 22:15:22 +00:00
|
|
|
if( dy1 != 0 ) // 2 segments are not 90 degrees.
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
delete newTrack;
|
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
/* Calculate coordinates the connection point.
|
2011-06-12 16:38:43 +00:00
|
|
|
* The new segment connects the 1st vertical segment and the 2nd
|
2009-11-14 22:15:22 +00:00
|
|
|
* horizontal segment.
|
|
|
|
*/
|
2007-08-20 01:20:48 +00:00
|
|
|
if( dy0 > 0 )
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_Start.y -= segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_Start.y += segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
if( dx1 > 0 )
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_End.x += segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_End.x -= segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
if( Drc_On && BAD_DRC == m_drc->Drc( curTrack, GetBoard()->m_Track ) )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
delete newTrack;
|
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
prevTrack->m_End = newTrack->m_Start;
|
|
|
|
curTrack->m_Start = newTrack->m_End;
|
|
|
|
|
|
|
|
g_CurrentTrackList.Insert( newTrack, curTrack );
|
|
|
|
return true;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2011-06-12 16:38:43 +00:00
|
|
|
if( dy0 == 0 ) // Previous segment is horizontal
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2009-11-14 22:15:22 +00:00
|
|
|
if( dx1 != 0 ) // 2 segments are not 90 degrees
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
delete newTrack;
|
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
/* Calculate the coordinates of the point of connection:
|
2011-06-12 16:38:43 +00:00
|
|
|
* A new segment has been created, connecting segment 1
|
2009-11-14 22:15:22 +00:00
|
|
|
* (horizontal) and segment 2 (vertical)
|
|
|
|
*/
|
2007-08-20 01:20:48 +00:00
|
|
|
if( dx0 > 0 )
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_Start.x -= segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_Start.x += segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
if( dy1 > 0 )
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_End.y += segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2011-06-16 19:52:12 +00:00
|
|
|
newTrack->m_End.y -= segm_step_45;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-01-05 05:21:35 +00:00
|
|
|
if( Drc_On && BAD_DRC==m_drc->Drc( newTrack, GetBoard()->m_Track ) )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
delete newTrack;
|
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
prevTrack->m_End = newTrack->m_Start;
|
|
|
|
curTrack->m_Start = newTrack->m_End;
|
|
|
|
|
|
|
|
g_CurrentTrackList.Insert( newTrack, curTrack );
|
|
|
|
return true;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
return false;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2011-12-06 08:35:13 +00:00
|
|
|
int layerMask = GetLayerMask( GetScreen()->m_Active_Layer );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
if( aTrack == NULL )
|
2011-04-14 18:44:46 +00:00
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
if( Drc_On && BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
|
2011-04-14 18:44:46 +00:00
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Saving the coordinate of end point of the trace
|
2008-12-04 04:28:11 +00:00
|
|
|
wxPoint pos = g_CurrentTrackSegment->m_End;
|
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
if( Begin_Route( aTrack, aDC ) == NULL )
|
2011-04-14 18:44:46 +00:00
|
|
|
return false;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-22 13:28:11 +00:00
|
|
|
ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, true );
|
|
|
|
ShowNewTrackWhenMovingCursor( m_canvas, aDC, wxDefaultPosition, false );
|
2011-11-08 16:18:46 +00:00
|
|
|
TraceAirWiresToTargets( aDC );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
/* cleanup
|
2009-06-18 20:51:01 +00:00
|
|
|
* if( g_CurrentTrackSegment->Next() != NULL )
|
|
|
|
* {
|
|
|
|
* delete g_CurrentTrackSegment->Next();
|
|
|
|
* g_CurrentTrackSegment->SetNext( NULL );
|
|
|
|
* }
|
|
|
|
*/
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
/* The track here is now chained to the list of track segments.
|
2009-11-14 22:15:22 +00:00
|
|
|
* It must be seen in the area of net
|
|
|
|
* As close as possible to the segment base (or end), because
|
|
|
|
* This helps to reduce the computing time */
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// Attaching the end point of the new track to a pad or a track
|
2011-11-08 16:18:46 +00:00
|
|
|
BOARD_CONNECTED_ITEM* LockPoint = GetBoard()->GetLockPoint( pos, layerMask );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( LockPoint )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-12-04 17:57:03 +00:00
|
|
|
if( LockPoint->Type() == PCB_PAD_T ) // End of track is on a pad.
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
|
|
|
EnsureEndTrackOnPad( (D_PAD*) LockPoint );
|
|
|
|
}
|
2011-12-04 17:57:03 +00:00
|
|
|
else // If end point of is on a different track,
|
|
|
|
// creates a lock point if not exists
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2012-02-04 20:30:00 +00:00
|
|
|
// Creates a lock point, if not already exists:
|
2011-09-17 01:22:26 +00:00
|
|
|
LockPoint = GetBoard()->CreateLockPoint( g_CurrentTrackSegment->m_End,
|
2012-02-04 20:30:00 +00:00
|
|
|
(TRACK*) LockPoint,
|
2011-09-17 01:22:26 +00:00
|
|
|
&s_ItemsListPicker );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// Delete null length segments:
|
2009-01-05 05:21:35 +00:00
|
|
|
DeleteNullTrackSegments( GetBoard(), g_CurrentTrackList );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// Insert new segments if they exist.
|
|
|
|
// g_FirstTrackSegment can be NULL on a double click on the starting point
|
2007-08-20 01:20:48 +00:00
|
|
|
if( g_FirstTrackSegment != NULL )
|
|
|
|
{
|
2009-06-18 20:51:01 +00:00
|
|
|
int netcode = g_FirstTrackSegment->GetNet();
|
|
|
|
TRACK* firstTrack = g_FirstTrackSegment;
|
|
|
|
int newCount = g_CurrentTrackList.GetCount();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
// Put entire new current segment list in BOARD, and prepare undo command
|
2008-12-04 04:28:11 +00:00
|
|
|
TRACK* track;
|
2011-09-07 19:41:04 +00:00
|
|
|
TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( GetBoard() );
|
|
|
|
|
2009-06-18 20:51:01 +00:00
|
|
|
while( ( track = g_CurrentTrackList.PopFront() ) != NULL )
|
2008-12-04 04:28:11 +00:00
|
|
|
{
|
2009-08-08 06:07:08 +00:00
|
|
|
ITEM_PICKER picker( track, UR_NEW );
|
|
|
|
s_ItemsListPicker.PushItem( picker );
|
2009-01-05 05:21:35 +00:00
|
|
|
GetBoard()->m_Track.Insert( track, insertBeforeMe );
|
2008-12-04 04:28:11 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-11-08 16:18:46 +00:00
|
|
|
TraceAirWiresToTargets( aDC );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
int i = 0;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
for( track = firstTrack; track && i < newCount; ++i, track = track->Next() )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-12-21 13:42:02 +00:00
|
|
|
track->ClearFlags();
|
2009-03-05 15:58:06 +00:00
|
|
|
track->SetState( BUSY, OFF );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// delete the old track, if it exists and is redundant
|
2007-08-20 01:20:48 +00:00
|
|
|
if( g_AutoDeleteOldTrack )
|
|
|
|
{
|
2011-09-15 17:58:35 +00:00
|
|
|
EraseRedundantTrack( aDC, firstTrack, newCount, &s_ItemsListPicker );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
SaveCopyInUndoList( s_ItemsListPicker, UR_UNSPECIFIED );
|
2011-09-15 17:58:35 +00:00
|
|
|
s_ItemsListPicker.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
// compute the new ratsnest
|
2011-09-15 17:58:35 +00:00
|
|
|
TestNetConnection( aDC, netcode );
|
2010-02-19 13:23:58 +00:00
|
|
|
OnModify();
|
2009-04-17 08:51:02 +00:00
|
|
|
GetBoard()->DisplayInfo( this );
|
2011-12-04 17:57:03 +00:00
|
|
|
|
|
|
|
// Redraw the entire new track.
|
2011-12-22 13:28:11 +00:00
|
|
|
DrawTraces( m_canvas, aDC, firstTrack, newCount, GR_OR );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
wxASSERT( g_FirstTrackSegment == NULL );
|
|
|
|
wxASSERT( g_CurrentTrackSegment == NULL );
|
|
|
|
wxASSERT( g_CurrentTrackList.GetCount() == 0 );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
if( GetBoard()->IsHighLightNetON() )
|
2011-10-17 20:01:27 +00:00
|
|
|
HighLight( aDC );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
GetBoard()->PopHighLight();
|
2011-02-11 20:48:13 +00:00
|
|
|
|
2011-09-14 20:04:58 +00:00
|
|
|
if( GetBoard()->IsHighLightNetON() )
|
2011-12-22 13:28:11 +00:00
|
|
|
GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-12-22 13:28:11 +00:00
|
|
|
m_canvas->SetMouseCapture( NULL, NULL );
|
2007-09-12 02:14:07 +00:00
|
|
|
SetCurItem( NULL );
|
2011-04-14 18:44:46 +00:00
|
|
|
|
|
|
|
return true;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2011-01-30 22:22:38 +00:00
|
|
|
TRACK* LocateIntrusion( TRACK* listStart, TRACK* aTrack, int aLayer, const wxPoint& aRef )
|
2008-02-27 15:26:16 +00:00
|
|
|
{
|
2009-09-10 15:22:26 +00:00
|
|
|
int net = aTrack->GetNet();
|
|
|
|
int width = aTrack->m_Width;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2008-02-29 20:35:11 +00:00
|
|
|
TRACK* found = NULL;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
for( TRACK* track = listStart; track; track = track->Next() )
|
2008-02-29 20:35:11 +00:00
|
|
|
{
|
2011-10-01 19:24:27 +00:00
|
|
|
if( track->Type() == PCB_TRACE_T ) // skip vias
|
2008-02-29 20:35:11 +00:00
|
|
|
{
|
2011-02-13 17:53:48 +00:00
|
|
|
if( track->GetState( BUSY | IS_DELETED ) )
|
2008-02-29 20:35:11 +00:00
|
|
|
continue;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2011-01-30 22:22:38 +00:00
|
|
|
if( aLayer != track->GetLayer() )
|
2008-02-29 20:35:11 +00:00
|
|
|
continue;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2008-02-29 20:35:11 +00:00
|
|
|
if( track->GetNet() == net )
|
|
|
|
continue;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// TRACK::HitTest
|
2011-01-30 22:22:38 +00:00
|
|
|
int dist = (width + track->m_Width) / 2 + aTrack->GetClearance( track );
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2011-01-30 22:22:38 +00:00
|
|
|
wxPoint pos = aRef - track->m_Start;
|
2009-06-18 20:51:01 +00:00
|
|
|
wxPoint vec = track->m_End - track->m_Start;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2008-02-29 20:35:11 +00:00
|
|
|
if( !DistanceTest( dist, vec.x, vec.y, pos.x, pos.y ) )
|
|
|
|
continue;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2008-02-29 20:35:11 +00:00
|
|
|
found = track;
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// prefer intrusions from the side, not the end
|
2008-02-29 23:01:30 +00:00
|
|
|
double tmp = (double) pos.x * vec.x + (double) pos.y * vec.y;
|
2011-01-30 22:22:38 +00:00
|
|
|
|
|
|
|
if( tmp >= 0 && tmp <= (double) vec.x * vec.x + (double) vec.y * vec.y )
|
2008-02-29 20:35:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-02-27 15:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function PushTrack
|
|
|
|
* detects if the mouse is pointing into a conflicting track.
|
2008-02-26 21:12:08 +00:00
|
|
|
* In this case, it tries to push the new track out of the conflicting track's
|
|
|
|
* clearance zone. This gives us a cheap mechanism for drawing tracks that
|
|
|
|
* tightly follow others, independent of grid settings.
|
|
|
|
*
|
|
|
|
* KNOWN BUGS:
|
|
|
|
* - we do the same sort of search and calculation up to three times:
|
|
|
|
* 1) we search for magnetic hits (in controle.cpp)
|
|
|
|
* 2) we check if there's a DRC violation in the making (also controle.cpp)
|
|
|
|
* 3) we try to fix the DRC violation (here)
|
|
|
|
* - if we have a magnetic hit and a DRC violation at the same time, we choose
|
|
|
|
* the magnetic hit instead of solving the violation
|
|
|
|
* - should locate conflicting tracks also when we're crossing over them
|
|
|
|
*/
|
2011-01-21 19:30:59 +00:00
|
|
|
static void PushTrack( EDA_DRAW_PANEL* panel )
|
2008-02-26 21:12:08 +00:00
|
|
|
{
|
2011-03-01 19:26:17 +00:00
|
|
|
PCB_SCREEN* screen = ( (PCB_BASE_FRAME*) (panel->GetParent()) )->GetScreen();
|
|
|
|
BOARD* pcb = ( (PCB_BASE_FRAME*) (panel->GetParent()) )->GetBoard();
|
2011-02-11 20:48:13 +00:00
|
|
|
wxPoint cursor = screen->GetCrossHairPosition();
|
2008-02-26 21:12:08 +00:00
|
|
|
wxPoint cv, vec, n;
|
2008-02-27 15:26:16 +00:00
|
|
|
TRACK* track = g_CurrentTrackSegment;
|
|
|
|
TRACK* other;
|
2008-02-29 23:01:30 +00:00
|
|
|
double det;
|
2008-02-27 15:26:16 +00:00
|
|
|
int dist;
|
|
|
|
double f;
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2011-01-30 22:22:38 +00:00
|
|
|
other = LocateIntrusion( pcb->m_Track, track, screen->m_Active_Layer, screen->RefPos( true ) );
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// are we currently pointing into a conflicting trace ?
|
2008-02-27 15:26:16 +00:00
|
|
|
if( !other )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( other->GetNet() == track->GetNet() )
|
|
|
|
return;
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2008-02-27 15:26:16 +00:00
|
|
|
cv = cursor - other->m_Start;
|
|
|
|
vec = other->m_End - other->m_Start;
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2008-02-29 23:01:30 +00:00
|
|
|
det = (double) cv.x * vec.y - (double) cv.y * vec.x;
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// cursor is right at the center of the old track
|
2008-02-27 15:26:16 +00:00
|
|
|
if( !det )
|
|
|
|
return;
|
|
|
|
|
2011-09-07 19:41:04 +00:00
|
|
|
dist = (track->m_Width + 1) / 2 + (other->m_Width + 1) / 2 + track->GetClearance( other ) + 2;
|
2008-02-27 15:26:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* DRC wants >, so +1.
|
|
|
|
* We may have a quantization error of 1/sqrt(2), so +1 again.
|
|
|
|
*/
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Vector "n" is perpendicular to "other", pointing towards the cursor.
|
2008-02-27 15:26:16 +00:00
|
|
|
if( det > 0 )
|
|
|
|
{
|
|
|
|
n.x = vec.y;
|
|
|
|
n.y = -vec.x;
|
2008-02-26 21:12:08 +00:00
|
|
|
}
|
2008-02-27 15:26:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
n.x = -vec.y;
|
|
|
|
n.y = vec.x;
|
2008-02-26 21:12:08 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-02-29 23:01:30 +00:00
|
|
|
f = dist / hypot( double(n.x), double(n.y) );
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
n.x = KiROUND( f * n.x );
|
|
|
|
n.y = KiROUND( f * n.y );
|
2008-02-26 21:12:08 +00:00
|
|
|
|
2008-02-29 20:35:11 +00:00
|
|
|
Project( &track->m_End, cursor, other );
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End += n;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2008-02-27 15:26:16 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
/* Redraw the current track being created when the mouse cursor is moved
|
2007-08-20 01:20:48 +00:00
|
|
|
*/
|
2011-02-03 19:27:28 +00:00
|
|
|
void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
|
|
|
|
bool aErase )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
|
|
|
|
2011-03-01 19:26:17 +00:00
|
|
|
PCB_SCREEN* screen = (PCB_SCREEN*) aPanel->GetScreen();
|
|
|
|
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
bool Track_fill_copy = DisplayOpt.DisplayPcbTrackFill;
|
2009-05-21 17:42:42 +00:00
|
|
|
DisplayOpt.DisplayPcbTrackFill = true;
|
2011-09-24 18:33:28 +00:00
|
|
|
TRACE_CLEARANCE_DISPLAY_MODE_T showTrackClearanceMode = DisplayOpt.ShowTrackClearanceMode;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-02-03 19:27:28 +00:00
|
|
|
if ( g_FirstTrackSegment == NULL )
|
2010-12-18 09:26:01 +00:00
|
|
|
return;
|
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
NETCLASS* netclass = g_FirstTrackSegment->GetNetClass();
|
|
|
|
|
2009-06-18 20:51:01 +00:00
|
|
|
if( showTrackClearanceMode != DO_NOT_SHOW_CLEARANCE )
|
|
|
|
DisplayOpt.ShowTrackClearanceMode = SHOW_CLEARANCE_ALWAYS;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-05-20 18:25:11 +00:00
|
|
|
#ifndef USE_WX_OVERLAY
|
2012-02-19 04:02:19 +00:00
|
|
|
// Erase old track
|
2011-02-03 19:27:28 +00:00
|
|
|
if( aErase )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-09-07 19:41:04 +00:00
|
|
|
DrawTraces( aPanel, aDC, g_FirstTrackSegment, g_CurrentTrackList.GetCount(), GR_XOR );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2011-11-08 16:18:46 +00:00
|
|
|
frame->TraceAirWiresToTargets( aDC );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
if( showTrackClearanceMode >= SHOW_CLEARANCE_NEW_TRACKS_AND_VIA_AREAS )
|
2009-06-18 17:32:27 +00:00
|
|
|
{
|
2011-09-15 17:58:35 +00:00
|
|
|
int color = g_ColorsSettings.GetLayerColor( g_CurrentTrackSegment->GetLayer() );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCircle( aPanel->GetClipBox(), aDC, g_CurrentTrackSegment->m_End.x,
|
2009-06-18 20:51:01 +00:00
|
|
|
g_CurrentTrackSegment->m_End.y,
|
2009-11-14 22:15:22 +00:00
|
|
|
( netclass->GetViaDiameter() / 2 ) + netclass->GetClearance(),
|
2009-06-18 20:51:01 +00:00
|
|
|
color );
|
2009-06-18 17:32:27 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2011-05-20 18:25:11 +00:00
|
|
|
#endif
|
2009-03-30 19:28:54 +00:00
|
|
|
// MacOSX seems to need this.
|
|
|
|
if( g_CurrentTrackList.GetCount() == 0 )
|
|
|
|
return;
|
|
|
|
|
2009-10-03 17:18:08 +00:00
|
|
|
// Set track parameters, that can be modified while creating the track
|
2007-08-23 04:28:46 +00:00
|
|
|
g_CurrentTrackSegment->SetLayer( screen->m_Active_Layer );
|
2011-02-03 19:27:28 +00:00
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
|
2010-10-14 12:17:14 +00:00
|
|
|
g_CurrentTrackSegment->m_Width = frame->GetBoard()->GetCurrentTrackWidth();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( g_TwoSegmentTrackBuild )
|
|
|
|
{
|
2008-11-24 06:53:43 +00:00
|
|
|
TRACK* previous_track = g_CurrentTrackSegment->Back();
|
2011-02-03 19:27:28 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
if( previous_track && previous_track->Type()==PCB_TRACE_T )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2007-08-23 04:28:46 +00:00
|
|
|
previous_track->SetLayer( screen->m_Active_Layer );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
++PCBNew
* Removed Pcb_Frame argument from BOARD() constructor, since it precludes
having a BOARD being edited by more than one editor, it was a bad design.
And this meant removing m_PcbFrame from BOARD.
* removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame
* Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp
* added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance
* a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed,
such as dialog_mask_clearance, dialog_drc, etc.
* Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it
with build_version.h's #define BOARD_FILE_VERSION, although there may be a
better place for this constant.
* Made the public functions in PARAM_CFG_ARRAY be type const.
void SaveParam(..) const and void ReadParam(..) const
* PARAM_CFG_BASE now has virtual destructor since we have various way of
destroying the derived class and boost::ptr_vector must be told about this.
* Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use
an automatic PARAM_CFG_ARRAY which is on the stack.\
* PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array,
since it has to access the current BOARD and the BOARD can change.
Remember BOARD_DESIGN_SETTINGS are now in the BOARD.
* Made the m_BoundingBox member private, this was a brutally hard task,
and indicative of the lack of commitment to accessors and object oriented
design on the part of KiCad developers. We must do better.
Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox().
* Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
2011-12-05 06:15:33 +00:00
|
|
|
if( !frame->GetBoard()->GetDesignSettings().m_UseConnectedTrackWidth )
|
2011-02-03 19:27:28 +00:00
|
|
|
previous_track->m_Width = frame->GetBoard()->GetCurrentTrackWidth();
|
2008-02-12 01:02:53 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2010-05-01 09:22:12 +00:00
|
|
|
if( g_Track_45_Only_Allowed )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
if( g_TwoSegmentTrackBuild )
|
|
|
|
{
|
2011-02-11 20:48:13 +00:00
|
|
|
g_CurrentTrackSegment->m_End = screen->GetCrossHairPosition();
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
if( Drc_On )
|
2011-02-03 19:27:28 +00:00
|
|
|
PushTrack( aPanel );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
ComputeBreakPoint( g_CurrentTrackSegment,
|
|
|
|
g_CurrentTrackList.GetCount(),
|
2009-06-18 20:51:01 +00:00
|
|
|
g_CurrentTrackSegment->m_End );
|
2008-12-04 04:28:11 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
|
|
|
{
|
2009-11-14 22:15:22 +00:00
|
|
|
/* Calculate of the end of the path for the permitted directions:
|
|
|
|
* horizontal, vertical or 45 degrees.
|
2008-12-04 04:28:11 +00:00
|
|
|
*/
|
2011-09-07 19:41:04 +00:00
|
|
|
CalculateSegmentEndPoint( screen->GetCrossHairPosition(),
|
2011-09-15 17:58:35 +00:00
|
|
|
g_CurrentTrackSegment->m_Start.x,
|
|
|
|
g_CurrentTrackSegment->m_Start.y,
|
|
|
|
&g_CurrentTrackSegment->m_End.x,
|
|
|
|
&g_CurrentTrackSegment->m_End.y );
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-19 04:02:19 +00:00
|
|
|
else // Here the angle is arbitrary
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2011-02-11 20:48:13 +00:00
|
|
|
g_CurrentTrackSegment->m_End = screen->GetCrossHairPosition();
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Redraw the new track
|
2008-12-04 04:28:11 +00:00
|
|
|
D( g_CurrentTrackList.VerifyListIntegrity(); );
|
2011-09-07 19:41:04 +00:00
|
|
|
DrawTraces( aPanel, aDC, g_FirstTrackSegment, g_CurrentTrackList.GetCount(), GR_XOR );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
if( showTrackClearanceMode >= SHOW_CLEARANCE_NEW_TRACKS_AND_VIA_AREAS )
|
2009-06-18 17:32:27 +00:00
|
|
|
{
|
2011-02-03 19:27:28 +00:00
|
|
|
int color = g_ColorsSettings.GetLayerColor(g_CurrentTrackSegment->GetLayer());
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCircle( aPanel->GetClipBox(), aDC, g_CurrentTrackSegment->m_End.x,
|
2009-06-18 20:51:01 +00:00
|
|
|
g_CurrentTrackSegment->m_End.y,
|
2009-11-14 22:15:22 +00:00
|
|
|
( netclass->GetViaDiameter() / 2 ) + netclass->GetClearance(),
|
2009-06-18 20:51:01 +00:00
|
|
|
color );
|
2009-06-18 17:32:27 +00:00
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
/* Display info about current segment and the full new track:
|
2009-10-14 18:14:58 +00:00
|
|
|
* Choose the interesting segment: because we are using a 2 segments step,
|
2009-11-14 22:15:22 +00:00
|
|
|
* the last segment can be null, and the previous segment can be the
|
|
|
|
* interesting segment.
|
2009-10-14 18:14:58 +00:00
|
|
|
*/
|
|
|
|
TRACK* isegm = g_CurrentTrackSegment;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
if( isegm->GetLength() == 0 && g_CurrentTrackSegment->Back() )
|
|
|
|
isegm = g_CurrentTrackSegment->Back();
|
|
|
|
|
|
|
|
// display interesting segment info only:
|
|
|
|
isegm->DisplayInfoBase( frame );
|
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
// Display current track length (on board) and the the actual track len
|
2011-08-20 14:46:48 +00:00
|
|
|
// if there is an extra len due to the len die on the starting pad (if any)
|
2010-01-13 21:15:54 +00:00
|
|
|
double trackLen = 0.0;
|
2011-08-20 14:46:48 +00:00
|
|
|
double lenDie = 0.0;
|
2009-10-14 18:14:58 +00:00
|
|
|
wxString msg;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-09-15 17:58:35 +00:00
|
|
|
// If the starting point is on a pad, add current track length+ length die
|
2011-08-20 14:46:48 +00:00
|
|
|
if( g_FirstTrackSegment->GetState( BEGIN_ONPAD ) )
|
|
|
|
{
|
|
|
|
D_PAD * pad = (D_PAD *) g_FirstTrackSegment->start;
|
2012-02-19 04:02:19 +00:00
|
|
|
lenDie = (double) pad->GetDieLength();
|
2011-09-07 19:41:04 +00:00
|
|
|
}
|
|
|
|
|
2011-08-20 14:46:48 +00:00
|
|
|
// calculate track len on board:
|
2009-10-14 18:14:58 +00:00
|
|
|
for( TRACK* track = g_FirstTrackSegment; track; track = track->Next() )
|
|
|
|
trackLen += track->GetLength();
|
|
|
|
|
2012-04-27 14:15:11 +00:00
|
|
|
msg = frame->LengthDoubleToString( trackLen );
|
2009-10-16 17:18:23 +00:00
|
|
|
frame->AppendMsgPanel( _( "Track Len" ), msg, DARKCYAN );
|
2009-10-14 18:14:58 +00:00
|
|
|
|
2011-08-20 14:46:48 +00:00
|
|
|
if( lenDie != 0 ) // display the track len on board and the actual track len
|
|
|
|
{
|
|
|
|
frame->AppendMsgPanel( _( "Full Len" ), msg, DARKCYAN );
|
2012-04-27 14:15:11 +00:00
|
|
|
msg = frame->LengthDoubleToString( trackLen+lenDie );
|
2011-08-20 14:46:48 +00:00
|
|
|
frame->AppendMsgPanel( _( "On Die" ), msg, DARKCYAN );
|
|
|
|
}
|
|
|
|
|
2009-10-14 18:14:58 +00:00
|
|
|
// Add current segments count (number of segments in this new track):
|
|
|
|
msg.Printf( wxT( "%d" ), g_CurrentTrackList.GetCount() );
|
2009-10-16 17:18:23 +00:00
|
|
|
frame->AppendMsgPanel( _( "Segs Count" ), msg, DARKCYAN );
|
2009-10-14 18:14:58 +00:00
|
|
|
|
2009-06-18 20:51:01 +00:00
|
|
|
DisplayOpt.ShowTrackClearanceMode = showTrackClearanceMode;
|
|
|
|
DisplayOpt.DisplayPcbTrackFill = Track_fill_copy;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-11-08 16:18:46 +00:00
|
|
|
frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->m_End, false );
|
|
|
|
frame->TraceAirWiresToTargets( aDC );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
/* Determine the coordinate to advanced the the current segment
|
2011-01-31 18:26:12 +00:00
|
|
|
* in 0, 90, or 45 degrees, depending on position of origin and \a aPosition.
|
2007-08-20 01:20:48 +00:00
|
|
|
*/
|
2011-09-07 19:41:04 +00:00
|
|
|
void CalculateSegmentEndPoint( const wxPoint& aPosition, int ox, int oy, int* fx, int* fy )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-20 01:20:48 +00:00
|
|
|
int deltax, deltay, angle;
|
|
|
|
|
2011-01-31 18:26:12 +00:00
|
|
|
deltax = aPosition.x - ox;
|
|
|
|
deltay = aPosition.y - oy;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
deltax = abs( deltax );
|
|
|
|
deltay = abs( deltay );
|
2009-06-18 20:51:01 +00:00
|
|
|
angle = 45;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( deltax >= deltay )
|
|
|
|
{
|
|
|
|
if( deltax == 0 )
|
|
|
|
angle = 0;
|
|
|
|
else if( ( (deltay << 6 ) / deltax ) < 26 )
|
|
|
|
angle = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
angle = 45;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( deltay == 0 )
|
|
|
|
angle = 90;
|
|
|
|
else if( ( (deltax << 6 ) / deltay ) < 26 )
|
|
|
|
angle = 90;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( angle )
|
|
|
|
{
|
|
|
|
case 0:
|
2011-01-31 18:26:12 +00:00
|
|
|
*fx = aPosition.x;
|
2007-08-20 01:20:48 +00:00
|
|
|
*fy = oy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 45:
|
2012-08-03 15:43:15 +00:00
|
|
|
deltax = std::min( deltax, deltay );
|
2008-12-04 04:28:11 +00:00
|
|
|
deltay = deltax;
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Recalculate the signs for deltax and deltaY.
|
2011-01-31 18:26:12 +00:00
|
|
|
if( ( aPosition.x - ox ) < 0 )
|
2007-08-20 01:20:48 +00:00
|
|
|
deltax = -deltax;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-01-31 18:26:12 +00:00
|
|
|
if( ( aPosition.y - oy ) < 0 )
|
2007-08-20 01:20:48 +00:00
|
|
|
deltay = -deltay;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
*fx = ox + deltax;
|
|
|
|
*fy = oy + deltay;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 90:
|
|
|
|
*fx = ox;
|
2011-01-31 18:26:12 +00:00
|
|
|
*fy = aPosition.y;
|
2007-08-20 01:20:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute new track angle based on previous track.
|
|
|
|
*/
|
2009-11-14 22:15:22 +00:00
|
|
|
void ComputeBreakPoint( TRACK* track, int SegmentCount, wxPoint end )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-20 01:20:48 +00:00
|
|
|
int iDx = 0;
|
|
|
|
int iDy = 0;
|
|
|
|
int iAngle = 0;
|
|
|
|
|
|
|
|
if( SegmentCount <= 0 )
|
|
|
|
return;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( track == NULL )
|
|
|
|
return;
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
TRACK* newTrack = track;
|
2008-11-24 06:53:43 +00:00
|
|
|
track = track->Back();
|
2007-08-20 01:20:48 +00:00
|
|
|
SegmentCount--;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( track )
|
|
|
|
{
|
2008-02-26 21:12:08 +00:00
|
|
|
iDx = end.x - track->m_Start.x;
|
|
|
|
iDy = end.y - track->m_Start.y;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
iDx = abs( iDx );
|
|
|
|
iDy = abs( iDy );
|
|
|
|
}
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
TRACK* lastTrack = track ? track->Back() : NULL;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
if( lastTrack )
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2010-06-16 15:01:45 +00:00
|
|
|
if(( (lastTrack->m_End.x == lastTrack->m_Start.x)
|
2009-06-18 20:51:01 +00:00
|
|
|
|| (lastTrack->m_End.y == lastTrack->m_Start.y) )
|
2011-09-15 17:58:35 +00:00
|
|
|
&& !g_Alternate_Track_Posture)
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
|
|
|
iAngle = 45;
|
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( g_Alternate_Track_Posture )
|
|
|
|
{
|
|
|
|
iAngle = 45;
|
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( iAngle == 0 )
|
|
|
|
{
|
|
|
|
if( iDx >= iDy )
|
|
|
|
iAngle = 0;
|
|
|
|
else
|
|
|
|
iAngle = 90;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( track == NULL )
|
|
|
|
iAngle = -1;
|
|
|
|
|
|
|
|
switch( iAngle )
|
|
|
|
{
|
2009-11-14 22:15:22 +00:00
|
|
|
case -1:
|
2007-08-20 01:20:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
2009-11-14 22:15:22 +00:00
|
|
|
if( ( end.x - track->m_Start.x ) < 0 )
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End.x = end.x + iDy;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End.x = end.x - iDy;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
track->m_End.y = track->m_Start.y;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 45:
|
2012-08-03 15:43:15 +00:00
|
|
|
iDx = std::min( iDx, iDy );
|
2007-08-20 01:20:48 +00:00
|
|
|
iDy = iDx;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
// Recalculate the signs for deltax and deltaY.
|
2009-11-14 22:15:22 +00:00
|
|
|
if( ( end.x - track->m_Start.x ) < 0 )
|
2007-08-20 01:20:48 +00:00
|
|
|
iDx = -iDx;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2009-11-14 22:15:22 +00:00
|
|
|
if( ( end.y - track->m_Start.y ) < 0 )
|
2007-08-20 01:20:48 +00:00
|
|
|
iDy = -iDy;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
track->m_End.x = track->m_Start.x + iDx;
|
|
|
|
track->m_End.y = track->m_Start.y + iDy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 90:
|
2009-11-14 22:15:22 +00:00
|
|
|
if( ( end.y - track->m_Start.y ) < 0 )
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End.y = end.y + iDx;
|
2007-08-20 01:20:48 +00:00
|
|
|
else
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End.y = end.y - iDx;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
track->m_End.x = track->m_Start.x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( track )
|
|
|
|
{
|
|
|
|
if( track->IsNull() )
|
2008-02-26 21:12:08 +00:00
|
|
|
track->m_End = end;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
|
|
|
newTrack->m_Start = track->m_End;
|
2007-08-20 01:20:48 +00:00
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
newTrack->m_End = end;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
/* Delete track segments which have len = 0 after creating a new track
|
2007-08-20 01:20:48 +00:00
|
|
|
* return a pointer on the first segment (start of track list)
|
|
|
|
*/
|
2009-11-14 22:15:22 +00:00
|
|
|
void DeleteNullTrackSegments( BOARD* pcb, DLIST<TRACK>& aTrackList )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2008-12-04 04:28:11 +00:00
|
|
|
if( aTrackList.GetCount() == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
TRACK* track = aTrackList.GetFirst();
|
2008-01-28 18:44:14 +00:00
|
|
|
TRACK* firsttrack = track;
|
|
|
|
TRACK* oldtrack;
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-11-03 19:07:59 +00:00
|
|
|
BOARD_CONNECTED_ITEM* LockPoint = track->start;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
while( track != NULL )
|
|
|
|
{
|
|
|
|
oldtrack = track;
|
|
|
|
track = track->Next();
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( !oldtrack->IsNull() )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NULL segment, delete it
|
|
|
|
if( firsttrack == oldtrack )
|
|
|
|
firsttrack = track;
|
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
delete aTrackList.Remove( oldtrack );
|
|
|
|
}
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2008-12-04 04:28:11 +00:00
|
|
|
if( aTrackList.GetCount() == 0 )
|
|
|
|
return; // all the new track segments have been deleted
|
2007-08-20 01:20:48 +00:00
|
|
|
|
|
|
|
// we must set the pointers on connected items and the connection status
|
|
|
|
oldtrack = track = firsttrack;
|
|
|
|
firsttrack->start = NULL;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
while( track != NULL )
|
|
|
|
{
|
2009-06-18 20:51:01 +00:00
|
|
|
oldtrack = track;
|
|
|
|
track = track->Next();
|
2007-08-20 01:20:48 +00:00
|
|
|
oldtrack->end = track;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( track )
|
|
|
|
track->start = oldtrack;
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
oldtrack->SetStatus( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
firsttrack->start = LockPoint;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2011-12-04 17:57:03 +00:00
|
|
|
if( LockPoint && LockPoint->Type()==PCB_PAD_T )
|
2007-08-20 01:20:48 +00:00
|
|
|
firsttrack->SetState( BEGIN_ONPAD, ON );
|
|
|
|
|
|
|
|
track = firsttrack;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
while( track != NULL )
|
|
|
|
{
|
|
|
|
TRACK* next_track = track->Next();
|
2012-07-25 18:46:25 +00:00
|
|
|
LockPoint = pcb->GetPad( track, FLG_END );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( LockPoint )
|
|
|
|
{
|
|
|
|
track->end = LockPoint;
|
|
|
|
track->SetState( END_ONPAD, ON );
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( next_track )
|
|
|
|
{
|
|
|
|
next_track->start = LockPoint;
|
|
|
|
next_track->SetState( BEGIN_ONPAD, ON );
|
|
|
|
}
|
|
|
|
}
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
track = next_track;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
|
2011-08-20 14:46:48 +00:00
|
|
|
/* Ensure the end point of g_CurrentTrackSegment is on the pad "Pad"
|
2007-08-20 01:20:48 +00:00
|
|
|
* if no, create a new track segment if necessary
|
|
|
|
* and move current (or new) end segment on pad
|
|
|
|
*/
|
2012-02-19 04:02:19 +00:00
|
|
|
void EnsureEndTrackOnPad( D_PAD* aPad )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
if( g_CurrentTrackSegment->m_End == aPad->GetPosition() ) // Ok !
|
2007-08-20 01:20:48 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
g_CurrentTrackSegment->end = aPad;
|
2007-08-20 01:20:48 +00:00
|
|
|
g_CurrentTrackSegment->SetState( END_ONPAD, ON );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACK* lasttrack = g_CurrentTrackSegment;
|
2011-09-07 19:41:04 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
if( !g_CurrentTrackSegment->IsNull() )
|
2008-01-28 18:44:14 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
// Must create a new segment, from track end to pad center
|
2012-01-14 19:50:32 +00:00
|
|
|
g_CurrentTrackList.PushBack( (TRACK*)lasttrack->Clone() );
|
2008-12-04 04:28:11 +00:00
|
|
|
|
2007-08-20 01:20:48 +00:00
|
|
|
lasttrack->end = g_CurrentTrackSegment;
|
|
|
|
}
|
2008-01-28 18:44:14 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
g_CurrentTrackSegment->m_End = aPad->GetPosition();
|
2007-08-20 01:20:48 +00:00
|
|
|
g_CurrentTrackSegment->SetState( END_ONPAD, OFF );
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
g_CurrentTrackSegment->end = aPad;
|
2007-08-20 01:20:48 +00:00
|
|
|
g_CurrentTrackSegment->SetState( END_ONPAD, ON );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|