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:
unknown 2014-08-13 17:47:02 +02:00 committed by jean-pierre charras
parent adbf343fef
commit c8d69f19c8
8 changed files with 258 additions and 14 deletions

View File

@ -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 );
}
}

View File

@ -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.

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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 )
{

View File

@ -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 );

View File

@ -197,7 +197,7 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y
if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
{
if( x )
*x = KiROUND( x1 );
*x = KiROUND( x1 );
if( y )
*y = KiROUND( y1 );
@ -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;