Pcbnew: add drc test for texts on copper layer (only in full drc test, not in on line drc), from a patch sent by Simon Schumann
Add EDA_TEXT::TransformTextShapeToSegmentList function to export a list of segments used to draw/plot the text.
This commit is contained in:
parent
adbf343fef
commit
c8d69f19c8
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <eda_text.h>
|
||||
#include <drawtxt.h>
|
||||
#include <macros.h>
|
||||
#include <trigo.h> // RotatePoint
|
||||
#include <class_drawpanel.h> // EDA_DRAW_PANEL
|
||||
|
||||
|
@ -447,3 +448,55 @@ void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert the text shape to a list of segment
|
||||
// each segment is stored as 2 wxPoints: its starting point and its ending point
|
||||
// we are using DrawGraphicText to create the segments.
|
||||
// and therefore a call-back function is needed
|
||||
static std::vector<wxPoint>* s_cornerBuffer;
|
||||
|
||||
// This is a call back function, used by DrawGraphicText to put each segment in buffer
|
||||
static void addTextSegmToBuffer( int x0, int y0, int xf, int yf )
|
||||
{
|
||||
s_cornerBuffer->push_back( wxPoint( x0, y0 ) );
|
||||
s_cornerBuffer->push_back( wxPoint( xf, yf ) );
|
||||
}
|
||||
|
||||
void EDA_TEXT::TransformTextShapeToSegmentList( std::vector<wxPoint>& aCornerBuffer ) const
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
|
||||
if( IsMirrored() )
|
||||
NEGATE( size.x );
|
||||
|
||||
s_cornerBuffer = &aCornerBuffer;
|
||||
EDA_COLOR_T color = BLACK; // not actually used, but needed by DrawGraphicText
|
||||
|
||||
if( IsMultilineAllowed() )
|
||||
{
|
||||
wxArrayString* list = wxStringSplit( GetText(), '\n' );
|
||||
std::vector<wxPoint> positions;
|
||||
positions.reserve( list->Count() );
|
||||
GetPositionsOfLinesOfMultilineText( positions, list->Count() );
|
||||
|
||||
for( unsigned ii = 0; ii < list->Count(); ii++ )
|
||||
{
|
||||
wxString txt = list->Item( ii );
|
||||
DrawGraphicText( NULL, NULL, positions[ii], color,
|
||||
txt, GetOrientation(), size,
|
||||
GetHorizJustify(), GetVertJustify(),
|
||||
GetThickness(), IsItalic(),
|
||||
true, addTextSegmToBuffer );
|
||||
}
|
||||
|
||||
delete list;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawGraphicText( NULL, NULL, GetTextPosition(), color,
|
||||
GetText(), GetOrientation(), size,
|
||||
GetHorizJustify(), GetVertJustify(),
|
||||
GetThickness(), IsItalic(),
|
||||
true, addTextSegmToBuffer );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,6 +202,14 @@ public:
|
|||
GR_DRAWMODE aDrawMode, EDA_DRAW_MODE_T aDisplay_mode = LINE,
|
||||
EDA_COLOR_T aAnchor_color = UNSPECIFIED_COLOR );
|
||||
|
||||
/**
|
||||
* Convert the text shape to a list of segment
|
||||
* each segment is stored as 2 wxPoints: the starting point and the ending point
|
||||
* there are therefore 2*n points
|
||||
* @param aCornerBuffer = a buffer to store the polygon
|
||||
*/
|
||||
void TransformTextShapeToSegmentList( std::vector<wxPoint>& aCornerBuffer ) const;
|
||||
|
||||
/**
|
||||
* Function TextHitTest
|
||||
* Test if \a aPoint is within the bounds of this object.
|
||||
|
|
|
@ -309,11 +309,11 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
|
|||
|
||||
/**
|
||||
* Function TransformBoundingBoxWithClearanceToPolygon
|
||||
* Convert the text bonding box to a rectangular polygon
|
||||
* Convert the text bounding box to a rectangular polygon
|
||||
* Used in filling zones calculations
|
||||
* Circles and arcs are approximated by segments
|
||||
* @param aCornerBuffer = a buffer to store the polygon
|
||||
* @param aClearanceValue = the clearance around the pad
|
||||
* @param aClearanceValue = the clearance around the text bounding box
|
||||
*/
|
||||
void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
|
||||
CPOLYGONS_LIST& aCornerBuffer,
|
||||
|
|
|
@ -111,6 +111,15 @@ wxString DRC_ITEM::GetErrorText() const
|
|||
case DRCE_PAD_INSIDE_KEEPOUT:
|
||||
return wxString( _("Pad inside a keepout area"));
|
||||
|
||||
case DRCE_VIA_INSIDE_TEXT:
|
||||
return wxString( _("Via inside a text"));
|
||||
|
||||
case DRCE_TRACK_INSIDE_TEXT:
|
||||
return wxString( _("Track inside a text"));
|
||||
|
||||
case DRCE_PAD_INSIDE_TEXT:
|
||||
return wxString( _("Pad inside a text"));
|
||||
|
||||
default:
|
||||
{
|
||||
wxString msg;
|
||||
|
|
154
pcbnew/drc.cpp
154
pcbnew/drc.cpp
|
@ -2,9 +2,9 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2007 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
|
||||
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
|
||||
* Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2004-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com
|
||||
* Copyright (C) 2014 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -24,9 +24,9 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/****************************/
|
||||
/* DRC control */
|
||||
/****************************/
|
||||
/**
|
||||
* @file drc.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <wxPcbStruct.h>
|
||||
|
@ -38,8 +38,10 @@
|
|||
#include <class_track.h>
|
||||
#include <class_pad.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_pcb_text.h>
|
||||
#include <class_draw_panel_gal.h>
|
||||
#include <view/view.h>
|
||||
#include <geometry/seg.h>
|
||||
|
||||
#include <pcbnew.h>
|
||||
#include <drc_stuff.h>
|
||||
|
@ -261,6 +263,15 @@ void DRC::RunTests( wxTextCtrl* aMessages )
|
|||
testKeepoutAreas();
|
||||
}
|
||||
|
||||
// find and gather vias, tracks, pads inside text boxes.
|
||||
if( aMessages )
|
||||
{
|
||||
aMessages->AppendText( _( "Test texts...\n" ) );
|
||||
wxSafeYield();
|
||||
}
|
||||
|
||||
testTexts();
|
||||
|
||||
// update the m_ui listboxes
|
||||
updatePointers();
|
||||
|
||||
|
@ -628,6 +639,137 @@ void DRC::testKeepoutAreas()
|
|||
}
|
||||
|
||||
|
||||
void DRC::testTexts()
|
||||
{
|
||||
std::vector<wxPoint> textShape; // a buffer to store the text shape (set of segments)
|
||||
std::vector<D_PAD*> padList = m_pcb->GetPads();
|
||||
|
||||
// Test text areas for vias, tracks and pads inside text areas
|
||||
for( BOARD_ITEM* item = m_pcb->m_Drawings; item; item = item->Next() )
|
||||
{
|
||||
// Drc test only items on copper layers
|
||||
if( ! IsCopperLayer( item->GetLayer() ) )
|
||||
continue;
|
||||
|
||||
// only texts on copper layers are tested
|
||||
if( item->Type() != PCB_TEXT_T )
|
||||
continue;
|
||||
|
||||
textShape.clear();
|
||||
|
||||
// So far the bounding box makes up the text-area
|
||||
TEXTE_PCB* text = (TEXTE_PCB*) item;
|
||||
text->TransformTextShapeToSegmentList( textShape );
|
||||
|
||||
if( textShape.size() == 0 ) // Should not happen (empty text?)
|
||||
continue;
|
||||
|
||||
for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() )
|
||||
{
|
||||
if( ! track->IsOnLayer( item->GetLayer() ) )
|
||||
continue;
|
||||
|
||||
// Test the distance between each segment and the current track/via
|
||||
int min_dist = ( track->GetWidth() + text->GetThickness() ) /2 +
|
||||
track->GetClearance(NULL);
|
||||
|
||||
if( track->Type() == PCB_TRACE_T )
|
||||
{
|
||||
SEG segref( track->GetStart(), track->GetEnd() );
|
||||
|
||||
// Error condition: Distance between text segment and track segment is
|
||||
// smaller than the clearance of the segment
|
||||
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
|
||||
{
|
||||
SEG segtest( textShape[jj], textShape[jj+1] );
|
||||
int dist = segref.Distance( segtest );
|
||||
|
||||
if( dist < min_dist )
|
||||
{
|
||||
m_currentMarker = fillMarker( track, text,
|
||||
DRCE_TRACK_INSIDE_TEXT,
|
||||
m_currentMarker );
|
||||
m_pcb->Add( m_currentMarker );
|
||||
m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker );
|
||||
m_currentMarker = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( track->Type() == PCB_VIA_T )
|
||||
{
|
||||
// Error condition: Distance between text segment and via is
|
||||
// smaller than the clearance of the via
|
||||
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
|
||||
{
|
||||
SEG segtest( textShape[jj], textShape[jj+1] );
|
||||
|
||||
if( segtest.PointCloserThan( track->GetPosition(), min_dist ) )
|
||||
{
|
||||
m_currentMarker = fillMarker( track, text,
|
||||
DRCE_VIA_INSIDE_TEXT, m_currentMarker );
|
||||
m_pcb->Add( m_currentMarker );
|
||||
m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker );
|
||||
m_currentMarker = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test pads
|
||||
for( unsigned ii = 0; ii < padList.size(); ii++ )
|
||||
{
|
||||
D_PAD* pad = padList[ii];
|
||||
|
||||
if( ! pad->IsOnLayer( item->GetLayer() ) )
|
||||
continue;
|
||||
|
||||
wxPoint shape_pos = pad->ShapePos();
|
||||
|
||||
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
|
||||
{
|
||||
SEG segtest( textShape[jj], textShape[jj+1] );
|
||||
/* In order to make some calculations more easier or faster,
|
||||
* pads and tracks coordinates will be made relative
|
||||
* to the segment origin
|
||||
*/
|
||||
wxPoint origin = textShape[jj]; // origin will be the origin of other coordinates
|
||||
m_segmEnd = textShape[jj+1] - origin;
|
||||
wxPoint delta = m_segmEnd;
|
||||
m_segmAngle = 0;
|
||||
|
||||
// for a non horizontal or vertical segment Compute the segment angle
|
||||
// in tenths of degrees and its length
|
||||
if( delta.x || delta.y ) // delta.x == delta.y == 0 for vias
|
||||
{
|
||||
// Compute the segment angle in 0,1 degrees
|
||||
m_segmAngle = ArcTangente( delta.y, delta.x );
|
||||
|
||||
// Compute the segment length: we build an equivalent rotated segment,
|
||||
// this segment is horizontal, therefore dx = length
|
||||
RotatePoint( &delta, m_segmAngle ); // delta.x = length, delta.y = 0
|
||||
}
|
||||
|
||||
m_segmLength = delta.x;
|
||||
m_padToTestPos = shape_pos - origin;
|
||||
|
||||
if( !checkClearanceSegmToPad( pad, text->GetThickness(),
|
||||
pad->GetClearance(NULL) ) )
|
||||
{
|
||||
m_currentMarker = fillMarker( pad, text,
|
||||
DRCE_PAD_INSIDE_TEXT, m_currentMarker );
|
||||
m_pcb->Add( m_currentMarker );
|
||||
m_mainWindow->GetGalCanvas()->GetView()->Add( m_currentMarker );
|
||||
m_currentMarker = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
|
||||
{
|
||||
// Test keepout areas for vias, tracks and pads inside keepout areas
|
||||
|
|
|
@ -41,7 +41,9 @@
|
|||
#include <class_pad.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_marker_pcb.h>
|
||||
#include <class_pcb_text.h>
|
||||
|
||||
|
||||
MARKER_PCB* DRC::fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode,
|
||||
|
@ -84,6 +86,11 @@ MARKER_PCB* DRC::fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorC
|
|||
if( dToEnd < dToStart )
|
||||
position = endPos;
|
||||
}
|
||||
else if( aItem->Type() == PCB_TEXT_T )
|
||||
{
|
||||
position = aTrack->GetPosition();
|
||||
posB = ((TEXTE_PCB*) aItem)->GetPosition();
|
||||
}
|
||||
}
|
||||
else
|
||||
position = aTrack->GetPosition();
|
||||
|
@ -118,13 +125,33 @@ MARKER_PCB* DRC::fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorC
|
|||
}
|
||||
|
||||
|
||||
MARKER_PCB* DRC::fillMarker( D_PAD* aPad, D_PAD* bPad, int aErrorCode, MARKER_PCB* fillMe )
|
||||
MARKER_PCB* DRC::fillMarker( D_PAD* aPad, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe )
|
||||
{
|
||||
wxString textA = aPad->GetSelectMenuText();
|
||||
wxString textB = bPad->GetSelectMenuText();
|
||||
wxString textB;
|
||||
|
||||
wxPoint posA = aPad->GetPosition();
|
||||
wxPoint posB = bPad->GetPosition();
|
||||
wxPoint posB;
|
||||
|
||||
if( aItem )
|
||||
{
|
||||
textB = aItem->GetSelectMenuText();
|
||||
|
||||
switch( aItem->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
posB = ((D_PAD*)aItem)->GetPosition();
|
||||
break;
|
||||
|
||||
case PCB_TEXT_T:
|
||||
posB = ((TEXTE_PCB*)aItem)->GetPosition();
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogDebug( wxT("fillMarker: unsupported item") );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( fillMe )
|
||||
{
|
||||
|
|
|
@ -75,6 +75,9 @@
|
|||
#define DRCE_VIA_INSIDE_KEEPOUT 36 ///< Via in inside a keepout area
|
||||
#define DRCE_TRACK_INSIDE_KEEPOUT 37 ///< Track in inside a keepout area
|
||||
#define DRCE_PAD_INSIDE_KEEPOUT 38 ///< Pad in inside a keepout area
|
||||
#define DRCE_VIA_INSIDE_TEXT 39 ///< Via in inside a text area
|
||||
#define DRCE_TRACK_INSIDE_TEXT 40 ///< Track in inside a text area
|
||||
#define DRCE_PAD_INSIDE_TEXT 41 ///< Pad in inside a text area
|
||||
|
||||
|
||||
class EDA_DRAW_PANEL;
|
||||
|
@ -221,7 +224,7 @@ private:
|
|||
*/
|
||||
MARKER_PCB* fillMarker( const TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe );
|
||||
|
||||
MARKER_PCB* fillMarker( D_PAD* aPad, D_PAD* bPad, int aErrorCode, MARKER_PCB* fillMe );
|
||||
MARKER_PCB* fillMarker( D_PAD* aPad, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe );
|
||||
|
||||
MARKER_PCB* fillMarker( ZONE_CONTAINER* aArea, int aErrorCode, MARKER_PCB* fillMe );
|
||||
|
||||
|
@ -281,6 +284,8 @@ private:
|
|||
|
||||
void testKeepoutAreas();
|
||||
|
||||
void testTexts();
|
||||
|
||||
//-----<single "item" tests>-----------------------------------------
|
||||
|
||||
bool doNetClass( boost::shared_ptr<NETCLASS> aNetClass, wxString& msg );
|
||||
|
|
|
@ -399,7 +399,7 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int w1,
|
|||
double dist;
|
||||
TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f,
|
||||
x2i, y2i, x2f, y2f, &xx, &yy, &dist );
|
||||
int d = KiROUND( dist - (w1 + w2) / 2 );
|
||||
int d = KiROUND( dist ) - ((w1 + w2) / 2);
|
||||
if( d < 0 )
|
||||
d = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue